diff --git a/.gitignore b/.gitignore index 21586748b7..b981a473f6 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,7 @@ .idea/ *.iml *.iws +out/ # Mac .DS_Store @@ -27,6 +28,9 @@ log/ target/ +# Gradle +.gradle/ + spring-openid/src/main/resources/application.properties .recommenders/ /spring-hibernate4/nbproject/ diff --git a/akka-streams/pom.xml b/akka-streams/pom.xml index a885753ce2..7719bb7351 100644 --- a/akka-streams/pom.xml +++ b/akka-streams/pom.xml @@ -14,18 +14,19 @@ com.typesafe.akka - akka-stream_2.11 + akka-stream_${scala.version} ${akkastreams.version} com.typesafe.akka - akka-stream-testkit_2.11 + akka-stream-testkit_${scala.version} ${akkastreams.version} 2.5.2 + 2.11 \ No newline at end of file diff --git a/algorithms-miscellaneous-1/README.md b/algorithms-miscellaneous-1/README.md index 7ed805f7c4..479c2792f6 100644 --- a/algorithms-miscellaneous-1/README.md +++ b/algorithms-miscellaneous-1/README.md @@ -14,6 +14,5 @@ - [Calculate Factorial in Java](https://www.baeldung.com/java-calculate-factorial) - [Find Substrings That Are Palindromes in Java](https://www.baeldung.com/java-palindrome-substrings) - [Find the Longest Substring without Repeating Characters](https://www.baeldung.com/java-longest-substring-without-repeated-characters) -- [Java Two Pointer Technique](https://www.baeldung.com/java-two-pointer-technique) - [Permutations of an Array in Java](https://www.baeldung.com/java-array-permutations) -- [Implementing Simple State Machines with Java Enums](https://www.baeldung.com/java-enum-simple-state-machine) +- [Generate Combinations in Java](https://www.baeldung.com/java-combinations-algorithm) diff --git a/algorithms-miscellaneous-2/README.md b/algorithms-miscellaneous-2/README.md index d693a44f66..de054566ed 100644 --- a/algorithms-miscellaneous-2/README.md +++ b/algorithms-miscellaneous-2/README.md @@ -8,9 +8,6 @@ - [Create a Sudoku Solver in Java](http://www.baeldung.com/java-sudoku) - [Displaying Money Amounts in Words](http://www.baeldung.com/java-money-into-words) - [A Collaborative Filtering Recommendation System in Java](http://www.baeldung.com/java-collaborative-filtering-recommendations) -- [Converting Between Roman and Arabic Numerals in Java](http://www.baeldung.com/java-convert-roman-arabic) -- [Practical Java Examples of the Big O Notation](http://www.baeldung.com/java-algorithm-complexity) -- [An Introduction to the Theory of Big-O Notation](http://www.baeldung.com/big-o-notation) - [Check If Two Rectangles Overlap In Java](https://www.baeldung.com/java-check-if-two-rectangles-overlap) - [Calculate the Distance Between Two Points in Java](https://www.baeldung.com/java-distance-between-two-points) - [Find the Intersection of Two Lines in Java](https://www.baeldung.com/java-intersection-of-two-lines) diff --git a/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/relativelyprime/RelativelyPrime.java b/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/relativelyprime/RelativelyPrime.java new file mode 100644 index 0000000000..fbea87be30 --- /dev/null +++ b/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/relativelyprime/RelativelyPrime.java @@ -0,0 +1,45 @@ +package com.baeldung.algorithms.relativelyprime; + +import java.math.BigInteger; + +class RelativelyPrime { + + static boolean iterativeRelativelyPrime(int a, int b) { + return iterativeGCD(a, b) == 1; + } + + static boolean recursiveRelativelyPrime(int a, int b) { + return recursiveGCD(a, b) == 1; + } + + static boolean bigIntegerRelativelyPrime(int a, int b) { + return BigInteger.valueOf(a).gcd(BigInteger.valueOf(b)).equals(BigInteger.ONE); + } + + private static int iterativeGCD(int a, int b) { + int tmp; + while (b != 0) { + if (a < b) { + tmp = a; + a = b; + b = tmp; + } + tmp = b; + b = a % b; + a = tmp; + } + return a; + } + + private static int recursiveGCD(int a, int b) { + if (b == 0) { + return a; + } + if (a < b) { + return recursiveGCD(b, a); + } + return recursiveGCD(b, a % b); + } + + +} diff --git a/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/reversingtree/TreeNode.java b/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/reversingtree/TreeNode.java new file mode 100644 index 0000000000..a6ec2277e5 --- /dev/null +++ b/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/reversingtree/TreeNode.java @@ -0,0 +1,42 @@ +package com.baeldung.algorithms.reversingtree; + +public class TreeNode { + + private int value; + private TreeNode rightChild; + private TreeNode leftChild; + + public int getValue() { + return value; + } + + public void setValue(int value) { + this.value = value; + } + + public TreeNode getRightChild() { + return rightChild; + } + + public void setRightChild(TreeNode rightChild) { + this.rightChild = rightChild; + } + + public TreeNode getLeftChild() { + return leftChild; + } + + public void setLeftChild(TreeNode leftChild) { + this.leftChild = leftChild; + } + + public TreeNode(int value, TreeNode leftChild, TreeNode rightChild) { + this.value = value; + this.rightChild = rightChild; + this.leftChild = leftChild; + } + + public TreeNode(int value) { + this.value = value; + } +} diff --git a/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/reversingtree/TreeReverser.java b/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/reversingtree/TreeReverser.java new file mode 100644 index 0000000000..162119d390 --- /dev/null +++ b/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/reversingtree/TreeReverser.java @@ -0,0 +1,53 @@ +package com.baeldung.algorithms.reversingtree; + +import java.util.LinkedList; + +public class TreeReverser { + + public void reverseRecursive(TreeNode treeNode) { + if (treeNode == null) { + return; + } + + TreeNode temp = treeNode.getLeftChild(); + treeNode.setLeftChild(treeNode.getRightChild()); + treeNode.setRightChild(temp); + + reverseRecursive(treeNode.getLeftChild()); + reverseRecursive(treeNode.getRightChild()); + } + + public void reverseIterative(TreeNode treeNode) { + LinkedList queue = new LinkedList(); + + if (treeNode != null) { + queue.add(treeNode); + } + + while (!queue.isEmpty()) { + + TreeNode node = queue.poll(); + if (node.getLeftChild() != null) + queue.add(node.getLeftChild()); + if (node.getRightChild() != null) + queue.add(node.getRightChild()); + + TreeNode temp = node.getLeftChild(); + node.setLeftChild(node.getRightChild()); + node.setRightChild(temp); + } + } + + public String toString(TreeNode root) { + if (root == null) { + return ""; + } + + StringBuffer buffer = new StringBuffer(String.valueOf(root.getValue())).append(" "); + + buffer.append(toString(root.getLeftChild())); + buffer.append(toString(root.getRightChild())); + + return buffer.toString(); + } +} diff --git a/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/relativelyprime/RelativelyPrimeUnitTest.java b/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/relativelyprime/RelativelyPrimeUnitTest.java new file mode 100644 index 0000000000..84bb2620af --- /dev/null +++ b/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/relativelyprime/RelativelyPrimeUnitTest.java @@ -0,0 +1,51 @@ +package com.baeldung.algorithms.relativelyprime; + +import org.junit.Test; + +import static com.baeldung.algorithms.relativelyprime.RelativelyPrime.*; +import static org.assertj.core.api.Assertions.assertThat; + +public class RelativelyPrimeUnitTest { + + @Test + public void givenNonRelativelyPrimeNumbers_whenCheckingIteratively_shouldReturnFalse() { + + boolean result = iterativeRelativelyPrime(45, 35); + assertThat(result).isFalse(); + } + + @Test + public void givenRelativelyPrimeNumbers_whenCheckingIteratively_shouldReturnTrue() { + + boolean result = iterativeRelativelyPrime(500, 501); + assertThat(result).isTrue(); + } + + @Test + public void givenNonRelativelyPrimeNumbers_whenCheckingRecursively_shouldReturnFalse() { + + boolean result = recursiveRelativelyPrime(45, 35); + assertThat(result).isFalse(); + } + + @Test + public void givenRelativelyPrimeNumbers_whenCheckingRecursively_shouldReturnTrue() { + + boolean result = recursiveRelativelyPrime(500, 501); + assertThat(result).isTrue(); + } + + @Test + public void givenNonRelativelyPrimeNumbers_whenCheckingUsingBigIntegers_shouldReturnFalse() { + + boolean result = bigIntegerRelativelyPrime(45, 35); + assertThat(result).isFalse(); + } + + @Test + public void givenRelativelyPrimeNumbers_whenCheckingBigIntegers_shouldReturnTrue() { + + boolean result = bigIntegerRelativelyPrime(500, 501); + assertThat(result).isTrue(); + } +} diff --git a/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/reversingtree/TreeReverserUnitTest.java b/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/reversingtree/TreeReverserUnitTest.java new file mode 100644 index 0000000000..44fac57361 --- /dev/null +++ b/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/reversingtree/TreeReverserUnitTest.java @@ -0,0 +1,47 @@ +package com.baeldung.algorithms.reversingtree; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +public class TreeReverserUnitTest { + + @Test + public void givenTreeWhenReversingRecursivelyThenReversed() { + TreeReverser reverser = new TreeReverser(); + + TreeNode treeNode = createBinaryTree(); + + reverser.reverseRecursive(treeNode); + + assertEquals("4 7 9 6 2 3 1", reverser.toString(treeNode) + .trim()); + } + + @Test + public void givenTreeWhenReversingIterativelyThenReversed() { + TreeReverser reverser = new TreeReverser(); + + TreeNode treeNode = createBinaryTree(); + + reverser.reverseIterative(treeNode); + + assertEquals("4 7 9 6 2 3 1", reverser.toString(treeNode) + .trim()); + } + + private TreeNode createBinaryTree() { + + TreeNode leaf1 = new TreeNode(1); + TreeNode leaf2 = new TreeNode(3); + TreeNode leaf3 = new TreeNode(6); + TreeNode leaf4 = new TreeNode(9); + + TreeNode nodeRight = new TreeNode(7, leaf3, leaf4); + TreeNode nodeLeft = new TreeNode(2, leaf1, leaf2); + + TreeNode root = new TreeNode(4, nodeLeft, nodeRight); + + return root; + } +} diff --git a/algorithms-miscellaneous-3/.gitignore b/algorithms-miscellaneous-3/.gitignore new file mode 100644 index 0000000000..30b2b7442c --- /dev/null +++ b/algorithms-miscellaneous-3/.gitignore @@ -0,0 +1,4 @@ +/target/ +.settings/ +.classpath +.project \ No newline at end of file diff --git a/algorithms-miscellaneous-3/README.md b/algorithms-miscellaneous-3/README.md new file mode 100644 index 0000000000..f299492d9c --- /dev/null +++ b/algorithms-miscellaneous-3/README.md @@ -0,0 +1,7 @@ +## Relevant articles: + +- [Java Two Pointer Technique](https://www.baeldung.com/java-two-pointer-technique) +- [Implementing Simple State Machines with Java Enums](https://www.baeldung.com/java-enum-simple-state-machine) +- [Converting Between Roman and Arabic Numerals in Java](http://www.baeldung.com/java-convert-roman-arabic) +- [Practical Java Examples of the Big O Notation](http://www.baeldung.com/java-algorithm-complexity) +- [An Introduction to the Theory of Big-O Notation](http://www.baeldung.com/big-o-notation) \ No newline at end of file diff --git a/algorithms-miscellaneous-3/pom.xml b/algorithms-miscellaneous-3/pom.xml new file mode 100644 index 0000000000..c4017144c8 --- /dev/null +++ b/algorithms-miscellaneous-3/pom.xml @@ -0,0 +1,39 @@ + + 4.0.0 + algorithms-miscellaneous-3 + 0.0.1-SNAPSHOT + algorithms-miscellaneous-3 + + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + + + + + org.assertj + assertj-core + ${org.assertj.core.version} + test + + + + + + + + org.codehaus.mojo + exec-maven-plugin + ${exec-maven-plugin.version} + + + + + + + 3.9.0 + + + \ No newline at end of file diff --git a/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/enumstatemachine/LeaveRequestState.java b/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/enumstatemachine/LeaveRequestState.java similarity index 100% rename from algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/enumstatemachine/LeaveRequestState.java rename to algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/enumstatemachine/LeaveRequestState.java diff --git a/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/romannumerals/RomanArabicConverter.java b/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/romannumerals/RomanArabicConverter.java similarity index 100% rename from algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/romannumerals/RomanArabicConverter.java rename to algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/romannumerals/RomanArabicConverter.java diff --git a/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/romannumerals/RomanNumeral.java b/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/romannumerals/RomanNumeral.java similarity index 100% rename from algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/romannumerals/RomanNumeral.java rename to algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/romannumerals/RomanNumeral.java diff --git a/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/twopointertechnique/LinkedListFindMiddle.java b/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/twopointertechnique/LinkedListFindMiddle.java similarity index 100% rename from algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/twopointertechnique/LinkedListFindMiddle.java rename to algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/twopointertechnique/LinkedListFindMiddle.java diff --git a/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/twopointertechnique/MyNode.java b/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/twopointertechnique/MyNode.java similarity index 100% rename from algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/twopointertechnique/MyNode.java rename to algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/twopointertechnique/MyNode.java diff --git a/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/twopointertechnique/RotateArray.java b/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/twopointertechnique/RotateArray.java similarity index 100% rename from algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/twopointertechnique/RotateArray.java rename to algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/twopointertechnique/RotateArray.java diff --git a/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/twopointertechnique/TwoSum.java b/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/twopointertechnique/TwoSum.java similarity index 100% rename from algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/twopointertechnique/TwoSum.java rename to algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/twopointertechnique/TwoSum.java diff --git a/noexception/src/main/resources/logback.xml b/algorithms-miscellaneous-3/src/main/resources/logback.xml similarity index 100% rename from noexception/src/main/resources/logback.xml rename to algorithms-miscellaneous-3/src/main/resources/logback.xml diff --git a/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/analysis/AnalysisRunnerLiveTest.java b/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/analysis/AnalysisRunnerLiveTest.java similarity index 100% rename from algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/analysis/AnalysisRunnerLiveTest.java rename to algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/analysis/AnalysisRunnerLiveTest.java diff --git a/algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/enumstatemachine/LeaveRequestStateUnitTest.java b/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/enumstatemachine/LeaveRequestStateUnitTest.java similarity index 100% rename from algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/enumstatemachine/LeaveRequestStateUnitTest.java rename to algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/enumstatemachine/LeaveRequestStateUnitTest.java diff --git a/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/romannumerals/RomanArabicConverterUnitTest.java b/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/romannumerals/RomanArabicConverterUnitTest.java similarity index 100% rename from algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/romannumerals/RomanArabicConverterUnitTest.java rename to algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/romannumerals/RomanArabicConverterUnitTest.java diff --git a/algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/twopointertechnique/LinkedListFindMiddleUnitTest.java b/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/twopointertechnique/LinkedListFindMiddleUnitTest.java similarity index 100% rename from algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/twopointertechnique/LinkedListFindMiddleUnitTest.java rename to algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/twopointertechnique/LinkedListFindMiddleUnitTest.java diff --git a/algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/twopointertechnique/RotateArrayUnitTest.java b/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/twopointertechnique/RotateArrayUnitTest.java similarity index 100% rename from algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/twopointertechnique/RotateArrayUnitTest.java rename to algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/twopointertechnique/RotateArrayUnitTest.java diff --git a/algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/twopointertechnique/TwoSumUnitTest.java b/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/twopointertechnique/TwoSumUnitTest.java similarity index 100% rename from algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/twopointertechnique/TwoSumUnitTest.java rename to algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/twopointertechnique/TwoSumUnitTest.java diff --git a/antlr/pom.xml b/antlr/pom.xml index ac66891598..91b939a882 100644 --- a/antlr/pom.xml +++ b/antlr/pom.xml @@ -10,6 +10,14 @@ 1.0.0-SNAPSHOT + + + org.antlr + antlr4-runtime + ${antlr.version} + + + @@ -44,13 +52,7 @@ - - - org.antlr - antlr4-runtime - ${antlr.version} - - + 4.7.1 3.0.0 diff --git a/apache-cxf/sse-jaxrs/sse-jaxrs-client/pom.xml b/apache-cxf/sse-jaxrs/sse-jaxrs-client/pom.xml index c7acf22c32..be2138e172 100644 --- a/apache-cxf/sse-jaxrs/sse-jaxrs-client/pom.xml +++ b/apache-cxf/sse-jaxrs/sse-jaxrs-client/pom.xml @@ -12,9 +12,18 @@ 0.0.1-SNAPSHOT - - 3.2.0 - + + + org.apache.cxf + cxf-rt-rs-client + ${cxf-version} + + + org.apache.cxf + cxf-rt-rs-sse + ${cxf-version} + + @@ -45,17 +54,8 @@ - - - org.apache.cxf - cxf-rt-rs-client - ${cxf-version} - - - org.apache.cxf - cxf-rt-rs-sse - ${cxf-version} - - + + 3.2.0 + diff --git a/apache-cxf/sse-jaxrs/sse-jaxrs-server/pom.xml b/apache-cxf/sse-jaxrs/sse-jaxrs-server/pom.xml index eeb5726ee1..43bbcf1ef4 100644 --- a/apache-cxf/sse-jaxrs/sse-jaxrs-server/pom.xml +++ b/apache-cxf/sse-jaxrs/sse-jaxrs-server/pom.xml @@ -13,11 +13,28 @@ 0.0.1-SNAPSHOT - - 2.4.2 - false - 18.0.0.2 - + + + + javax.ws.rs + javax.ws.rs-api + 2.1 + provided + + + javax.enterprise + cdi-api + 2.0 + provided + + + javax.json.bind + javax.json.bind-api + 1.0 + provided + + + ${project.artifactId} @@ -59,27 +76,10 @@ - - - - javax.ws.rs - javax.ws.rs-api - 2.1 - provided - - - javax.enterprise - cdi-api - 2.0 - provided - - - javax.json.bind - javax.json.bind-api - 1.0 - provided - - - + + 2.4.2 + false + 18.0.0.2 + diff --git a/apache-fop/README.md b/apache-fop/README.md index 772681ad57..1e734a5f36 100644 --- a/apache-fop/README.md +++ b/apache-fop/README.md @@ -3,7 +3,3 @@ ## Core Java Cookbooks and Examples ### Relevant Articles: -- [Immutable ArrayList in Java](http://www.baeldung.com/java-immutable-list) -- [Java - Reading a Large File Efficiently](http://www.baeldung.com/java-read-lines-large-file) -- [Java InputStream to String](http://www.baeldung.com/convert-input-stream-to-string) - diff --git a/apache-meecrowave/pom.xml b/apache-meecrowave/pom.xml index fb5af69f9b..bb851577e2 100644 --- a/apache-meecrowave/pom.xml +++ b/apache-meecrowave/pom.xml @@ -6,6 +6,12 @@ 0.0.1 apache-meecrowave A sample REST API application with Meecrowave + + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + diff --git a/apache-meecrowave/src/test/java/com/baeldung/meecrowave/ArticleEndpointsTest.java b/apache-meecrowave/src/test/java/com/baeldung/meecrowave/ArticleEndpointsUnitTest.java similarity index 96% rename from apache-meecrowave/src/test/java/com/baeldung/meecrowave/ArticleEndpointsTest.java rename to apache-meecrowave/src/test/java/com/baeldung/meecrowave/ArticleEndpointsUnitTest.java index 0dc9773490..f9a06fd7b9 100644 --- a/apache-meecrowave/src/test/java/com/baeldung/meecrowave/ArticleEndpointsTest.java +++ b/apache-meecrowave/src/test/java/com/baeldung/meecrowave/ArticleEndpointsUnitTest.java @@ -17,7 +17,7 @@ import okhttp3.Request; import okhttp3.Response; @RunWith(MonoMeecrowave.Runner.class) -public class ArticleEndpointsTest { +public class ArticleEndpointsUnitTest { @ConfigurationInject private Meecrowave.Builder config; diff --git a/autovalue/src/main/java/com/baeldung/autofactory/provided/IntermediateAssembler.java b/autovalue/src/main/java/com/baeldung/autofactory/provided/IntermediateAssembler.java index e0ee8879a5..65d0eb6f58 100644 --- a/autovalue/src/main/java/com/baeldung/autofactory/provided/IntermediateAssembler.java +++ b/autovalue/src/main/java/com/baeldung/autofactory/provided/IntermediateAssembler.java @@ -1,8 +1,9 @@ package com.baeldung.autofactory.provided; +import com.baeldung.autofactory.model.Camera; import com.google.auto.factory.AutoFactory; import com.google.auto.factory.Provided; -import javafx.scene.Camera; + import javax.inject.Provider; diff --git a/azure/README.md b/azure/README.md index c60186e1ce..ae8c443660 100644 --- a/azure/README.md +++ b/azure/README.md @@ -1,4 +1,4 @@ ### Relevant Articles: -- [Deploy Spring Boot App to Azure](http://www.baeldung.com/spring-boot-azure) +- [Deploy a Spring Boot App to Azure](http://www.baeldung.com/spring-boot-azure) diff --git a/blade/README.md b/blade/README.md index d823de775f..1f2a00ed3f 100644 --- a/blade/README.md +++ b/blade/README.md @@ -1,5 +1,5 @@ ### Relevant Articles: -- [Blade - A Complete GuideBook](http://www.baeldung.com/blade) +- [Blade – A Complete Guidebook](http://www.baeldung.com/blade) -Run Integration Tests with `mvn integration-test` \ No newline at end of file +Run Integration Tests with `mvn integration-test` diff --git a/cloud-foundry-uaa/README.md b/cloud-foundry-uaa/README.md new file mode 100644 index 0000000000..b2f382cad1 --- /dev/null +++ b/cloud-foundry-uaa/README.md @@ -0,0 +1,3 @@ +### Revelant Articles + +- [A Quick Guide To Using Cloud Foundry UAA](https://www.baeldung.com/cloud-foundry-uaa) diff --git a/cloud-foundry-uaa/cf-uaa-config/uaa.yml b/cloud-foundry-uaa/cf-uaa-config/uaa.yml new file mode 100644 index 0000000000..ebaa99fb6c --- /dev/null +++ b/cloud-foundry-uaa/cf-uaa-config/uaa.yml @@ -0,0 +1,68 @@ +issuer: + uri: http://localhost:8080/uaa + +spring_profiles: default,hsqldb + +encryption: + active_key_label: CHANGE-THIS-KEY + encryption_keys: + - label: CHANGE-THIS-KEY + passphrase: CHANGEME + +login: + serviceProviderKey: | + -----BEGIN RSA PRIVATE KEY----- + MIICXQIBAAKBgQDHtC5gUXxBKpEqZTLkNvFwNGnNIkggNOwOQVNbpO0WVHIivig5 + L39WqS9u0hnA+O7MCA/KlrAR4bXaeVVhwfUPYBKIpaaTWFQR5cTR1UFZJL/OF9vA + fpOwznoD66DDCnQVpbCjtDYWX+x6imxn8HCYxhMol6ZnTbSsFW6VZjFMjQIDAQAB + AoGAVOj2Yvuigi6wJD99AO2fgF64sYCm/BKkX3dFEw0vxTPIh58kiRP554Xt5ges + 7ZCqL9QpqrChUikO4kJ+nB8Uq2AvaZHbpCEUmbip06IlgdA440o0r0CPo1mgNxGu + lhiWRN43Lruzfh9qKPhleg2dvyFGQxy5Gk6KW/t8IS4x4r0CQQD/dceBA+Ndj3Xp + ubHfxqNz4GTOxndc/AXAowPGpge2zpgIc7f50t8OHhG6XhsfJ0wyQEEvodDhZPYX + kKBnXNHzAkEAyCA76vAwuxqAd3MObhiebniAU3SnPf2u4fdL1EOm92dyFs1JxyyL + gu/DsjPjx6tRtn4YAalxCzmAMXFSb1qHfwJBAM3qx3z0gGKbUEWtPHcP7BNsrnWK + vw6By7VC8bk/ffpaP2yYspS66Le9fzbFwoDzMVVUO/dELVZyBnhqSRHoXQcCQQCe + A2WL8S5o7Vn19rC0GVgu3ZJlUrwiZEVLQdlrticFPXaFrn3Md82ICww3jmURaKHS + N+l4lnMda79eSp3OMmq9AkA0p79BvYsLshUJJnvbk76pCjR28PK4dV1gSDUEqQMB + qy45ptdwJLqLJCeNoR0JUcDNIRhOCuOPND7pcMtX6hI/ + -----END RSA PRIVATE KEY----- + serviceProviderKeyPassword: password + serviceProviderCertificate: | + -----BEGIN CERTIFICATE----- + MIIDSTCCArKgAwIBAgIBADANBgkqhkiG9w0BAQQFADB8MQswCQYDVQQGEwJhdzEO + MAwGA1UECBMFYXJ1YmExDjAMBgNVBAoTBWFydWJhMQ4wDAYDVQQHEwVhcnViYTEO + MAwGA1UECxMFYXJ1YmExDjAMBgNVBAMTBWFydWJhMR0wGwYJKoZIhvcNAQkBFg5h + cnViYUBhcnViYS5hcjAeFw0xNTExMjAyMjI2MjdaFw0xNjExMTkyMjI2MjdaMHwx + CzAJBgNVBAYTAmF3MQ4wDAYDVQQIEwVhcnViYTEOMAwGA1UEChMFYXJ1YmExDjAM + BgNVBAcTBWFydWJhMQ4wDAYDVQQLEwVhcnViYTEOMAwGA1UEAxMFYXJ1YmExHTAb + BgkqhkiG9w0BCQEWDmFydWJhQGFydWJhLmFyMIGfMA0GCSqGSIb3DQEBAQUAA4GN + ADCBiQKBgQDHtC5gUXxBKpEqZTLkNvFwNGnNIkggNOwOQVNbpO0WVHIivig5L39W + qS9u0hnA+O7MCA/KlrAR4bXaeVVhwfUPYBKIpaaTWFQR5cTR1UFZJL/OF9vAfpOw + znoD66DDCnQVpbCjtDYWX+x6imxn8HCYxhMol6ZnTbSsFW6VZjFMjQIDAQABo4Ha + MIHXMB0GA1UdDgQWBBTx0lDzjH/iOBnOSQaSEWQLx1syGDCBpwYDVR0jBIGfMIGc + gBTx0lDzjH/iOBnOSQaSEWQLx1syGKGBgKR+MHwxCzAJBgNVBAYTAmF3MQ4wDAYD + VQQIEwVhcnViYTEOMAwGA1UEChMFYXJ1YmExDjAMBgNVBAcTBWFydWJhMQ4wDAYD + VQQLEwVhcnViYTEOMAwGA1UEAxMFYXJ1YmExHTAbBgkqhkiG9w0BCQEWDmFydWJh + QGFydWJhLmFyggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAYvBJ + 0HOZbbHClXmGUjGs+GS+xC1FO/am2suCSYqNB9dyMXfOWiJ1+TLJk+o/YZt8vuxC + KdcZYgl4l/L6PxJ982SRhc83ZW2dkAZI4M0/Ud3oePe84k8jm3A7EvH5wi5hvCkK + RpuRBwn3Ei+jCRouxTbzKPsuCVB+1sNyxMTXzf0= + -----END CERTIFICATE----- + +#The secret that an external login server will use to authenticate to the uaa using the id `login` +LOGIN_SECRET: loginsecret + +jwt: + token: + signing-key: | + -----BEGIN RSA PRIVATE KEY----- + MIIEpAIBAAKCAQEAqUeygEfDGxI6c1VDQ6xIyUSLrP6iz1y97iHFbtXSxXaArL4a + ... + v6Mtt5LcRAAVP7pemunTdju4h8Q/noKYlVDVL30uLYUfKBL4UKfOBw== + -----END RSA PRIVATE KEY----- + verification-key: | + -----BEGIN PUBLIC KEY----- + MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqUeygEfDGxI6c1VDQ6xI + ... + AwIDAQAB + -----END PUBLIC KEY----- diff --git a/cloud-foundry-uaa/cf-uaa-oauth2-client/pom.xml b/cloud-foundry-uaa/cf-uaa-oauth2-client/pom.xml new file mode 100644 index 0000000000..f650498b69 --- /dev/null +++ b/cloud-foundry-uaa/cf-uaa-oauth2-client/pom.xml @@ -0,0 +1,41 @@ + + + 4.0.0 + com.example + cf-uaa-oauth2-client + 0.0.1-SNAPSHOT + uaa-client-webapp + Demo project for Spring Boot + + + 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-oauth2-client + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + 1.8 + + diff --git a/cloud-foundry-uaa/cf-uaa-oauth2-client/src/main/java/com/baeldung/cfuaa/oauth2/client/CFUAAOAuth2ClientApplication.java b/cloud-foundry-uaa/cf-uaa-oauth2-client/src/main/java/com/baeldung/cfuaa/oauth2/client/CFUAAOAuth2ClientApplication.java new file mode 100644 index 0000000000..c9e81fcd5d --- /dev/null +++ b/cloud-foundry-uaa/cf-uaa-oauth2-client/src/main/java/com/baeldung/cfuaa/oauth2/client/CFUAAOAuth2ClientApplication.java @@ -0,0 +1,13 @@ +package com.baeldung.cfuaa.oauth2.client; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class CFUAAOAuth2ClientApplication { + + public static void main(String[] args) { + SpringApplication.run(CFUAAOAuth2ClientApplication.class, args); + } + +} diff --git a/cloud-foundry-uaa/cf-uaa-oauth2-client/src/main/java/com/baeldung/cfuaa/oauth2/client/CFUAAOAuth2ClientController.java b/cloud-foundry-uaa/cf-uaa-oauth2-client/src/main/java/com/baeldung/cfuaa/oauth2/client/CFUAAOAuth2ClientController.java new file mode 100644 index 0000000000..b1631ed327 --- /dev/null +++ b/cloud-foundry-uaa/cf-uaa-oauth2-client/src/main/java/com/baeldung/cfuaa/oauth2/client/CFUAAOAuth2ClientController.java @@ -0,0 +1,80 @@ +package com.baeldung.cfuaa.oauth2.client; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService; +import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; +import org.springframework.security.oauth2.core.OAuth2AccessToken; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.RestTemplate; + +@RestController +public class CFUAAOAuth2ClientController { + + @Value("${resource.server.url}") + private String remoteResourceServer; + + private RestTemplate restTemplate; + + private OAuth2AuthorizedClientService authorizedClientService; + + public CFUAAOAuth2ClientController(OAuth2AuthorizedClientService authorizedClientService) { + this.authorizedClientService = authorizedClientService; + this.restTemplate = new RestTemplate(); + } + + @RequestMapping("/") + public String index(OAuth2AuthenticationToken authenticationToken) { + OAuth2AuthorizedClient oAuth2AuthorizedClient = this.authorizedClientService.loadAuthorizedClient(authenticationToken.getAuthorizedClientRegistrationId(), authenticationToken.getName()); + OAuth2AccessToken oAuth2AccessToken = oAuth2AuthorizedClient.getAccessToken(); + + String response = "Hello, " + authenticationToken.getPrincipal().getName(); + response += "

"; + response += "Here is your accees token :
" + oAuth2AccessToken.getTokenValue(); + response += "
"; + response += "
You can use it to call these Resource Server APIs:"; + response += "

"; + response += "Call Resource Server Read API"; + response += "
"; + response += "Call Resource Server Write API"; + return response; + } + + @RequestMapping("/read") + public String read(OAuth2AuthenticationToken authenticationToken) { + String url = remoteResourceServer + "/read"; + return callResourceServer(authenticationToken, url); + } + + @RequestMapping("/write") + public String write(OAuth2AuthenticationToken authenticationToken) { + String url = remoteResourceServer + "/write"; + return callResourceServer(authenticationToken, url); + } + + private String callResourceServer(OAuth2AuthenticationToken authenticationToken, String url) { + OAuth2AuthorizedClient oAuth2AuthorizedClient = this.authorizedClientService.loadAuthorizedClient(authenticationToken.getAuthorizedClientRegistrationId(), authenticationToken.getName()); + OAuth2AccessToken oAuth2AccessToken = oAuth2AuthorizedClient.getAccessToken(); + + HttpHeaders headers = new HttpHeaders(); + headers.add("Authorization", "Bearer " + oAuth2AccessToken.getTokenValue()); + + HttpEntity entity = new HttpEntity<>("parameters", headers); + ResponseEntity responseEntity = null; + + String response = null; + try { + responseEntity = restTemplate.exchange(url, HttpMethod.GET, entity, String.class); + response = responseEntity.getBody(); + } catch (HttpClientErrorException e) { + response = e.getMessage(); + } + return response; + } +} \ No newline at end of file diff --git a/cloud-foundry-uaa/cf-uaa-oauth2-client/src/main/resources/application.properties b/cloud-foundry-uaa/cf-uaa-oauth2-client/src/main/resources/application.properties new file mode 100644 index 0000000000..8e8797ce54 --- /dev/null +++ b/cloud-foundry-uaa/cf-uaa-oauth2-client/src/main/resources/application.properties @@ -0,0 +1,11 @@ +server.port=8081 + +resource.server.url=http://localhost:8082 + +spring.security.oauth2.client.registration.uaa.client-name=Web App Client +spring.security.oauth2.client.registration.uaa.client-id=webappclient +spring.security.oauth2.client.registration.uaa.client-secret=webappclientsecret +spring.security.oauth2.client.registration.uaa.scope=resource.read,resource.write,openid,profile + +spring.security.oauth2.client.provider.uaa.issuer-uri=http://localhost:8080/uaa/oauth/token + diff --git a/cloud-foundry-uaa/cf-uaa-oauth2-client/src/main/resources/templates/index.html b/cloud-foundry-uaa/cf-uaa-oauth2-client/src/main/resources/templates/index.html new file mode 100644 index 0000000000..eb6e267b94 --- /dev/null +++ b/cloud-foundry-uaa/cf-uaa-oauth2-client/src/main/resources/templates/index.html @@ -0,0 +1 @@ +tintin \ No newline at end of file diff --git a/cloud-foundry-uaa/cf-uaa-oauth2-resource-server/pom.xml b/cloud-foundry-uaa/cf-uaa-oauth2-resource-server/pom.xml new file mode 100644 index 0000000000..710cecbd4e --- /dev/null +++ b/cloud-foundry-uaa/cf-uaa-oauth2-resource-server/pom.xml @@ -0,0 +1,42 @@ + + + 4.0.0 + com.baeldung.cfuaa + cf-uaa-oauth2-resource-server + 0.0.1-SNAPSHOT + cf-uaa-oauth2-resource-server + Demo project for Spring Boot + + + parent-boot-2 + com.baeldung + 0.0.1-SNAPSHOT + ../../parent-boot-2 + + + + + org.springframework.boot + spring-boot-starter-oauth2-resource-server + + + org.springframework.boot + spring-boot-starter-web + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + 1.8 + + + diff --git a/cloud-foundry-uaa/cf-uaa-oauth2-resource-server/src/main/java/com/baeldung/cfuaa/oauth2/resourceserver/CFUAAOAuth2ResourceServerApplication.java b/cloud-foundry-uaa/cf-uaa-oauth2-resource-server/src/main/java/com/baeldung/cfuaa/oauth2/resourceserver/CFUAAOAuth2ResourceServerApplication.java new file mode 100644 index 0000000000..51ad6e938d --- /dev/null +++ b/cloud-foundry-uaa/cf-uaa-oauth2-resource-server/src/main/java/com/baeldung/cfuaa/oauth2/resourceserver/CFUAAOAuth2ResourceServerApplication.java @@ -0,0 +1,13 @@ +package com.baeldung.cfuaa.oauth2.resourceserver; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class CFUAAOAuth2ResourceServerApplication { + + public static void main(String[] args) { + SpringApplication.run(CFUAAOAuth2ResourceServerApplication.class, args); + } + +} diff --git a/cloud-foundry-uaa/cf-uaa-oauth2-resource-server/src/main/java/com/baeldung/cfuaa/oauth2/resourceserver/CFUAAOAuth2ResourceServerRestController.java b/cloud-foundry-uaa/cf-uaa-oauth2-resource-server/src/main/java/com/baeldung/cfuaa/oauth2/resourceserver/CFUAAOAuth2ResourceServerRestController.java new file mode 100644 index 0000000000..c08f17d8d8 --- /dev/null +++ b/cloud-foundry-uaa/cf-uaa-oauth2-resource-server/src/main/java/com/baeldung/cfuaa/oauth2/resourceserver/CFUAAOAuth2ResourceServerRestController.java @@ -0,0 +1,28 @@ +package com.baeldung.cfuaa.oauth2.resourceserver; + +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.security.oauth2.jwt.Jwt; +import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.security.Principal; + +@RestController +public class CFUAAOAuth2ResourceServerRestController { + + @GetMapping("/") + public String index(@AuthenticationPrincipal Jwt jwt) { + return String.format("Hello, %s!", jwt.getSubject()); + } + + @GetMapping("/read") + public String read(JwtAuthenticationToken jwtAuthenticationToken) { + return "Hello write: " + jwtAuthenticationToken.getTokenAttributes(); + } + + @GetMapping("/write") + public String write(Principal principal) { + return "Hello write: " + principal.getName(); + } +} diff --git a/cloud-foundry-uaa/cf-uaa-oauth2-resource-server/src/main/java/com/baeldung/cfuaa/oauth2/resourceserver/CFUAAOAuth2ResourceServerSecurityConfiguration.java b/cloud-foundry-uaa/cf-uaa-oauth2-resource-server/src/main/java/com/baeldung/cfuaa/oauth2/resourceserver/CFUAAOAuth2ResourceServerSecurityConfiguration.java new file mode 100644 index 0000000000..d04d51cda3 --- /dev/null +++ b/cloud-foundry-uaa/cf-uaa-oauth2-resource-server/src/main/java/com/baeldung/cfuaa/oauth2/resourceserver/CFUAAOAuth2ResourceServerSecurityConfiguration.java @@ -0,0 +1,21 @@ +package com.baeldung.cfuaa.oauth2.resourceserver; + +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; + +@EnableWebSecurity +public class CFUAAOAuth2ResourceServerSecurityConfiguration extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + .authorizeRequests() + .antMatchers("/read/**").hasAuthority("SCOPE_resource.read") + .antMatchers("/write/**").hasAuthority("SCOPE_resource.write") + .anyRequest().authenticated() + .and() + .oauth2ResourceServer() + .jwt(); + } +} \ No newline at end of file diff --git a/cloud-foundry-uaa/cf-uaa-oauth2-resource-server/src/main/resources/application.properties b/cloud-foundry-uaa/cf-uaa-oauth2-resource-server/src/main/resources/application.properties new file mode 100644 index 0000000000..a6e846a00f --- /dev/null +++ b/cloud-foundry-uaa/cf-uaa-oauth2-resource-server/src/main/resources/application.properties @@ -0,0 +1,3 @@ +server.port=8082 + +spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:8080/uaa/oauth/token diff --git a/core-groovy-2/README.md b/core-groovy-2/README.md new file mode 100644 index 0000000000..f60bdb3cbe --- /dev/null +++ b/core-groovy-2/README.md @@ -0,0 +1,7 @@ +# Groovy + +## Relevant articles: + +- [String Matching in Groovy](http://www.baeldung.com/) +- [Groovy def Keyword] + diff --git a/core-groovy-2/pom.xml b/core-groovy-2/pom.xml new file mode 100644 index 0000000000..77de9c8fc8 --- /dev/null +++ b/core-groovy-2/pom.xml @@ -0,0 +1,131 @@ + + + 4.0.0 + core-groovy-2 + 1.0-SNAPSHOT + core-groovy-2 + jar + + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + + + + + org.codehaus.groovy + groovy + ${groovy.version} + + + org.codehaus.groovy + groovy-all + ${groovy-all.version} + pom + + + org.codehaus.groovy + groovy-dateutil + ${groovy.version} + + + org.codehaus.groovy + groovy-sql + ${groovy-sql.version} + + + org.junit.platform + junit-platform-runner + ${junit.platform.version} + test + + + org.hsqldb + hsqldb + ${hsqldb.version} + test + + + org.spockframework + spock-core + ${spock-core.version} + test + + + + + + + org.codehaus.gmavenplus + gmavenplus-plugin + ${gmavenplus-plugin.version} + + + + addSources + addTestSources + compile + compileTests + + + + + + maven-failsafe-plugin + ${maven-failsafe-plugin.version} + + + org.junit.platform + junit-platform-surefire-provider + ${junit.platform.version} + + + + + junit5 + + integration-test + verify + + + + **/*Test5.java + + + + + + + maven-surefire-plugin + 2.20.1 + + false + + **/*Test.java + **/*Spec.java + + + + + + + + + central + http://jcenter.bintray.com + + + + + 1.0.0 + 2.5.6 + 2.5.6 + 2.5.6 + 2.4.0 + 1.1-groovy-2.4 + 1.6 + + + diff --git a/core-groovy-2/src/test/groovy/com/baeldung/defkeyword/DefUnitTest.groovy b/core-groovy-2/src/test/groovy/com/baeldung/defkeyword/DefUnitTest.groovy new file mode 100644 index 0000000000..310d97d3fd --- /dev/null +++ b/core-groovy-2/src/test/groovy/com/baeldung/defkeyword/DefUnitTest.groovy @@ -0,0 +1,79 @@ +package com.baeldung.defkeyword + +import org.codehaus.groovy.runtime.NullObject +import org.codehaus.groovy.runtime.typehandling.GroovyCastException + +import groovy.transform.TypeChecked +import groovy.transform.TypeCheckingMode + +@TypeChecked +class DefUnitTest extends GroovyTestCase { + + def id + def firstName = "Samwell" + def listOfCountries = ['USA', 'UK', 'FRANCE', 'INDIA'] + + @TypeChecked(TypeCheckingMode.SKIP) + def multiply(x, y) { + return x*y + } + + @TypeChecked(TypeCheckingMode.SKIP) + void testDefVariableDeclaration() { + + def list + assert list.getClass() == org.codehaus.groovy.runtime.NullObject + assert list.is(null) + + list = [1,2,4] + assert list instanceof ArrayList + } + + @TypeChecked(TypeCheckingMode.SKIP) + void testTypeVariables() { + int rate = 200 + try { + rate = [12] //GroovyCastException + rate = "nill" //GroovyCastException + } catch(GroovyCastException) { + println "Cannot assign anything other than integer" + } + } + + @TypeChecked(TypeCheckingMode.SKIP) + void testDefVariableMultipleAssignment() { + def rate + assert rate == null + assert rate.getClass() == org.codehaus.groovy.runtime.NullObject + + rate = 12 + assert rate instanceof Integer + + rate = "Not Available" + assert rate instanceof String + + rate = [1, 4] + assert rate instanceof List + + assert divide(12, 3) instanceof BigDecimal + assert divide(1, 0) instanceof String + + } + + def divide(int x, int y) { + if(y==0) { + return "Should not divide by 0" + } else { + return x/y + } + } + + def greetMsg() { + println "Hello! I am Groovy" + } + + void testDefVsType() { + def int count + assert count instanceof Integer + } +} \ No newline at end of file diff --git a/core-groovy-2/src/test/groovy/com/baeldung/strings/StringMatchingSpec.groovy b/core-groovy-2/src/test/groovy/com/baeldung/strings/StringMatchingSpec.groovy new file mode 100644 index 0000000000..3865bc73fa --- /dev/null +++ b/core-groovy-2/src/test/groovy/com/baeldung/strings/StringMatchingSpec.groovy @@ -0,0 +1,44 @@ +package com.baeldung.strings + +import spock.lang.Specification + +import java.util.regex.Pattern + +class StringMatchingSpec extends Specification { + + def "pattern operator example"() { + given: "a pattern" + def p = ~'foo' + + expect: + p instanceof Pattern + + and: "you can use slash strings to avoid escaping of blackslash" + def digitPattern = ~/\d*/ + digitPattern.matcher('4711').matches() + } + + def "match operator example"() { + expect: + 'foobar' ==~ /.*oba.*/ + + and: "matching is strict" + !('foobar' ==~ /foo/) + } + + def "find operator example"() { + when: "using the find operator" + def matcher = 'foo and bar, baz and buz' =~ /(\w+) and (\w+)/ + + then: "will find groups" + matcher.size() == 2 + + and: "can access groups using array" + matcher[0][0] == 'foo and bar' + matcher[1][2] == 'buz' + + and: "you can use it as a predicate" + 'foobarbaz' =~ /bar/ + } + +} diff --git a/core-groovy-collections/README.md b/core-groovy-collections/README.md new file mode 100644 index 0000000000..482e33bce1 --- /dev/null +++ b/core-groovy-collections/README.md @@ -0,0 +1,6 @@ +# Groovy + +## Relevant articles: + +- [Maps in Groovy](http://www.baeldung.com/) + diff --git a/core-groovy-collections/pom.xml b/core-groovy-collections/pom.xml new file mode 100644 index 0000000000..bf3ae26592 --- /dev/null +++ b/core-groovy-collections/pom.xml @@ -0,0 +1,131 @@ + + + 4.0.0 + core-groovy-collections + 1.0-SNAPSHOT + core-groovy-collections + jar + + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + + + + + org.codehaus.groovy + groovy + ${groovy.version} + + + org.codehaus.groovy + groovy-all + ${groovy-all.version} + pom + + + org.codehaus.groovy + groovy-dateutil + ${groovy.version} + + + org.codehaus.groovy + groovy-sql + ${groovy-sql.version} + + + org.junit.platform + junit-platform-runner + ${junit.platform.version} + test + + + org.hsqldb + hsqldb + ${hsqldb.version} + test + + + org.spockframework + spock-core + ${spock-core.version} + test + + + + + + + org.codehaus.gmavenplus + gmavenplus-plugin + ${gmavenplus-plugin.version} + + + + addSources + addTestSources + compile + compileTests + + + + + + maven-failsafe-plugin + ${maven-failsafe-plugin.version} + + + org.junit.platform + junit-platform-surefire-provider + ${junit.platform.version} + + + + + junit5 + + integration-test + verify + + + + **/*Test5.java + + + + + + + maven-surefire-plugin + 2.20.1 + + false + + **/*Test.java + **/*Spec.java + + + + + + + + + central + http://jcenter.bintray.com + + + + + 1.0.0 + 2.5.6 + 2.5.6 + 2.5.6 + 2.4.0 + 1.1-groovy-2.4 + 1.6 + + + diff --git a/core-groovy-collections/src/test/groovy/com/baeldung/map/MapTest.groovy b/core-groovy-collections/src/test/groovy/com/baeldung/map/MapTest.groovy new file mode 100644 index 0000000000..c6105eb1c4 --- /dev/null +++ b/core-groovy-collections/src/test/groovy/com/baeldung/map/MapTest.groovy @@ -0,0 +1,148 @@ +package com.baeldung.map; + +import static groovy.test.GroovyAssert.* +import org.junit.Test + +class MapTest{ + + @Test + void createMap() { + + def emptyMap = [:] + assertNotNull(emptyMap) + + assertTrue(emptyMap instanceof java.util.LinkedHashMap) + + def map = [name:"Jerry", age: 42, city: "New York"] + assertTrue(map.size() == 3) + } + + @Test + void addItemsToMap() { + + def map = [name:"Jerry"] + + map["age"] = 42 + + map.city = "New York" + + def hobbyLiteral = "hobby" + def hobbyMap = [(hobbyLiteral): "Singing"] + map.putAll(hobbyMap) + + assertTrue(map == [name:"Jerry", age: 42, city: "New York", hobby:"Singing"]) + assertTrue(hobbyMap.hobby == "Singing") + assertTrue(hobbyMap[hobbyLiteral] == "Singing") + + map.plus([1:20]) // returns new map + + map << [2:30] + + } + + @Test + void getItemsFromMap() { + + def map = [name:"Jerry", age: 42, city: "New York", hobby:"Singing"] + + assertTrue(map["name"] == "Jerry") + + assertTrue(map.name == "Jerry") + + def propertyAge = "age" + assertTrue(map[propertyAge] == 42) + } + + @Test + void removeItemsFromMap() { + + def map = [1:20, a:30, 2:42, 4:34, ba:67, 6:39, 7:49] + + def minusMap = map.minus([2:42, 4:34]); + assertTrue(minusMap == [1:20, a:30, ba:67, 6:39, 7:49]) + + minusMap.removeAll{it -> it.key instanceof String} + assertTrue( minusMap == [ 1:20, 6:39, 7:49]) + + minusMap.retainAll{it -> it.value %2 == 0} + assertTrue( minusMap == [1:20]) + } + + @Test + void iteratingOnMaps(){ + def map = [name:"Jerry", age: 42, city: "New York", hobby:"Singing"] + + map.each{ entry -> println "$entry.key: $entry.value" } + + map.eachWithIndex{ entry, i -> println "$i $entry.key: $entry.value" } + + map.eachWithIndex{ key, value, i -> println "$i $key: $value" } + } + + @Test + void filteringAndSearchingMaps(){ + def map = [name:"Jerry", age: 42, city: "New York", hobby:"Singing"] + + assertTrue(map.find{ it.value == "New York"}.key == "city") + + assertTrue(map.findAll{ it.value == "New York"} == [city : "New York"]) + + map.grep{it.value == "New York"}.each{ it -> assertTrue(it.key == "city" && it.value == "New York")} + + assertTrue(map.every{it -> it.value instanceof String} == false) + + assertTrue(map.any{it -> it.value instanceof String} == true) + } + + @Test + void collect(){ + + def map = [1: [name:"Jerry", age: 42, city: "New York"], + 2: [name:"Long", age: 25, city: "New York"], + 3: [name:"Dustin", age: 29, city: "New York"], + 4: [name:"Dustin", age: 34, city: "New York"]] + + def names = map.collect{entry -> entry.value.name} // returns only list + assertTrue(names == ["Jerry", "Long", "Dustin", "Dustin"]) + + def uniqueNames = map.collect([] as HashSet){entry -> entry.value.name} + assertTrue(uniqueNames == ["Jerry", "Long", "Dustin"] as Set) + + def idNames = map.collectEntries{key, value -> [key, value.name]} + assertTrue(idNames == [1:"Jerry", 2: "Long", 3:"Dustin", 4: "Dustin"]) + + def below30Names = map.findAll{it.value.age < 30}.collect{key, value -> value.name} + assertTrue(below30Names == ["Long", "Dustin"]) + + + } + + @Test + void group(){ + def map = [1:20, 2: 40, 3: 11, 4: 93] + + def subMap = map.groupBy{it.value % 2} + println subMap + assertTrue(subMap == [0:[1:20, 2:40 ], 1:[3:11, 4:93]]) + + def keySubMap = map.subMap([1, 2]) + assertTrue(keySubMap == [1:20, 2:40]) + + } + + @Test + void sorting(){ + def map = [ab:20, a: 40, cb: 11, ba: 93] + + def naturallyOrderedMap = map.sort() + assertTrue([a:40, ab:20, ba:93, cb:11] == naturallyOrderedMap) + + def compSortedMap = map.sort({ k1, k2 -> k1 <=> k2 } as Comparator) + assertTrue([a:40, ab:20, ba:93, cb:11] == compSortedMap) + + def cloSortedMap = map.sort({ it1, it2 -> it1.value <=> it1.value }) + assertTrue([cb:11, ab:20, a:40, ba:93] == cloSortedMap) + + } + +} diff --git a/core-groovy/README.md b/core-groovy/README.md index ec2fcfa574..321c37be8d 100644 --- a/core-groovy/README.md +++ b/core-groovy/README.md @@ -8,3 +8,8 @@ - [Types of Strings in Groovy](https://www.baeldung.com/groovy-strings) - [A Quick Guide to Iterating a Map in Groovy](https://www.baeldung.com/groovy-map-iterating) - [An Introduction to Traits in Groovy](https://www.baeldung.com/groovy-traits) +- [Closures in Groovy](https://www.baeldung.com/groovy-closures) +- [Finding Elements in Collections in Groovy](https://www.baeldung.com/groovy-collections-find-elements) +- [Lists in Groovy](https://www.baeldung.com/groovy-lists) +- [Converting a String to a Date in Groovy](https://www.baeldung.com/groovy-string-to-date) +- [Guide to I/O in Groovy](https://www.baeldung.com/groovy-io) \ No newline at end of file diff --git a/core-groovy/src/main/groovy/com/baeldung/Person.groovy b/core-groovy/src/main/groovy/com/baeldung/Person.groovy new file mode 100644 index 0000000000..6a009aeee0 --- /dev/null +++ b/core-groovy/src/main/groovy/com/baeldung/Person.groovy @@ -0,0 +1,37 @@ +package com.baeldung + +class Person { + private String firstname + private String lastname + private Integer age + + Person(String firstname, String lastname, Integer age) { + this.firstname = firstname + this.lastname = lastname + this.age = age + } + + String getFirstname() { + return firstname + } + + void setFirstname(String firstname) { + this.firstname = firstname + } + + String getLastname() { + return lastname + } + + void setLastname(String lastname) { + this.lastname = lastname + } + + Integer getAge() { + return age + } + + void setAge(Integer age) { + this.age = age + } +} diff --git a/core-groovy/src/main/groovy/com/baeldung/closures/Closures.groovy b/core-groovy/src/main/groovy/com/baeldung/closures/Closures.groovy new file mode 100644 index 0000000000..607329ce88 --- /dev/null +++ b/core-groovy/src/main/groovy/com/baeldung/closures/Closures.groovy @@ -0,0 +1,87 @@ +package com.baeldung.closures + +class Closures { + + def printWelcome = { + println "Welcome to Closures!" + } + + def print = { name -> + println name + } + + def formatToLowerCase(name) { + return name.toLowerCase() + } + def formatToLowerCaseClosure = { name -> + return name.toLowerCase() + } + + def count=0 + + def increaseCount = { + count++ + } + + def greet = { + return "Hello! ${it}" + } + + def multiply = { x, y -> + return x*y + } + + def calculate = {int x, int y, String operation -> + + //log closure + def log = { + println "Performing $it" + } + + def result = 0 + switch(operation) { + case "ADD": + log("Addition") + result = x+y + break + case "SUB": + log("Subtraction") + result = x-y + break + case "MUL": + log("Multiplication") + result = x*y + break + case "DIV": + log("Division") + result = x/y + break + } + return result + } + + def addAll = { int... args -> + return args.sum() + } + + def volume(Closure areaCalculator, int... dimensions) { + if(dimensions.size() == 3) { + + //consider dimension[0] = length, dimension[1] = breadth, dimension[2] = height + //for cube and cuboid + return areaCalculator(dimensions[0], dimensions[1]) * dimensions[2] + } else if(dimensions.size() == 2) { + + //consider dimension[0] = radius, dimension[1] = height + //for cylinder and cone + return areaCalculator(dimensions[0]) * dimensions[1] + } else if(dimensions.size() == 1) { + + //consider dimension[0] = radius + //for sphere + return areaCalculator(dimensions[0]) * dimensions[0] + } + + } + +} \ No newline at end of file diff --git a/core-groovy/src/main/groovy/com/baeldung/closures/Employee.groovy b/core-groovy/src/main/groovy/com/baeldung/closures/Employee.groovy new file mode 100644 index 0000000000..78eb5aadeb --- /dev/null +++ b/core-groovy/src/main/groovy/com/baeldung/closures/Employee.groovy @@ -0,0 +1,6 @@ +package com.baeldung.closures + +class Employee { + + String fullName +} \ No newline at end of file diff --git a/core-groovy/src/test/groovy/com/baeldung/closures/ClosuresUnitTest.groovy b/core-groovy/src/test/groovy/com/baeldung/closures/ClosuresUnitTest.groovy new file mode 100644 index 0000000000..32c67e99bc --- /dev/null +++ b/core-groovy/src/test/groovy/com/baeldung/closures/ClosuresUnitTest.groovy @@ -0,0 +1,80 @@ +package com.baeldung.closures + +import spock.lang.Specification + +class ClosuresUnitTest extends GroovyTestCase { + + Closures closures = new Closures() + + void testDeclaration() { + + closures.print("Hello! Closure") + closures.formatToLowerCaseClosure("Hello! Closure") + + closures.print.call("Hello! Closure") + closures.formatToLowerCaseClosure.call("Hello! Closure") + + } + + void testClosureVsMethods() { + assert closures.formatToLowerCase("TONY STARK") == closures.formatToLowerCaseClosure("Tony STark") + } + + void testParameters() { + //implicit parameter + assert closures.greet("Alex") == "Hello! Alex" + + //multiple parameters + assert closures.multiply(2, 4) == 8 + + assert closures.calculate(12, 4, "ADD") == 16 + assert closures.calculate(12, 4, "SUB") == 8 + assert closures.calculate(43, 8, "DIV") == 5.375 + + //varags + assert closures.addAll(12, 10, 14) == 36 + + } + + void testClosureAsAnArgument() { + assert closures.volume({ l, b -> return l*b }, 12, 6, 10) == 720 + + assert closures.volume({ radius -> return Math.PI*radius*radius/3 }, 5, 10) == Math.PI * 250/3 + } + + void testGStringsLazyEvaluation() { + def name = "Samwell" + def welcomeMsg = "Welcome! $name" + + assert welcomeMsg == "Welcome! Samwell" + + // changing the name does not affect original interpolated value + name = "Tarly" + assert welcomeMsg != "Welcome! Tarly" + + def fullName = "Tarly Samson" + def greetStr = "Hello! ${-> fullName}" + + assert greetStr == "Hello! Tarly Samson" + + // this time changing the variable affects the interpolated String's value + fullName = "Jon Smith" + assert greetStr == "Hello! Jon Smith" + } + + void testClosureInLists() { + def list = [10, 11, 12, 13, 14, true, false, "BUNTHER"] + list.each { + println it + } + + assert [13, 14] == list.findAll{ it instanceof Integer && it >= 13} + } + + void testClosureInMaps() { + def map = [1:10, 2:30, 4:5] + + assert [10, 60, 20] == map.collect{it.key * it.value} + } + +} \ No newline at end of file diff --git a/core-groovy/src/test/groovy/com/baeldung/lists/ListTest.groovy b/core-groovy/src/test/groovy/com/baeldung/lists/ListTest.groovy index f682503ed4..7771028132 100644 --- a/core-groovy/src/test/groovy/com/baeldung/lists/ListTest.groovy +++ b/core-groovy/src/test/groovy/com/baeldung/lists/ListTest.groovy @@ -129,13 +129,13 @@ class ListTest{ assertTrue(filterList.findAll{it > 3} == [4, 5, 6, 76]) assertTrue(filterList.findAll{ it instanceof Number} == [2, 1, 3, 4, 5, 6, 76]) - + assertTrue(filterList.grep( Number )== [2, 1, 3, 4, 5, 6, 76]) - + assertTrue(filterList.grep{ it> 6 }== [76]) def conditionList = [2, 1, 3, 4, 5, 6, 76] - + assertFalse(conditionList.every{ it < 6}) assertTrue(conditionList.any{ it%2 == 0}) @@ -165,7 +165,7 @@ class ListTest{ def strList = ["na", "ppp", "as"] assertTrue(strList.max() == "ppp") - + Comparator minc = {a,b -> a == b? 0: a < b? -1 : 1} def numberList = [3, 2, 0, 7] assertTrue(numberList.min(minc) == 0) diff --git a/core-groovy/src/test/groovy/com/baeldung/lists/ListUnitTest.groovy b/core-groovy/src/test/groovy/com/baeldung/lists/ListUnitTest.groovy new file mode 100644 index 0000000000..9617c099ce --- /dev/null +++ b/core-groovy/src/test/groovy/com/baeldung/lists/ListUnitTest.groovy @@ -0,0 +1,58 @@ +package com.baeldung.lists + +import com.baeldung.Person +import org.junit.Test + +import static org.junit.Assert.* + +class ListUnitTest { + + private final personList = [ + new Person("Regina", "Fitzpatrick", 25), + new Person("Abagail", "Ballard", 26), + new Person("Lucian", "Walter", 30), + ] + + @Test + void whenListContainsElement_thenCheckReturnsTrue() { + def list = ['a', 'b', 'c'] + + assertTrue(list.indexOf('a') > -1) + assertTrue(list.contains('a')) + } + + @Test + void whenListContainsElement_thenCheckWithMembershipOperatorReturnsTrue() { + def list = ['a', 'b', 'c'] + + assertTrue('a' in list) + } + + @Test + void givenListOfPerson_whenUsingStreamMatching_thenShouldEvaluateList() { + assertTrue(personList.stream().anyMatch {it.age > 20}) + assertFalse(personList.stream().allMatch {it.age < 30}) + } + + @Test + void givenListOfPerson_whenUsingCollectionMatching_thenShouldEvaluateList() { + assertTrue(personList.any {it.age > 20}) + assertFalse(personList.every {it.age < 30}) + } + + @Test + void givenListOfPerson_whenUsingStreamFind_thenShouldReturnMatchingElements() { + assertTrue(personList.stream().filter {it.age > 20}.findAny().isPresent()) + assertFalse(personList.stream().filter {it.age > 30}.findAny().isPresent()) + assertTrue(personList.stream().filter {it.age > 20}.findAll().size() == 3) + assertTrue(personList.stream().filter {it.age > 30}.findAll().isEmpty()) + } + + @Test + void givenListOfPerson_whenUsingCollectionFind_thenShouldReturnMatchingElements() { + assertNotNull(personList.find {it.age > 20}) + assertNull(personList.find {it.age > 30}) + assertTrue(personList.findAll {it.age > 20}.size() == 3) + assertTrue(personList.findAll {it.age > 30}.isEmpty()) + } +} diff --git a/core-groovy/src/test/groovy/com/baeldung/map/MapTest.groovy b/core-groovy/src/test/groovy/com/baeldung/map/MapTest.groovy new file mode 100644 index 0000000000..f1d528207f --- /dev/null +++ b/core-groovy/src/test/groovy/com/baeldung/map/MapTest.groovy @@ -0,0 +1,148 @@ +package com.baeldung.groovy.map; + +import static groovy.test.GroovyAssert.* +import org.junit.Test + +class MapTest{ + + @Test + void createMap() { + + def emptyMap = [:] + assertNotNull(emptyMap) + + assertTrue(emptyMap instanceof java.util.LinkedHashMap) + + def map = [name:"Jerry", age: 42, city: "New York"] + assertTrue(map.size() == 3) + } + + @Test + void addItemsToMap() { + + def map = [name:"Jerry"] + + map["age"] = 42 + + map.city = "New York" + + def hobbyLiteral = "hobby" + def hobbyMap = [(hobbyLiteral): "Singing"] + map.putAll(hobbyMap) + + assertTrue(map == [name:"Jerry", age: 42, city: "New York", hobby:"Singing"]) + assertTrue(hobbyMap.hobby == "Singing") + assertTrue(hobbyMap[hobbyLiteral] == "Singing") + + map.plus([1:20]) // returns new map + + map << [2:30] + + } + + @Test + void getItemsFromMap() { + + def map = [name:"Jerry", age: 42, city: "New York", hobby:"Singing"] + + assertTrue(map["name"] == "Jerry") + + assertTrue(map.name == "Jerry") + + def propertyAge = "age" + assertTrue(map[propertyAge] == 42) + } + + @Test + void removeItemsFromMap() { + + def map = [1:20, a:30, 2:42, 4:34, ba:67, 6:39, 7:49] + + def minusMap = map.minus([2:42, 4:34]); + assertTrue(minusMap == [1:20, a:30, ba:67, 6:39, 7:49]) + + minusMap.removeAll{it -> it.key instanceof String} + assertTrue( minusMap == [ 1:20, 6:39, 7:49]) + + minusMap.retainAll{it -> it.value %2 == 0} + assertTrue( minusMap == [1:20]) + } + + @Test + void iteratingOnMaps(){ + def map = [name:"Jerry", age: 42, city: "New York", hobby:"Singing"] + + map.each{ entry -> println "$entry.key: $entry.value" } + + map.eachWithIndex{ entry, i -> println "$i $entry.key: $entry.value" } + + map.eachWithIndex{ key, value, i -> println "$i $key: $value" } + } + + @Test + void filteringAndSearchingMaps(){ + def map = [name:"Jerry", age: 42, city: "New York", hobby:"Singing"] + + assertTrue(map.find{ it.value == "New York"}.key == "city") + + assertTrue(map.findAll{ it.value == "New York"} == [city : "New York"]) + + map.grep{it.value == "New York"}.each{ it -> assertTrue(it.key == "city" && it.value == "New York")} + + assertTrue(map.every{it -> it.value instanceof String} == false) + + assertTrue(map.any{it -> it.value instanceof String} == true) + } + + @Test + void collect(){ + + def map = [1: [name:"Jerry", age: 42, city: "New York"], + 2: [name:"Long", age: 25, city: "New York"], + 3: [name:"Dustin", age: 29, city: "New York"], + 4: [name:"Dustin", age: 34, city: "New York"]] + + def names = map.collect{entry -> entry.value.name} // returns only list + assertTrue(names == ["Jerry", "Long", "Dustin", "Dustin"]) + + def uniqueNames = map.collect([] as HashSet){entry -> entry.value.name} + assertTrue(uniqueNames == ["Jerry", "Long", "Dustin"] as Set) + + def idNames = map.collectEntries{key, value -> [key, value.name]} + assertTrue(idNames == [1:"Jerry", 2: "Long", 3:"Dustin", 4: "Dustin"]) + + def below30Names = map.findAll{it.value.age < 30}.collect{key, value -> value.name} + assertTrue(below30Names == ["Long", "Dustin"]) + + + } + + @Test + void group(){ + def map = [1:20, 2: 40, 3: 11, 4: 93] + + def subMap = map.groupBy{it.value % 2} + println subMap + assertTrue(subMap == [0:[1:20, 2:40 ], 1:[3:11, 4:93]]) + + def keySubMap = map.subMap([1, 2]) + assertTrue(keySubMap == [1:20, 2:40]) + + } + + @Test + void sorting(){ + def map = [ab:20, a: 40, cb: 11, ba: 93] + + def naturallyOrderedMap = map.sort() + assertTrue([a:40, ab:20, ba:93, cb:11] == naturallyOrderedMap) + + def compSortedMap = map.sort({ k1, k2 -> k1 <=> k2 } as Comparator) + assertTrue([a:40, ab:20, ba:93, cb:11] == compSortedMap) + + def cloSortedMap = map.sort({ it1, it2 -> it1.value <=> it1.value }) + assertTrue([cb:11, ab:20, a:40, ba:93] == cloSortedMap) + + } + +} diff --git a/core-groovy/src/test/groovy/com/baeldung/map/MapUnitTest.groovy b/core-groovy/src/test/groovy/com/baeldung/map/MapUnitTest.groovy index 97ffc50c76..0d6bbed04b 100644 --- a/core-groovy/src/test/groovy/com/baeldung/map/MapUnitTest.groovy +++ b/core-groovy/src/test/groovy/com/baeldung/map/MapUnitTest.groovy @@ -1,10 +1,18 @@ package com.baeldung.map -import static org.junit.Assert.* +import com.baeldung.Person import org.junit.Test +import static org.junit.Assert.* + class MapUnitTest { + private final personMap = [ + Regina : new Person("Regina", "Fitzpatrick", 25), + Abagail: new Person("Abagail", "Ballard", 26), + Lucian : new Person("Lucian", "Walter", 30) + ] + @Test void whenUsingEach_thenMapIsIterated() { def map = [ @@ -63,7 +71,7 @@ class MapUnitTest { 'FF6347' : 'Tomato', 'FF4500' : 'Orange Red' ] - + map.eachWithIndex { key, val, index -> def indent = ((index == 0 || index % 2 == 0) ? " " : "") println "$indent Hex Code: $key = Color Name: $val" @@ -82,4 +90,65 @@ class MapUnitTest { println "Hex Code: $entry.key = Color Name: $entry.value" } } + + @Test + void whenMapContainsKeyElement_thenCheckReturnsTrue() { + def map = [a: 'd', b: 'e', c: 'f'] + + assertTrue(map.containsKey('a')) + assertFalse(map.containsKey('e')) + assertTrue(map.containsValue('e')) + } + + @Test + void whenMapContainsKeyElement_thenCheckByMembershipReturnsTrue() { + def map = [a: 'd', b: 'e', c: 'f'] + + assertTrue('a' in map) + assertFalse('f' in map) + } + + @Test + void whenMapContainsFalseBooleanValues_thenCheckReturnsFalse() { + def map = [a: true, b: false, c: null] + + assertTrue(map.containsKey('b')) + assertTrue('a' in map) + assertFalse('b' in map) + assertFalse('c' in map) + } + + @Test + void givenMapOfPerson_whenUsingStreamMatching_thenShouldEvaluateMap() { + assertTrue(personMap.keySet().stream().anyMatch {it == "Regina"}) + assertFalse(personMap.keySet().stream().allMatch {it == "Albert"}) + assertFalse(personMap.values().stream().allMatch {it.age < 30}) + assertTrue(personMap.entrySet().stream().anyMatch {it.key == "Abagail" && it.value.lastname == "Ballard"}) + } + + @Test + void givenMapOfPerson_whenUsingCollectionMatching_thenShouldEvaluateMap() { + assertTrue(personMap.keySet().any {it == "Regina"}) + assertFalse(personMap.keySet().every {it == "Albert"}) + assertFalse(personMap.values().every {it.age < 30}) + assertTrue(personMap.any {firstname, person -> firstname == "Abagail" && person.lastname == "Ballard"}) + } + + @Test + void givenMapOfPerson_whenUsingCollectionFind_thenShouldReturnElements() { + assertNotNull(personMap.find {it.key == "Abagail" && it.value.lastname == "Ballard"}) + assertTrue(personMap.findAll {it.value.age > 20}.size() == 3) + } + + @Test + void givenMapOfPerson_whenUsingStreamFind_thenShouldReturnElements() { + assertTrue( + personMap.entrySet().stream() + .filter {it.key == "Abagail" && it.value.lastname == "Ballard"} + .findAny().isPresent()) + assertTrue( + personMap.entrySet().stream() + .filter {it.value.age > 20} + .findAll().size() == 3) + } } diff --git a/core-groovy/src/test/groovy/com/baeldung/set/SetUnitTest.groovy b/core-groovy/src/test/groovy/com/baeldung/set/SetUnitTest.groovy new file mode 100644 index 0000000000..1248c9ac91 --- /dev/null +++ b/core-groovy/src/test/groovy/com/baeldung/set/SetUnitTest.groovy @@ -0,0 +1,16 @@ +package com.baeldung.set + +import org.junit.Test + +import static org.junit.Assert.assertTrue + +class SetUnitTest { + + @Test + void whenSetContainsElement_thenCheckReturnsTrue() { + def set = ['a', 'b', 'c'] as Set + + assertTrue(set.contains('a')) + assertTrue('a' in set) + } +} \ No newline at end of file diff --git a/core-groovy/src/test/groovy/com/baeldung/strings/StringMatchingSpec.groovy b/core-groovy/src/test/groovy/com/baeldung/strings/StringMatchingSpec.groovy new file mode 100644 index 0000000000..3865bc73fa --- /dev/null +++ b/core-groovy/src/test/groovy/com/baeldung/strings/StringMatchingSpec.groovy @@ -0,0 +1,44 @@ +package com.baeldung.strings + +import spock.lang.Specification + +import java.util.regex.Pattern + +class StringMatchingSpec extends Specification { + + def "pattern operator example"() { + given: "a pattern" + def p = ~'foo' + + expect: + p instanceof Pattern + + and: "you can use slash strings to avoid escaping of blackslash" + def digitPattern = ~/\d*/ + digitPattern.matcher('4711').matches() + } + + def "match operator example"() { + expect: + 'foobar' ==~ /.*oba.*/ + + and: "matching is strict" + !('foobar' ==~ /foo/) + } + + def "find operator example"() { + when: "using the find operator" + def matcher = 'foo and bar, baz and buz' =~ /(\w+) and (\w+)/ + + then: "will find groups" + matcher.size() == 2 + + and: "can access groups using array" + matcher[0][0] == 'foo and bar' + matcher[1][2] == 'buz' + + and: "you can use it as a predicate" + 'foobarbaz' =~ /bar/ + } + +} diff --git a/core-java-11/README.md b/core-java-11/README.md index 3c8b94fa28..a4b0e0e59c 100644 --- a/core-java-11/README.md +++ b/core-java-11/README.md @@ -4,3 +4,6 @@ - [Java 11 Local Variable Syntax for Lambda Parameters](https://www.baeldung.com/java-var-lambda-params) - [Java 11 String API Additions](https://www.baeldung.com/java-11-string-api) - [Java 11 Nest Based Access Control](https://www.baeldung.com/java-nest-based-access-control) +- [Exploring the New HTTP Client in Java 9 and 11](https://www.baeldung.com/java-9-http-client) +- [An Introduction to Epsilon GC: A No-Op Experimental Garbage Collector](https://www.baeldung.com/jvm-epsilon-gc-garbage-collector) +- [Guide to jlink](https://www.baeldung.com/jlink) diff --git a/core-java-11/pom.xml b/core-java-11/pom.xml index a9776d8f3b..933acdbecc 100644 --- a/core-java-11/pom.xml +++ b/core-java-11/pom.xml @@ -14,6 +14,14 @@ 1.0.0-SNAPSHOT + + + com.google.guava + guava + ${guava.version} + + + @@ -31,6 +39,7 @@ 11 11 + 27.1-jre diff --git a/core-java-11/src/modules/jlinkModule/com/baeldung/jlink/HelloWorld.java b/core-java-11/src/modules/jlinkModule/com/baeldung/jlink/HelloWorld.java new file mode 100644 index 0000000000..47fe62ba40 --- /dev/null +++ b/core-java-11/src/modules/jlinkModule/com/baeldung/jlink/HelloWorld.java @@ -0,0 +1,12 @@ +package com.baeldung.jlink; + +import java.util.logging.Logger; + +public class HelloWorld { + + private static final Logger LOG = Logger.getLogger(HelloWorld.class.getName()); + + public static void main(String[] args) { + LOG.info("Hello World!"); + } +} diff --git a/core-java-11/src/modules/jlinkModule/module-info.java b/core-java-11/src/modules/jlinkModule/module-info.java new file mode 100644 index 0000000000..0587c65b53 --- /dev/null +++ b/core-java-11/src/modules/jlinkModule/module-info.java @@ -0,0 +1,3 @@ +module jlinkModule { + requires java.logging; +} \ No newline at end of file diff --git a/core-java-11/src/test/java/com/baeldung/EmptyStringToEmptyOptionalUnitTest.java b/core-java-11/src/test/java/com/baeldung/EmptyStringToEmptyOptionalUnitTest.java new file mode 100644 index 0000000000..cc429209d4 --- /dev/null +++ b/core-java-11/src/test/java/com/baeldung/EmptyStringToEmptyOptionalUnitTest.java @@ -0,0 +1,32 @@ +package com.baeldung; + +import com.google.common.base.Strings; +import org.junit.Assert; +import org.junit.Test; + +import java.util.Optional; +import java.util.function.Predicate; + +public class EmptyStringToEmptyOptionalUnitTest { + + @Test + public void givenEmptyString_whenFilteringOnOptional_thenEmptyOptionalIsReturned() { + String str = ""; + Optional opt = Optional.ofNullable(str).filter(s -> !s.isEmpty()); + Assert.assertFalse(opt.isPresent()); + } + + @Test + public void givenEmptyString_whenFilteringOnOptionalInJava11_thenEmptyOptionalIsReturned() { + String str = ""; + Optional opt = Optional.ofNullable(str).filter(Predicate.not(String::isEmpty)); + Assert.assertFalse(opt.isPresent()); + } + + @Test + public void givenEmptyString_whenPassingResultOfEmptyToNullToOfNullable_thenEmptyOptionalIsReturned() { + String str = ""; + Optional opt = Optional.ofNullable(Strings.emptyToNull(str)); + Assert.assertFalse(opt.isPresent()); + } +} diff --git a/core-java-12/pom.xml b/core-java-12/pom.xml new file mode 100644 index 0000000000..c5eec1a4bb --- /dev/null +++ b/core-java-12/pom.xml @@ -0,0 +1,49 @@ + + + 4.0.0 + com.baeldung + core-java-12 + 0.1.0-SNAPSHOT + core-java-12 + jar + http://maven.apache.org + + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + + + + + org.assertj + assertj-core + ${assertj.version} + test + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + ${maven.compiler.source.version} + ${maven.compiler.target.version} + --enable-preview + + + + + + + 12 + 12 + 3.6.1 + + + \ No newline at end of file diff --git a/core-java-12/src/test/java/com/baeldung/collectors/CollectorsUnitTest.java b/core-java-12/src/test/java/com/baeldung/collectors/CollectorsUnitTest.java new file mode 100644 index 0000000000..7c4cb9e8f0 --- /dev/null +++ b/core-java-12/src/test/java/com/baeldung/collectors/CollectorsUnitTest.java @@ -0,0 +1,71 @@ +package com.baeldung.collectors; + +import java.util.Arrays; +import java.util.List; +import java.util.Objects; + +import org.junit.Test; + +import static java.util.stream.Collectors.maxBy; +import static java.util.stream.Collectors.minBy; +import static java.util.stream.Collectors.teeing; +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Unit tests for collectors additions in Java 12. + */ +public class CollectorsUnitTest { + + @Test + public void whenTeeing_ItShouldCombineTheResultsAsExpected() { + List numbers = Arrays.asList(42, 4, 2, 24); + Range range = numbers.stream() + .collect(teeing(minBy(Integer::compareTo), maxBy(Integer::compareTo), (min, max) -> new Range(min.orElse(null), max.orElse(null)))); + + assertThat(range).isEqualTo(new Range(2, 42)); + } + + /** + * Represents a closed range of numbers between {@link #min} and + * {@link #max}, both inclusive. + */ + private static class Range { + + private final Integer min; + + private final Integer max; + + Range(Integer min, Integer max) { + this.min = min; + this.max = max; + } + + Integer getMin() { + return min; + } + + Integer getMax() { + return max; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + Range range = (Range) o; + return Objects.equals(getMin(), range.getMin()) && Objects.equals(getMax(), range.getMax()); + } + + @Override + public int hashCode() { + return Objects.hash(getMin(), getMax()); + } + + @Override + public String toString() { + return "Range{" + "min=" + min + ", max=" + max + '}'; + } + } +} diff --git a/core-java-12/src/test/java/com/baeldung/switchExpression/SwitchUnitTest.java b/core-java-12/src/test/java/com/baeldung/switchExpression/SwitchUnitTest.java new file mode 100644 index 0000000000..708e416090 --- /dev/null +++ b/core-java-12/src/test/java/com/baeldung/switchExpression/SwitchUnitTest.java @@ -0,0 +1,37 @@ +package com.baeldung.switchExpression; + +import org.junit.Assert; +import org.junit.Test; + +public class SwitchUnitTest { + + @Test + public void switchJava12(){ + + var month = Month.AUG; + + var value = switch(month){ + case JAN,JUN, JUL -> 3; + case FEB,SEP, OCT, NOV, DEC -> 1; + case MAR,MAY, APR, AUG -> 2; + }; + + Assert.assertEquals(value, 2); + } + + @Test + public void switchLocalVariable(){ + var month = Month.AUG; + int i = switch (month){ + case JAN,JUN, JUL -> 3; + case FEB,SEP, OCT, NOV, DEC -> 1; + case MAR,MAY, APR, AUG -> { + int j = month.toString().length() * 4; + break j; + } + }; + Assert.assertEquals(12, i); + } + + enum Month {JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC} +} diff --git a/core-java-8-2/.gitignore b/core-java-8-2/.gitignore new file mode 100644 index 0000000000..374c8bf907 --- /dev/null +++ b/core-java-8-2/.gitignore @@ -0,0 +1,25 @@ +*.class + +0.* + +#folders# +/target +/neoDb* +/data +/src/main/webapp/WEB-INF/classes +*/META-INF/* +.resourceCache + +# Packaged files # +*.jar +*.war +*.ear + +# Files generated by integration tests +backup-pom.xml +/bin/ +/temp + +#IntelliJ specific +.idea/ +*.iml \ No newline at end of file diff --git a/core-java-8-2/README.md b/core-java-8-2/README.md new file mode 100644 index 0000000000..e2b12e8819 --- /dev/null +++ b/core-java-8-2/README.md @@ -0,0 +1,6 @@ +========= + +## Core Java 8 Cookbooks and Examples (part 2) + +### Relevant Articles: +- [Anonymous Classes in Java](http://www.baeldung.com/) diff --git a/core-java-8-2/pom.xml b/core-java-8-2/pom.xml new file mode 100644 index 0000000000..4692a0fca6 --- /dev/null +++ b/core-java-8-2/pom.xml @@ -0,0 +1,50 @@ + + + 4.0.0 + com.baeldung + core-java-8-2 + 0.1.0-SNAPSHOT + core-java-8-2 + jar + + + + com.baeldung + parent-java + 0.0.1-SNAPSHOT + ../parent-java + + + + UTF-8 + 1.8 + 1.8 + 64.2 + + + + + com.ibm.icu + icu4j + ${icu.version} + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + ${maven.compiler.source} + ${maven.compiler.target} + + + + + + diff --git a/core-java-8-2/src/main/java/com/baeldung/jarArguments/JarExample.java b/core-java-8-2/src/main/java/com/baeldung/jarArguments/JarExample.java new file mode 100644 index 0000000000..c2fb809790 --- /dev/null +++ b/core-java-8-2/src/main/java/com/baeldung/jarArguments/JarExample.java @@ -0,0 +1,18 @@ +package com.baeldung.jarArguments; + +public class JarExample { + + public static void main(String[] args) { + System.out.println("Hello Baeldung Reader in JarExample!"); + + if(args == null) { + System.out.println("You have not provided any arguments!"); + }else { + System.out.println("There are "+args.length+" argument(s)!"); + for(int i=0; i locales = Arrays.asList(new Locale[] { Locale.UK, Locale.ITALY, Locale.FRANCE, Locale.forLanguageTag("pl-PL") }); + Localization.run(locales); + JavaSEFormat.run(locales); + ICUFormat.run(locales); + } + +} diff --git a/core-java-8-2/src/main/java/com/baeldung/localization/ICUFormat.java b/core-java-8-2/src/main/java/com/baeldung/localization/ICUFormat.java new file mode 100644 index 0000000000..f7bc357933 --- /dev/null +++ b/core-java-8-2/src/main/java/com/baeldung/localization/ICUFormat.java @@ -0,0 +1,29 @@ +package com.baeldung.localization; + +import java.util.List; +import java.util.Locale; +import java.util.ResourceBundle; + +import com.ibm.icu.text.MessageFormat; + +public class ICUFormat { + + public static String getLabel(Locale locale, Object[] data) { + ResourceBundle bundle = ResourceBundle.getBundle("formats", locale); + String format = bundle.getString("label-icu"); + MessageFormat formatter = new MessageFormat(format, locale); + return formatter.format(data); + } + + public static void run(List locales) { + System.out.println("ICU formatter"); + locales.forEach(locale -> System.out.println(getLabel(locale, new Object[] { "Alice", "female", 0 }))); + locales.forEach(locale -> System.out.println(getLabel(locale, new Object[] { "Alice", "female", 1 }))); + locales.forEach(locale -> System.out.println(getLabel(locale, new Object[] { "Alice", "female", 2 }))); + locales.forEach(locale -> System.out.println(getLabel(locale, new Object[] { "Alice", "female", 3 }))); + locales.forEach(locale -> System.out.println(getLabel(locale, new Object[] { "Bob", "male", 0 }))); + locales.forEach(locale -> System.out.println(getLabel(locale, new Object[] { "Bob", "male", 1 }))); + locales.forEach(locale -> System.out.println(getLabel(locale, new Object[] { "Bob", "male", 2 }))); + locales.forEach(locale -> System.out.println(getLabel(locale, new Object[] { "Bob", "male", 3 }))); + } +} diff --git a/core-java-8-2/src/main/java/com/baeldung/localization/JavaSEFormat.java b/core-java-8-2/src/main/java/com/baeldung/localization/JavaSEFormat.java new file mode 100644 index 0000000000..c95dfffa13 --- /dev/null +++ b/core-java-8-2/src/main/java/com/baeldung/localization/JavaSEFormat.java @@ -0,0 +1,24 @@ +package com.baeldung.localization; + +import java.text.MessageFormat; +import java.util.Date; +import java.util.List; +import java.util.Locale; +import java.util.ResourceBundle; + +public class JavaSEFormat { + + public static String getLabel(Locale locale, Object[] data) { + ResourceBundle bundle = ResourceBundle.getBundle("formats", locale); + final String pattern = bundle.getString("label"); + final MessageFormat formatter = new MessageFormat(pattern, locale); + return formatter.format(data); + } + + public static void run(List locales) { + System.out.println("Java formatter"); + final Date date = new Date(System.currentTimeMillis()); + locales.forEach(locale -> System.out.println(getLabel(locale, new Object[] { date, "Alice", 0 }))); + locales.forEach(locale -> System.out.println(getLabel(locale, new Object[] { date, "Alice", 2 }))); + } +} diff --git a/core-java-8-2/src/main/java/com/baeldung/localization/Localization.java b/core-java-8-2/src/main/java/com/baeldung/localization/Localization.java new file mode 100644 index 0000000000..17a6598ce0 --- /dev/null +++ b/core-java-8-2/src/main/java/com/baeldung/localization/Localization.java @@ -0,0 +1,18 @@ +package com.baeldung.localization; + +import java.util.List; +import java.util.Locale; +import java.util.ResourceBundle; + +public class Localization { + + public static String getLabel(Locale locale) { + final ResourceBundle bundle = ResourceBundle.getBundle("messages", locale); + return bundle.getString("label"); + } + + public static void run(List locales) { + locales.forEach(locale -> System.out.println(getLabel(locale))); + } + +} diff --git a/core-java-8-2/src/main/resources/example_manifest.txt b/core-java-8-2/src/main/resources/example_manifest.txt new file mode 100644 index 0000000000..71abcb05fb --- /dev/null +++ b/core-java-8-2/src/main/resources/example_manifest.txt @@ -0,0 +1 @@ +Main-Class: com.baeldung.jarArguments.JarExample diff --git a/core-java-8-2/src/main/resources/formats_en.properties b/core-java-8-2/src/main/resources/formats_en.properties new file mode 100644 index 0000000000..41e0e00119 --- /dev/null +++ b/core-java-8-2/src/main/resources/formats_en.properties @@ -0,0 +1,2 @@ +label=On {0, date, short} {1} has sent you {2, choice, 0#no messages|1#a message|2#two messages|2<{2,number,integer} messages}. +label-icu={0} has sent you {2, plural, =0 {no messages} =1 {a message} other {{2, number, integer} messages}}. \ No newline at end of file diff --git a/core-java-8-2/src/main/resources/formats_fr.properties b/core-java-8-2/src/main/resources/formats_fr.properties new file mode 100644 index 0000000000..c2d5159b32 --- /dev/null +++ b/core-java-8-2/src/main/resources/formats_fr.properties @@ -0,0 +1,2 @@ +label={0, date, short}, {1}{2, choice, 0# ne|0<} vous a envoy {2, choice, 0#aucun message|1#un message|2#deux messages|2<{2,number,integer} messages}. +label-icu={0} {2, plural, =0 {ne } other {}}vous a envoy {2, plural, =0 {aucun message} =1 {un message} other {{2, number, integer} messages}}. \ No newline at end of file diff --git a/core-java-8-2/src/main/resources/formats_it.properties b/core-java-8-2/src/main/resources/formats_it.properties new file mode 100644 index 0000000000..43fd1eee1c --- /dev/null +++ b/core-java-8-2/src/main/resources/formats_it.properties @@ -0,0 +1,2 @@ +label={0, date, short} {1} ti ha inviato {2, choice, 0#nessun messagio|1#un messaggio|2#due messaggi|2<{2, number, integer} messaggi}. +label-icu={0} {2, plural, =0 {non } other {}}ti ha inviato {2, plural, =0 {nessun messaggio} =1 {un messaggio} other {{2, number, integer} messaggi}}. \ No newline at end of file diff --git a/core-java-8-2/src/main/resources/formats_pl.properties b/core-java-8-2/src/main/resources/formats_pl.properties new file mode 100644 index 0000000000..9333ec3396 --- /dev/null +++ b/core-java-8-2/src/main/resources/formats_pl.properties @@ -0,0 +1,2 @@ +label=W {0, date, short} {1}{2, choice, 0# nie|0<} wys\u0142a\u0142a ci {2, choice, 0#\u017Cadnych wiadomo\u015Bci|1#wiadomo\u015B\u0107|2#dwie wiadomo\u015Bci|2<{2, number, integer} wiadomo\u015Bci}. +label-icu={0} {2, plural, =0 {nie } other {}}{1, select, male {wys\u0142a\u0142} female {wys\u0142a\u0142a} other {wys\u0142a\u0142o}} ci {2, plural, =0 {\u017Cadnej wiadomo\u015Bci} =1 {wiadomo\u015B\u0107} other {{2, number, integer} wiadomo\u015Bci}}. diff --git a/core-java-8-2/src/main/resources/messages_en.properties b/core-java-8-2/src/main/resources/messages_en.properties new file mode 100644 index 0000000000..bcbca9483c --- /dev/null +++ b/core-java-8-2/src/main/resources/messages_en.properties @@ -0,0 +1 @@ +label=Alice has sent you a message. diff --git a/core-java-8-2/src/main/resources/messages_fr.properties b/core-java-8-2/src/main/resources/messages_fr.properties new file mode 100644 index 0000000000..6716102568 --- /dev/null +++ b/core-java-8-2/src/main/resources/messages_fr.properties @@ -0,0 +1 @@ +label=Alice vous a envoy un message. \ No newline at end of file diff --git a/core-java-8-2/src/main/resources/messages_it.properties b/core-java-8-2/src/main/resources/messages_it.properties new file mode 100644 index 0000000000..6929a8c091 --- /dev/null +++ b/core-java-8-2/src/main/resources/messages_it.properties @@ -0,0 +1 @@ +label=Alice ti ha inviato un messaggio. \ No newline at end of file diff --git a/core-java-8-2/src/main/resources/messages_pl.properties b/core-java-8-2/src/main/resources/messages_pl.properties new file mode 100644 index 0000000000..5515a9920e --- /dev/null +++ b/core-java-8-2/src/main/resources/messages_pl.properties @@ -0,0 +1 @@ +label=Alice wys\u0142a\u0142a ci wiadomo\u015B\u0107. \ No newline at end of file diff --git a/core-java-8-2/src/test/java/com/baeldung/localization/ICUFormatUnitTest.java b/core-java-8-2/src/test/java/com/baeldung/localization/ICUFormatUnitTest.java new file mode 100644 index 0000000000..2c8f9b47f3 --- /dev/null +++ b/core-java-8-2/src/test/java/com/baeldung/localization/ICUFormatUnitTest.java @@ -0,0 +1,74 @@ +package com.baeldung.localization; + +import static org.junit.Assert.assertEquals; + +import java.util.Locale; + +import org.junit.Test; + +import com.baeldung.localization.ICUFormat; + +public class ICUFormatUnitTest { + + @Test + public void givenInUK_whenAliceSendsNothing_thenCorrectMessage() { + assertEquals("Alice has sent you no messages.", ICUFormat.getLabel(Locale.UK, new Object[] { "Alice", "female", 0 })); + } + + @Test + public void givenInUK_whenAliceSendsOneMessage_thenCorrectMessage() { + assertEquals("Alice has sent you a message.", ICUFormat.getLabel(Locale.UK, new Object[] { "Alice", "female", 1 })); + } + + @Test + public void givenInUK_whenBobSendsSixMessages_thenCorrectMessage() { + assertEquals("Bob has sent you 6 messages.", ICUFormat.getLabel(Locale.UK, new Object[] { "Bob", "male", 6 })); + } + + @Test + public void givenInItaly_whenAliceSendsNothing_thenCorrectMessage() { + assertEquals("Alice non ti ha inviato nessun messaggio.", ICUFormat.getLabel(Locale.ITALY, new Object[] { "Alice", "female", 0 })); + } + + @Test + public void givenInItaly_whenAliceSendsOneMessage_thenCorrectMessage() { + assertEquals("Alice ti ha inviato un messaggio.", ICUFormat.getLabel(Locale.ITALY, new Object[] { "Alice", "female", 1 })); + } + + @Test + public void givenInItaly_whenBobSendsSixMessages_thenCorrectMessage() { + assertEquals("Bob ti ha inviato 6 messaggi.", ICUFormat.getLabel(Locale.ITALY, new Object[] { "Bob", "male", 6 })); + } + + @Test + public void givenInFrance_whenAliceSendsNothing_thenCorrectMessage() { + assertEquals("Alice ne vous a envoyé aucun message.", ICUFormat.getLabel(Locale.FRANCE, new Object[] { "Alice", "female", 0 })); + } + + @Test + public void givenInFrance_whenAliceSendsOneMessage_thenCorrectMessage() { + assertEquals("Alice vous a envoyé un message.", ICUFormat.getLabel(Locale.FRANCE, new Object[] { "Alice", "female", 1 })); + } + + @Test + public void givenInFrance_whenBobSendsSixMessages_thenCorrectMessage() { + assertEquals("Bob vous a envoyé 6 messages.", ICUFormat.getLabel(Locale.FRANCE, new Object[] { "Bob", "male", 6 })); + } + + + @Test + public void givenInPoland_whenAliceSendsNothing_thenCorrectMessage() { + assertEquals("Alice nie wysłała ci żadnej wiadomości.", ICUFormat.getLabel(Locale.forLanguageTag("pl-PL"), new Object[] { "Alice", "female", 0 })); + } + + @Test + public void givenInPoland_whenAliceSendsOneMessage_thenCorrectMessage() { + assertEquals("Alice wysłała ci wiadomość.", ICUFormat.getLabel(Locale.forLanguageTag("pl-PL"), new Object[] { "Alice", "female", 1 })); + } + + @Test + public void givenInPoland_whenBobSendsSixMessages_thenCorrectMessage() { + assertEquals("Bob wysłał ci 6 wiadomości.", ICUFormat.getLabel(Locale.forLanguageTag("pl-PL"), new Object[] { "Bob", "male", 6 })); + } + +} diff --git a/core-java-8/README.md b/core-java-8/README.md index 99182da390..d11d2debce 100644 --- a/core-java-8/README.md +++ b/core-java-8/README.md @@ -3,7 +3,7 @@ ## Core Java 8 Cookbooks and Examples ### Relevant Articles: -- [Java 8 Collectors](http://www.baeldung.com/java-8-collectors) +- [Guide to Java 8’s Collectors](http://www.baeldung.com/java-8-collectors) - [Functional Interfaces in Java 8](http://www.baeldung.com/java-8-functional-interfaces) - [Java 8 – Powerful Comparison with Lambdas](http://www.baeldung.com/java-8-sort-lambda) - [New Features in Java 8](http://www.baeldung.com/java-8-new-features) diff --git a/core-java-8/src/main/java/com/baeldung/Adder.java b/core-java-8/src/main/java/com/baeldung/Adder.java deleted file mode 100644 index e3e100f121..0000000000 --- a/core-java-8/src/main/java/com/baeldung/Adder.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.baeldung; - -import java.util.function.Consumer; -import java.util.function.Function; - -public interface Adder { - - String addWithFunction(Function f); - - void addWithConsumer(Consumer f); - -} diff --git a/core-java-8/src/main/java/com/baeldung/AdderImpl.java b/core-java-8/src/main/java/com/baeldung/AdderImpl.java deleted file mode 100644 index 7852934d55..0000000000 --- a/core-java-8/src/main/java/com/baeldung/AdderImpl.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.baeldung; - - -import java.util.function.Consumer; -import java.util.function.Function; - -public class AdderImpl implements Adder { - - @Override - public String addWithFunction(final Function f) { - return f.apply("Something "); - } - - @Override - public void addWithConsumer(final Consumer f) { - } - -} diff --git a/core-java-8/src/main/java/com/baeldung/Bar.java b/core-java-8/src/main/java/com/baeldung/java8/lambda/tips/Bar.java similarity index 80% rename from core-java-8/src/main/java/com/baeldung/Bar.java rename to core-java-8/src/main/java/com/baeldung/java8/lambda/tips/Bar.java index 6219bddf74..4cf0aa2399 100644 --- a/core-java-8/src/main/java/com/baeldung/Bar.java +++ b/core-java-8/src/main/java/com/baeldung/java8/lambda/tips/Bar.java @@ -1,4 +1,4 @@ -package com.baeldung; +package com.baeldung.java8.lambda.tips; @FunctionalInterface diff --git a/core-java-8/src/main/java/com/baeldung/Baz.java b/core-java-8/src/main/java/com/baeldung/java8/lambda/tips/Baz.java similarity index 80% rename from core-java-8/src/main/java/com/baeldung/Baz.java rename to core-java-8/src/main/java/com/baeldung/java8/lambda/tips/Baz.java index 23180551ac..c7efe14c89 100644 --- a/core-java-8/src/main/java/com/baeldung/Baz.java +++ b/core-java-8/src/main/java/com/baeldung/java8/lambda/tips/Baz.java @@ -1,4 +1,4 @@ -package com.baeldung; +package com.baeldung.java8.lambda.tips; @FunctionalInterface diff --git a/core-java-8/src/main/java/com/baeldung/Foo.java b/core-java-8/src/main/java/com/baeldung/java8/lambda/tips/Foo.java similarity index 75% rename from core-java-8/src/main/java/com/baeldung/Foo.java rename to core-java-8/src/main/java/com/baeldung/java8/lambda/tips/Foo.java index c8223727a1..b63ba61e7e 100644 --- a/core-java-8/src/main/java/com/baeldung/Foo.java +++ b/core-java-8/src/main/java/com/baeldung/java8/lambda/tips/Foo.java @@ -1,4 +1,4 @@ -package com.baeldung; +package com.baeldung.java8.lambda.tips; @FunctionalInterface diff --git a/core-java-8/src/main/java/com/baeldung/FooExtended.java b/core-java-8/src/main/java/com/baeldung/java8/lambda/tips/FooExtended.java similarity index 81% rename from core-java-8/src/main/java/com/baeldung/FooExtended.java rename to core-java-8/src/main/java/com/baeldung/java8/lambda/tips/FooExtended.java index 8c9b21e397..9141cd8eb8 100644 --- a/core-java-8/src/main/java/com/baeldung/FooExtended.java +++ b/core-java-8/src/main/java/com/baeldung/java8/lambda/tips/FooExtended.java @@ -1,4 +1,4 @@ -package com.baeldung; +package com.baeldung.java8.lambda.tips; @FunctionalInterface diff --git a/core-java-8/src/main/java/com/baeldung/java8/lambda/tips/Processor.java b/core-java-8/src/main/java/com/baeldung/java8/lambda/tips/Processor.java new file mode 100644 index 0000000000..7931129cf5 --- /dev/null +++ b/core-java-8/src/main/java/com/baeldung/java8/lambda/tips/Processor.java @@ -0,0 +1,12 @@ +package com.baeldung.java8.lambda.tips; + +import java.util.concurrent.Callable; +import java.util.function.Supplier; + +public interface Processor { + + String processWithCallable(Callable c) throws Exception; + + String processWithSupplier(Supplier s); + +} diff --git a/core-java-8/src/main/java/com/baeldung/java8/lambda/tips/ProcessorImpl.java b/core-java-8/src/main/java/com/baeldung/java8/lambda/tips/ProcessorImpl.java new file mode 100644 index 0000000000..cb1b3dcdd2 --- /dev/null +++ b/core-java-8/src/main/java/com/baeldung/java8/lambda/tips/ProcessorImpl.java @@ -0,0 +1,20 @@ +package com.baeldung.java8.lambda.tips; + + +import java.util.concurrent.Callable; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Supplier; + +public class ProcessorImpl implements Processor { + + @Override + public String processWithCallable(Callable c) throws Exception { + return c.call(); + } + + @Override + public String processWithSupplier(Supplier s) { + return s.get(); + } +} diff --git a/core-java-8/src/main/java/com/baeldung/UseFoo.java b/core-java-8/src/main/java/com/baeldung/java8/lambda/tips/UseFoo.java similarity index 95% rename from core-java-8/src/main/java/com/baeldung/UseFoo.java rename to core-java-8/src/main/java/com/baeldung/java8/lambda/tips/UseFoo.java index 950d02062d..a64d8bb920 100644 --- a/core-java-8/src/main/java/com/baeldung/UseFoo.java +++ b/core-java-8/src/main/java/com/baeldung/java8/lambda/tips/UseFoo.java @@ -1,4 +1,4 @@ -package com.baeldung; +package com.baeldung.java8.lambda.tips; import java.util.function.Function; diff --git a/core-java-8/src/test/java/com/baeldung/java8/Java8SortUnitTest.java b/core-java-8/src/test/java/com/baeldung/java8/Java8SortUnitTest.java index 71ec5b147f..57d9d8347b 100644 --- a/core-java-8/src/test/java/com/baeldung/java8/Java8SortUnitTest.java +++ b/core-java-8/src/test/java/com/baeldung/java8/Java8SortUnitTest.java @@ -124,11 +124,44 @@ public class Java8SortUnitTest { @Test public final void givenStreamCustomOrdering_whenSortingEntitiesByName_thenCorrectlySorted() { - final List humans = Lists.newArrayList(new Human("Sarah", 10), new Human("Jack", 12)); final Comparator nameComparator = (h1, h2) -> h1.getName().compareTo(h2.getName()); final List sortedHumans = humans.stream().sorted(nameComparator).collect(Collectors.toList()); Assert.assertThat(sortedHumans.get(0), equalTo(new Human("Jack", 12))); } + + @Test + public final void givenStreamComparatorOrdering_whenSortingEntitiesByName_thenCorrectlySorted() { + final List humans = Lists.newArrayList(new Human("Sarah", 10), new Human("Jack", 12)); + + final List sortedHumans = humans.stream().sorted(Comparator.comparing(Human::getName)).collect(Collectors.toList()); + Assert.assertThat(sortedHumans.get(0), equalTo(new Human("Jack", 12))); + } + + @Test + public final void givenStreamNaturalOrdering_whenSortingEntitiesByNameReversed_thenCorrectlySorted() { + final List letters = Lists.newArrayList("B", "A", "C"); + + final List reverseSortedLetters = letters.stream().sorted(Comparator.reverseOrder()).collect(Collectors.toList()); + Assert.assertThat(reverseSortedLetters.get(0), equalTo("C")); + } + + @Test + public final void givenStreamCustomOrdering_whenSortingEntitiesByNameReversed_thenCorrectlySorted() { + final List humans = Lists.newArrayList(new Human("Sarah", 10), new Human("Jack", 12)); + final Comparator reverseNameComparator = (h1, h2) -> h2.getName().compareTo(h1.getName()); + + final List reverseSortedHumans = humans.stream().sorted(reverseNameComparator).collect(Collectors.toList()); + Assert.assertThat(reverseSortedHumans.get(0), equalTo(new Human("Sarah", 10))); + } + + @Test + public final void givenStreamComparatorOrdering_whenSortingEntitiesByNameReversed_thenCorrectlySorted() { + final List humans = Lists.newArrayList(new Human("Sarah", 10), new Human("Jack", 12)); + + final List reverseSortedHumans = humans.stream().sorted(Comparator.comparing(Human::getName, Comparator.reverseOrder())).collect(Collectors.toList()); + Assert.assertThat(reverseSortedHumans.get(0), equalTo(new Human("Sarah", 10))); + } + } diff --git a/core-java-8/src/test/java/com/baeldung/java8/Java8FunctionalInteracesLambdasUnitTest.java b/core-java-8/src/test/java/com/baeldung/java8/lambda/tips/Java8FunctionalInteracesLambdasUnitTest.java similarity index 93% rename from core-java-8/src/test/java/com/baeldung/java8/Java8FunctionalInteracesLambdasUnitTest.java rename to core-java-8/src/test/java/com/baeldung/java8/lambda/tips/Java8FunctionalInteracesLambdasUnitTest.java index 13ddcc805f..b409f8e37f 100644 --- a/core-java-8/src/test/java/com/baeldung/java8/Java8FunctionalInteracesLambdasUnitTest.java +++ b/core-java-8/src/test/java/com/baeldung/java8/lambda/tips/Java8FunctionalInteracesLambdasUnitTest.java @@ -1,8 +1,8 @@ -package com.baeldung.java8; +package com.baeldung.java8.lambda.tips; -import com.baeldung.Foo; -import com.baeldung.FooExtended; -import com.baeldung.UseFoo; +import com.baeldung.java8.lambda.tips.Foo; +import com.baeldung.java8.lambda.tips.FooExtended; +import com.baeldung.java8.lambda.tips.UseFoo; import org.junit.Before; import org.junit.Test; diff --git a/core-java-8/src/test/java/com/baeldung/java8/optional/OptionalChainingUnitTest.java b/core-java-8/src/test/java/com/baeldung/java8/optional/OptionalChainingUnitTest.java new file mode 100644 index 0000000000..70ec324cb3 --- /dev/null +++ b/core-java-8/src/test/java/com/baeldung/java8/optional/OptionalChainingUnitTest.java @@ -0,0 +1,110 @@ +package com.baeldung.java8.optional; + +import org.junit.Before; +import org.junit.Test; + +import java.util.Optional; +import java.util.function.Supplier; +import java.util.stream.Stream; + +import static org.junit.Assert.*; + +public class OptionalChainingUnitTest { + + private boolean getEmptyEvaluated; + private boolean getHelloEvaluated; + private boolean getByeEvaluated; + + @Before + public void setUp() { + getEmptyEvaluated = false; + getHelloEvaluated = false; + getByeEvaluated = false; + } + + @Test + public void givenThreeOptionals_whenChaining_thenFirstNonEmptyIsReturned() { + Optional found = Stream.of(getEmpty(), getHello(), getBye()) + .filter(Optional::isPresent) + .map(Optional::get) + .findFirst(); + + assertEquals(getHello(), found); + } + + @Test + public void givenTwoEmptyOptionals_whenChaining_thenEmptyOptionalIsReturned() { + Optional found = Stream.of(getEmpty(), getEmpty()) + .filter(Optional::isPresent) + .map(Optional::get) + .findFirst(); + + assertFalse(found.isPresent()); + } + + @Test + public void givenTwoEmptyOptionals_whenChaining_thenDefaultIsReturned() { + String found = Stream.>>of( + () -> createOptional("empty"), + () -> createOptional("empty") + ) + .map(Supplier::get) + .filter(Optional::isPresent) + .map(Optional::get) + .findFirst() + .orElseGet(() -> "default"); + + assertEquals("default", found); + } + + @Test + public void givenThreeOptionals_whenChaining_thenFirstNonEmptyIsReturnedAndRestNotEvaluated() { + Optional found = Stream.>>of(this::getEmpty, this::getHello, this::getBye) + .map(Supplier::get) + .filter(Optional::isPresent) + .map(Optional::get) + .findFirst(); + + assertTrue(this.getEmptyEvaluated); + assertTrue(this.getHelloEvaluated); + assertFalse(this.getByeEvaluated); + assertEquals(getHello(), found); + } + + @Test + public void givenTwoOptionalsReturnedByOneArgMethod_whenChaining_thenFirstNonEmptyIsReturned() { + Optional found = Stream.>>of( + () -> createOptional("empty"), + () -> createOptional("hello") + ) + .map(Supplier::get) + .filter(Optional::isPresent) + .map(Optional::get) + .findFirst(); + + assertEquals(createOptional("hello"), found); + } + + private Optional getEmpty() { + this.getEmptyEvaluated = true; + return Optional.empty(); + } + + private Optional getHello() { + this.getHelloEvaluated = true; + return Optional.of("hello"); + } + + private Optional getBye() { + this.getByeEvaluated = true; + return Optional.of("bye"); + } + + private Optional createOptional(String input) { + if (input == null || input == "" || input == "empty") { + return Optional.empty(); + } + + return Optional.of(input); + } +} \ No newline at end of file diff --git a/core-java-8/src/test/java/com/baeldung/java8/optional/OptionalUnitTest.java b/core-java-8/src/test/java/com/baeldung/java8/optional/OptionalUnitTest.java index 4cb2551fae..bd7943c77b 100644 --- a/core-java-8/src/test/java/com/baeldung/java8/optional/OptionalUnitTest.java +++ b/core-java-8/src/test/java/com/baeldung/java8/optional/OptionalUnitTest.java @@ -27,34 +27,35 @@ public class OptionalUnitTest { @Test public void givenNonNull_whenCreatesNonNullable_thenCorrect() { String name = "baeldung"; - Optional.of(name); + Optional opt = Optional.of(name); + assertTrue(opt.isPresent()); } @Test(expected = NullPointerException.class) public void givenNull_whenThrowsErrorOnCreate_thenCorrect() { String name = null; - Optional opt = Optional.of(name); + Optional.of(name); } @Test public void givenNonNull_whenCreatesOptional_thenCorrect() { String name = "baeldung"; Optional opt = Optional.of(name); - assertEquals("Optional[baeldung]", opt.toString()); + assertTrue(opt.isPresent()); } @Test public void givenNonNull_whenCreatesNullable_thenCorrect() { String name = "baeldung"; Optional opt = Optional.ofNullable(name); - assertEquals("Optional[baeldung]", opt.toString()); + assertTrue(opt.isPresent()); } @Test public void givenNull_whenCreatesNullable_thenCorrect() { String name = null; Optional opt = Optional.ofNullable(name); - assertEquals("Optional.empty", opt.toString()); + assertFalse(opt.isPresent()); } // Checking Value With isPresent() diff --git a/core-java-8/src/test/java/com/baeldung/reduceIfelse/CalculatorUnitTest.java b/core-java-8/src/test/java/com/baeldung/reduceIfelse/CalculatorUnitTest.java index fa351930d8..1ff34bee89 100644 --- a/core-java-8/src/test/java/com/baeldung/reduceIfelse/CalculatorUnitTest.java +++ b/core-java-8/src/test/java/com/baeldung/reduceIfelse/CalculatorUnitTest.java @@ -29,4 +29,11 @@ public class CalculatorUnitTest { int result = calculator.calculate(new AddCommand(3, 7)); assertEquals(10, result); } + + @Test + public void whenCalculateUsingFactory_thenReturnCorrectResult() { + Calculator calculator = new Calculator(); + int result = calculator.calculateUsingFactory(3, 4, "add"); + assertEquals(7, result); + } } diff --git a/core-java-9/README.md b/core-java-9/README.md index 224306db19..8fdc3f6ee2 100644 --- a/core-java-9/README.md +++ b/core-java-9/README.md @@ -5,27 +5,21 @@ [Java 9 New Features](http://www.baeldung.com/new-java-9) ### Relevant Articles: -- [Java 9 Stream API Improvements](http://www.baeldung.com/java-9-stream-api) -- [Java 9 Convenience Factory Methods for Collections](http://www.baeldung.com/java-9-collections-factory-methods) + +- [Java 9 New Features](https://www.baeldung.com/new-java-9) - [New Stream Collectors in Java 9](http://www.baeldung.com/java9-stream-collectors) -- [Java 9 CompletableFuture API Improvements](http://www.baeldung.com/java-9-completablefuture) -- [Java 9 Process API Improvements](http://www.baeldung.com/java-9-process-api) -- [Introduction to Java 9 StackWalking API](http://www.baeldung.com/java-9-stackwalking-api) - [Introduction to Project Jigsaw](http://www.baeldung.com/project-jigsaw-java-modularity) -- [Java 9 Optional API Additions](http://www.baeldung.com/java-9-optional) -- [Java 9 Reactive Streams](http://www.baeldung.com/java-9-reactive-streams) -- [Java 9 java.util.Objects Additions](http://www.baeldung.com/java-9-objects-new) -- [Java 9 Variable Handles Demistyfied](http://www.baeldung.com/java-variable-handles) +- [Java 9 Variable Handles Demystified](http://www.baeldung.com/java-variable-handles) - [Exploring the New HTTP Client in Java 9 and 11](http://www.baeldung.com/java-9-http-client) - [Method Handles in Java](http://www.baeldung.com/java-method-handles) - [Introduction to Chronicle Queue](http://www.baeldung.com/java-chronicle-queue) -- [A Guide to Java 9 Modularity](http://www.baeldung.com/java-9-modularity) - [Optional orElse Optional](http://www.baeldung.com/java-optional-or-else-optional) -- [Java 9 java.lang.Module API](http://www.baeldung.com/java-9-module-api) - [Iterate Through a Range of Dates in Java](https://www.baeldung.com/java-iterate-date-range) - [Initialize a HashMap in Java](https://www.baeldung.com/java-initialize-hashmap) -- [Java 9 Platform Logging API](https://www.baeldung.com/java-9-logging-api) -- [Guide to java.lang.Process API](https://www.baeldung.com/java-process-api) - [Immutable Set in Java](https://www.baeldung.com/java-immutable-set) - [Multi-Release Jar Files](https://www.baeldung.com/java-multi-release-jar) - [Ahead of Time Compilation (AoT)](https://www.baeldung.com/ahead-of-time-compilation) +- [Java 9 Process API Improvements](https://www.baeldung.com/java-9-process-api) +- [Guide to java.lang.Process API](https://www.baeldung.com/java-process-api) + + diff --git a/core-java-arrays/src/main/java/com/baeldung/array/AddElementToEndOfArray.java b/core-java-arrays/src/main/java/com/baeldung/array/AddElementToEndOfArray.java new file mode 100644 index 0000000000..dcd61cdfa7 --- /dev/null +++ b/core-java-arrays/src/main/java/com/baeldung/array/AddElementToEndOfArray.java @@ -0,0 +1,34 @@ +package com.baeldung.array; + +import java.util.ArrayList; +import java.util.Arrays; + +public class AddElementToEndOfArray { + + public Integer[] addElementUsingArraysCopyOf(Integer[] srcArray, int elementToAdd) { + Integer[] destArray = Arrays.copyOf(srcArray, srcArray.length + 1); + + destArray[destArray.length - 1] = elementToAdd; + return destArray; + } + + public Integer[] addElementUsingArrayList(Integer[] srcArray, int elementToAdd) { + Integer[] destArray = new Integer[srcArray.length + 1]; + + ArrayList arrayList = new ArrayList<>(Arrays.asList(srcArray)); + arrayList.add(elementToAdd); + + return arrayList.toArray(destArray); + } + + public Integer[] addElementUsingSystemArrayCopy(Integer[] srcArray, int elementToAdd) { + Integer[] destArray = new Integer[srcArray.length + 1]; + + System.arraycopy(srcArray, 0, destArray, 0, srcArray.length); + + destArray[destArray.length - 1] = elementToAdd; + + return destArray; + } + +} diff --git a/core-java-arrays/src/test/java/com/baeldung/array/AddElementToEndOfArrayUnitTest.java b/core-java-arrays/src/test/java/com/baeldung/array/AddElementToEndOfArrayUnitTest.java new file mode 100644 index 0000000000..f6f1f954f6 --- /dev/null +++ b/core-java-arrays/src/test/java/com/baeldung/array/AddElementToEndOfArrayUnitTest.java @@ -0,0 +1,49 @@ +package com.baeldung.array; + +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertArrayEquals; + +public class AddElementToEndOfArrayUnitTest { + + AddElementToEndOfArray addElementToEndOfArray; + + @Before + public void init() { + addElementToEndOfArray = new AddElementToEndOfArray(); + } + + @Test + public void givenSourceArrayAndElement_whenAddElementUsingArraysCopyIsInvoked_thenNewElementMustBeAdded() { + Integer[] sourceArray = {1, 2, 3, 4}; + int elementToAdd = 5; + + Integer[] destArray = addElementToEndOfArray.addElementUsingArraysCopyOf(sourceArray, elementToAdd); + + Integer[] expectedArray = {1, 2, 3, 4, 5}; + assertArrayEquals(expectedArray, destArray); + } + + @Test + public void givenSourceArrayAndElement_whenAddElementUsingArrayListIsInvoked_thenNewElementMustBeAdded() { + Integer[] sourceArray = {1, 2, 3, 4}; + int elementToAdd = 5; + + Integer[] destArray = addElementToEndOfArray.addElementUsingArrayList(sourceArray, elementToAdd); + + Integer[] expectedArray = {1, 2, 3, 4, 5}; + assertArrayEquals(expectedArray, destArray); + } + + @Test + public void givenSourceArrayAndElement_whenAddElementUsingSystemArrayCopyIsInvoked_thenNewElementMustBeAdded() { + Integer[] sourceArray = {1, 2, 3, 4}; + int elementToAdd = 5; + + Integer[] destArray = addElementToEndOfArray.addElementUsingSystemArrayCopy(sourceArray, elementToAdd); + + Integer[] expectedArray = {1, 2, 3, 4, 5}; + assertArrayEquals(expectedArray, destArray); + } +} diff --git a/core-java-collections-list/README.md b/core-java-collections-list/README.md index c5139074e9..bfe06581c0 100644 --- a/core-java-collections-list/README.md +++ b/core-java-collections-list/README.md @@ -30,3 +30,4 @@ - [Determine If All Elements Are the Same in a Java List](https://www.baeldung.com/java-list-all-equal) - [List of Primitive Integer Values in Java](https://www.baeldung.com/java-list-primitive-int) - [Performance Comparison of Primitive Lists in Java](https://www.baeldung.com/java-list-primitive-performance) +- [Filtering a Java Collection by a List](https://www.baeldung.com/java-filter-collection-by-list) diff --git a/core-java-collections-set/README.md b/core-java-collections-set/README.md new file mode 100644 index 0000000000..217e9ee6a5 --- /dev/null +++ b/core-java-collections-set/README.md @@ -0,0 +1,11 @@ +========= + +## Core Java Sets Cookbooks and Examples + +### Relevant Articles: +- [Set Operations in Java](http://www.baeldung.com/set-operations-in-java) +- [HashSet and TreeSet Comparison](http://www.baeldung.com/java-hashset-vs-treeset) +- [A Guide to HashSet in Java](http://www.baeldung.com/java-hashset) +- [A Guide to TreeSet in Java](http://www.baeldung.com/java-tree-set) +- [Initializing HashSet at the Time of Construction](http://www.baeldung.com/java-initialize-hashset) +- [Guide to EnumSet](https://www.baeldung.com/java-enumset) \ No newline at end of file diff --git a/core-java-collections-set/pom.xml b/core-java-collections-set/pom.xml new file mode 100644 index 0000000000..d5f7937645 --- /dev/null +++ b/core-java-collections-set/pom.xml @@ -0,0 +1,33 @@ + + 4.0.0 + core-java-collections-set + 0.1.0-SNAPSHOT + core-java-collections-set + jar + + + com.baeldung + parent-java + 0.0.1-SNAPSHOT + ../parent-java + + + + + com.google.guava + guava + ${guava.version} + + + org.apache.commons + commons-collections4 + ${commons-collections4.version} + + + + + 4.3 + 27.1-jre + + diff --git a/core-java-collections/src/main/java/com/baeldung/enumset/EnumSets.java b/core-java-collections-set/src/main/java/com/baeldung/enumset/EnumSets.java similarity index 100% rename from core-java-collections/src/main/java/com/baeldung/enumset/EnumSets.java rename to core-java-collections-set/src/main/java/com/baeldung/enumset/EnumSets.java diff --git a/core-java-collections/src/test/java/com/baeldung/collection/WhenUsingHashSet.java b/core-java-collections-set/src/test/java/com/baeldung/collection/WhenUsingHashSet.java similarity index 100% rename from core-java-collections/src/test/java/com/baeldung/collection/WhenUsingHashSet.java rename to core-java-collections-set/src/test/java/com/baeldung/collection/WhenUsingHashSet.java diff --git a/core-java-collections/src/test/java/com/baeldung/collection/WhenUsingTreeSet.java b/core-java-collections-set/src/test/java/com/baeldung/collection/WhenUsingTreeSet.java similarity index 100% rename from core-java-collections/src/test/java/com/baeldung/collection/WhenUsingTreeSet.java rename to core-java-collections-set/src/test/java/com/baeldung/collection/WhenUsingTreeSet.java diff --git a/core-java-collections/src/test/java/com/baeldung/java/set/HashSetInitalizingUnitTest.java b/core-java-collections-set/src/test/java/com/baeldung/java/set/HashSetInitalizingUnitTest.java similarity index 100% rename from core-java-collections/src/test/java/com/baeldung/java/set/HashSetInitalizingUnitTest.java rename to core-java-collections-set/src/test/java/com/baeldung/java/set/HashSetInitalizingUnitTest.java diff --git a/core-java/src/test/java/com/baeldung/java/set/SetUnitTest.java b/core-java-collections-set/src/test/java/com/baeldung/java/set/SetUnitTest.java similarity index 100% rename from core-java/src/test/java/com/baeldung/java/set/SetUnitTest.java rename to core-java-collections-set/src/test/java/com/baeldung/java/set/SetUnitTest.java diff --git a/core-java-collections-set/src/test/java/com/baeldung/set/SetOperationsUnitTest.java b/core-java-collections-set/src/test/java/com/baeldung/set/SetOperationsUnitTest.java new file mode 100644 index 0000000000..7c25585e49 --- /dev/null +++ b/core-java-collections-set/src/test/java/com/baeldung/set/SetOperationsUnitTest.java @@ -0,0 +1,93 @@ +package com.baeldung.set; + +import static org.junit.Assert.*; + +import org.apache.commons.collections4.SetUtils; +import org.junit.Test; + +import com.google.common.collect.Sets; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class SetOperationsUnitTest { + + private Set setA = setOf(1,2,3,4); + private Set setB = setOf(2,4,6,8); + + private static Set setOf(Integer... values) { + return new HashSet(Arrays.asList(values)); + } + + @Test + public void givenTwoSets_WhenWeRetainAll_ThenWeIntersectThem() { + Set intersectSet = new HashSet<>(setA); + intersectSet.retainAll(setB); + assertEquals(setOf(2,4), intersectSet); + } + + @Test + public void givenTwoSets_WhenWeAddAll_ThenWeUnionThem() { + Set unionSet = new HashSet<>(setA); + unionSet.addAll(setB); + assertEquals(setOf(1,2,3,4,6,8), unionSet); + } + + @Test + public void givenTwoSets_WhenRemoveAll_ThenWeGetTheDifference() { + Set differenceSet = new HashSet<>(setA); + differenceSet.removeAll(setB); + assertEquals(setOf(1,3), differenceSet); + } + + @Test + public void givenTwoStreams_WhenWeFilterThem_ThenWeCanGetTheIntersect() { + Set intersectSet = setA.stream() + .filter(setB::contains) + .collect(Collectors.toSet()); + assertEquals(setOf(2,4), intersectSet); + } + + @Test + public void givenTwoStreams_WhenWeConcatThem_ThenWeGetTheUnion() { + Set unionSet = Stream.concat(setA.stream(), setB.stream()) + .collect(Collectors.toSet()); + assertEquals(setOf(1,2,3,4,6,8), unionSet); + } + + @Test + public void givenTwoStreams_WhenWeFilterThem_ThenWeCanGetTheDifference() { + Set differenceSet = setA.stream() + .filter(val -> !setB.contains(val)) + .collect(Collectors.toSet()); + assertEquals(setOf(1,3), differenceSet); + } + + @Test + public void givenTwoSets_WhenWeUseApacheCommonsIntersect_ThenWeGetTheIntersect() { + Set intersectSet = SetUtils.intersection(setA, setB); + assertEquals(setOf(2,4), intersectSet); + } + + @Test + public void givenTwoSets_WhenWeUseApacheCommonsUnion_ThenWeGetTheUnion() { + Set unionSet = SetUtils.union(setA, setB); + assertEquals(setOf(1,2,3,4,6,8), unionSet); + } + + + @Test + public void givenTwoSets_WhenWeUseGuavaIntersect_ThenWeGetTheIntersect() { + Set intersectSet = Sets.intersection(setA, setB); + assertEquals(setOf(2,4), intersectSet); + } + + @Test + public void givenTwoSets_WhenWeUseGuavaUnion_ThenWeGetTheUnion() { + Set unionSet = Sets.union(setA, setB); + assertEquals(setOf(1,2,3,4,6,8), unionSet); + } +} diff --git a/core-java-collections/README.md b/core-java-collections/README.md index 80d4385c45..b34293769d 100644 --- a/core-java-collections/README.md +++ b/core-java-collections/README.md @@ -3,15 +3,11 @@ ## Core Java Collections Cookbooks and Examples ### Relevant Articles: -- [Java - Combine Multiple Collections](http://www.baeldung.com/java-combine-multiple-collections) -- [HashSet and TreeSet Comparison](http://www.baeldung.com/java-hashset-vs-treeset) +- [Java – Combine Multiple Collections](http://www.baeldung.com/java-combine-multiple-collections) - [Collect a Java Stream to an Immutable Collection](http://www.baeldung.com/java-stream-immutable-collection) - [Introduction to the Java ArrayDeque](http://www.baeldung.com/java-array-deque) -- [A Guide to HashSet in Java](http://www.baeldung.com/java-hashset) -- [A Guide to TreeSet in Java](http://www.baeldung.com/java-tree-set) - [Getting the Size of an Iterable in Java](http://www.baeldung.com/java-iterable-size) - [How to Filter a Collection in Java](http://www.baeldung.com/java-collection-filtering) -- [Initializing HashSet at the Time of Construction](http://www.baeldung.com/java-initialize-hashset) - [Removing the First Element of an Array](https://www.baeldung.com/java-array-remove-first-element) - [Fail-Safe Iterator vs Fail-Fast Iterator](http://www.baeldung.com/java-fail-safe-vs-fail-fast-iterator) - [Shuffling Collections In Java](http://www.baeldung.com/java-shuffle-collection) @@ -23,7 +19,6 @@ - [Time Complexity of Java Collections](https://www.baeldung.com/java-collections-complexity) - [Operating on and Removing an Item from Stream](https://www.baeldung.com/java-use-remove-item-stream) - [An Introduction to Synchronized Java Collections](https://www.baeldung.com/java-synchronized-collections) -- [Guide to EnumSet](https://www.baeldung.com/java-enumset) - [Removing Elements from Java Collections](https://www.baeldung.com/java-collection-remove-elements) - [Combining Different Types of Collections in Java](https://www.baeldung.com/java-combine-collections) - [Sorting in Java](http://www.baeldung.com/java-sorting) @@ -33,3 +28,4 @@ - [Differences Between HashMap and Hashtable](https://www.baeldung.com/hashmap-hashtable-differences) - [Java ArrayList vs Vector](https://www.baeldung.com/java-arraylist-vs-vector) - [Defining a Char Stack in Java](https://www.baeldung.com/java-char-stack) +- [Time Comparison of Arrays.sort(Object[]) and Arrays.sort(int[])](https://www.baeldung.com/arrays-sortobject-vs-sortint) diff --git a/core-java-concurrency-advanced/README.md b/core-java-concurrency-advanced/README.md index bcbec9d687..8e99858693 100644 --- a/core-java-concurrency-advanced/README.md +++ b/core-java-concurrency-advanced/README.md @@ -12,7 +12,7 @@ - [Guide to the Java Phaser](http://www.baeldung.com/java-phaser) - [An Introduction to Atomic Variables in Java](http://www.baeldung.com/java-atomic-variables) - [CyclicBarrier in Java](http://www.baeldung.com/java-cyclic-barrier) -- [Guide to Volatile Keyword in Java](http://www.baeldung.com/java-volatile) +- [Guide to the Volatile Keyword in Java](http://www.baeldung.com/java-volatile) - [Semaphores in Java](http://www.baeldung.com/java-semaphore) - [Daemon Threads in Java](http://www.baeldung.com/java-daemon-thread) - [Priority-based Job Scheduling in Java](http://www.baeldung.com/java-priority-job-schedule) @@ -20,5 +20,6 @@ - [Print Even and Odd Numbers Using 2 Threads](https://www.baeldung.com/java-even-odd-numbers-with-2-threads) - [Java CyclicBarrier vs CountDownLatch](https://www.baeldung.com/java-cyclicbarrier-countdownlatch) - [Guide to the Fork/Join Framework in Java](http://www.baeldung.com/java-fork-join) -- [A Guide to ThreadLocalRandom in Java](http://www.baeldung.com/java-thread-local-random) -- [The Thread.join() Method in Java](http://www.baeldung.com/java-thread-join) \ No newline at end of file +- [Guide to ThreadLocalRandom in Java](http://www.baeldung.com/java-thread-local-random) +- [The Thread.join() Method in Java](http://www.baeldung.com/java-thread-join) +- [Passing Parameters to Java Threads](https://www.baeldung.com/java-thread-parameters) diff --git a/core-java-concurrency-basic/README.md b/core-java-concurrency-basic/README.md index ad3de4a758..6fa702fbe7 100644 --- a/core-java-concurrency-basic/README.md +++ b/core-java-concurrency-basic/README.md @@ -7,12 +7,13 @@ - [A Guide to the Java ExecutorService](http://www.baeldung.com/java-executor-service-tutorial) - [Guide to java.util.concurrent.Future](http://www.baeldung.com/java-future) - [Difference Between Wait and Sleep in Java](http://www.baeldung.com/java-wait-and-sleep) -- [Guide to Synchronized Keyword in Java](http://www.baeldung.com/java-synchronized) +- [Guide to the Synchronized Keyword in Java](http://www.baeldung.com/java-synchronized) - [Overview of the java.util.concurrent](http://www.baeldung.com/java-util-concurrent) - [Implementing a Runnable vs Extending a Thread](http://www.baeldung.com/java-runnable-vs-extending-thread) - [How to Kill a Java Thread](http://www.baeldung.com/java-thread-stop) -- [ExecutorService - Waiting for Threads to Finish](http://www.baeldung.com/java-executor-wait-for-threads) +- [ExecutorService – Waiting for Threads to Finish](http://www.baeldung.com/java-executor-wait-for-threads) - [wait and notify() Methods in Java](http://www.baeldung.com/java-wait-notify) - [Life Cycle of a Thread in Java](http://www.baeldung.com/java-thread-lifecycle) - [Runnable vs. Callable in Java](http://www.baeldung.com/java-runnable-callable) -- [What is Thread-Safety and How to Achieve it](https://www.baeldung.com/java-thread-safety) +- [What is Thread-Safety and How to Achieve it?](https://www.baeldung.com/java-thread-safety) +- [How to Start a Thread in Java](https://www.baeldung.com/java-start-thread) diff --git a/core-java-io/README.md b/core-java-io/README.md index 5e0f7bfbd1..9ce39459dd 100644 --- a/core-java-io/README.md +++ b/core-java-io/README.md @@ -6,7 +6,7 @@ - [How to Read a Large File Efficiently with Java](http://www.baeldung.com/java-read-lines-large-file) - [Java InputStream to String](http://www.baeldung.com/convert-input-stream-to-string) - [Java – Write to File](http://www.baeldung.com/java-write-to-file) -- [Java - Convert File to InputStream](http://www.baeldung.com/convert-file-to-input-stream) +- [Java – Convert File to InputStream](http://www.baeldung.com/convert-file-to-input-stream) - [Java Scanner](http://www.baeldung.com/java-scanner) - [Java – Byte Array to Writer](http://www.baeldung.com/java-convert-byte-array-to-writer) - [Java – Directory Size](http://www.baeldung.com/java-folder-size) @@ -14,7 +14,7 @@ - [File Size in Java](http://www.baeldung.com/java-file-size) - [Comparing getPath(), getAbsolutePath(), and getCanonicalPath() in Java](http://www.baeldung.com/java-path) - [Using Java MappedByteBuffer](http://www.baeldung.com/java-mapped-byte-buffer) -- [Copy a File with Java](http://www.baeldung.com/java-copy-file) +- [How to Copy a File with Java](http://www.baeldung.com/java-copy-file) - [Java – Append Data to a File](http://www.baeldung.com/java-append-to-file) - [FileNotFoundException in Java](http://www.baeldung.com/java-filenotfound-exception) - [How to Read a File in Java](http://www.baeldung.com/reading-file-in-java) @@ -30,7 +30,6 @@ - [Download a File From an URL in Java](http://www.baeldung.com/java-download-file) - [Create a Symbolic Link with Java](http://www.baeldung.com/java-symlink) - [Quick Use of FilenameFilter](http://www.baeldung.com/java-filename-filter) -- [Initialize a HashMap in Java](https://www.baeldung.com/java-initialize-hashmap) - [Read a File into an ArrayList](https://www.baeldung.com/java-file-to-arraylist) - [Guide to Java OutputStream](https://www.baeldung.com/java-outputstream) - [Reading a CSV File into an Array](https://www.baeldung.com/java-csv-file-array) @@ -40,3 +39,4 @@ - [Create a Directory in Java](https://www.baeldung.com/java-create-directory) - [How to Write to a CSV File in Java](https://www.baeldung.com/java-csv) - [List Files in a Directory in Java](https://www.baeldung.com/java-list-directory-files) +- [Java InputStream to Byte Array and ByteBuffer](https://www.baeldung.com/convert-input-stream-to-array-of-bytes) diff --git a/core-java-io/src/test/java/com/baeldung/filechannel/FileChannelUnitTest.java b/core-java-io/src/test/java/com/baeldung/filechannel/FileChannelUnitTest.java new file mode 100644 index 0000000000..6964ba80e3 --- /dev/null +++ b/core-java-io/src/test/java/com/baeldung/filechannel/FileChannelUnitTest.java @@ -0,0 +1,165 @@ +package com.baeldung.filechannel; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.nio.ByteBuffer; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.channels.FileLock; +import java.nio.charset.StandardCharsets; + +import org.junit.Test; + +public class FileChannelUnitTest { + + @Test + public void givenFile_whenReadWithFileChannelUsingRandomAccessFile_thenCorrect() throws IOException { + + try (RandomAccessFile reader = new RandomAccessFile("src/test/resources/test_read.in", "r"); + FileChannel channel = reader.getChannel(); + ByteArrayOutputStream out = new ByteArrayOutputStream();) { + + int bufferSize = 1024; + if (bufferSize > channel.size()) { + bufferSize = (int) channel.size(); + } + ByteBuffer buff = ByteBuffer.allocate(bufferSize); + + while (channel.read(buff) > 0) { + out.write(buff.array(), 0, buff.position()); + buff.clear(); + } + + String fileContent = new String(out.toByteArray(), StandardCharsets.UTF_8); + + assertEquals("Hello world", fileContent); + } + } + + @Test + public void givenFile_whenReadWithFileChannelUsingFileInputStream_thenCorrect() throws IOException { + + try (ByteArrayOutputStream out = new ByteArrayOutputStream(); + FileInputStream fin = new FileInputStream("src/test/resources/test_read.in"); + FileChannel channel = fin.getChannel();) { + + int bufferSize = 1024; + if (bufferSize > channel.size()) { + bufferSize = (int) channel.size(); + } + ByteBuffer buff = ByteBuffer.allocate(bufferSize); + + while (channel.read(buff) > 0) { + out.write(buff.array(), 0, buff.position()); + buff.clear(); + } + String fileContent = new String(out.toByteArray(), StandardCharsets.UTF_8); + + assertEquals("Hello world", fileContent); + } + } + + @Test + public void givenFile_whenReadAFileSectionIntoMemoryWithFileChannel_thenCorrect() throws IOException { + + try (RandomAccessFile reader = new RandomAccessFile("src/test/resources/test_read.in", "r"); + FileChannel channel = reader.getChannel(); + ByteArrayOutputStream out = new ByteArrayOutputStream();) { + + MappedByteBuffer buff = channel.map(FileChannel.MapMode.READ_ONLY, 6, 5); + + if (buff.hasRemaining()) { + byte[] data = new byte[buff.remaining()]; + buff.get(data); + assertEquals("world", new String(data, StandardCharsets.UTF_8)); + } + } + } + + @Test + public void whenWriteWithFileChannelUsingRandomAccessFile_thenCorrect() throws IOException { + String file = "src/test/resources/test_write_using_filechannel.txt"; + try (RandomAccessFile writer = new RandomAccessFile(file, "rw"); + FileChannel channel = writer.getChannel();) { + ByteBuffer buff = ByteBuffer.wrap("Hello world".getBytes(StandardCharsets.UTF_8)); + + channel.write(buff); + + // now we verify whether the file was written correctly + RandomAccessFile reader = new RandomAccessFile(file, "r"); + assertEquals("Hello world", reader.readLine()); + reader.close(); + } + } + + @Test + public void givenFile_whenWriteAFileUsingLockAFileSectionWithFileChannel_thenCorrect() throws IOException { + try (RandomAccessFile reader = new RandomAccessFile("src/test/resources/test_read.in", "rw"); + FileChannel channel = reader.getChannel(); + FileLock fileLock = channel.tryLock(6, 5, Boolean.FALSE);) { + + assertNotNull(fileLock); + } + } + + @Test + public void givenFile_whenReadWithFileChannelGetPosition_thenCorrect() throws IOException { + + try (ByteArrayOutputStream out = new ByteArrayOutputStream(); + RandomAccessFile reader = new RandomAccessFile("src/test/resources/test_read.in", "r"); + FileChannel channel = reader.getChannel();) { + + int bufferSize = 1024; + if (bufferSize > channel.size()) { + bufferSize = (int) channel.size(); + } + ByteBuffer buff = ByteBuffer.allocate(bufferSize); + + while (channel.read(buff) > 0) { + out.write(buff.array(), 0, buff.position()); + buff.clear(); + } + + // the original file is 11 bytes long, so that's where the position pointer should be + assertEquals(11, channel.position()); + + channel.position(4); + assertEquals(4, channel.position()); + } + } + + @Test + public void whenGetFileSize_thenCorrect() throws IOException { + + try (RandomAccessFile reader = new RandomAccessFile("src/test/resources/test_read.in", "r"); + FileChannel channel = reader.getChannel();) { + + // the original file is 11 bytes long, so that's where the position pointer should be + assertEquals(11, channel.size()); + } + } + + @Test + public void whenTruncateFile_thenCorrect() throws IOException { + String input = "this is a test input"; + + FileOutputStream fout = new FileOutputStream("src/test/resources/test_truncate.txt"); + FileChannel channel = fout.getChannel(); + + ByteBuffer buff = ByteBuffer.wrap(input.getBytes()); + channel.write(buff); + buff.flip(); + + channel = channel.truncate(5); + assertEquals(5, channel.size()); + + fout.close(); + channel.close(); + } +} diff --git a/core-java-io/src/test/resources/test_truncate.txt b/core-java-io/src/test/resources/test_truncate.txt new file mode 100644 index 0000000000..26d3b38cdd --- /dev/null +++ b/core-java-io/src/test/resources/test_truncate.txt @@ -0,0 +1 @@ +this \ No newline at end of file diff --git a/core-java-io/src/test/resources/test_write_using_filechannel.txt b/core-java-io/src/test/resources/test_write_using_filechannel.txt new file mode 100644 index 0000000000..70c379b63f --- /dev/null +++ b/core-java-io/src/test/resources/test_write_using_filechannel.txt @@ -0,0 +1 @@ +Hello world \ No newline at end of file diff --git a/core-java-jvm/README.md b/core-java-jvm/README.md new file mode 100644 index 0000000000..82067ad952 --- /dev/null +++ b/core-java-jvm/README.md @@ -0,0 +1,6 @@ +========= + +## Core Java JVM Cookbooks and Examples + +### Relevant Articles: +- [Method Inlining in the JVM](https://www.baeldung.com/jvm-method-inlining) diff --git a/core-java-jvm/pom.xml b/core-java-jvm/pom.xml new file mode 100644 index 0000000000..752b26f03f --- /dev/null +++ b/core-java-jvm/pom.xml @@ -0,0 +1,40 @@ + + 4.0.0 + com.baeldung + core-java-jvm + 0.1.0-SNAPSHOT + jar + core-java-jvm + + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + + + + + junit + junit + ${junit.version} + test + + + org.apache.commons + commons-lang3 + ${commons-lang3.version} + + + org.assertj + assertj-core + ${assertj.version} + test + + + + + 3.5 + 3.6.1 + + diff --git a/core-java-jvm/src/main/java/com/baeldung/inlining/ConsecutiveNumbersSum.java b/core-java-jvm/src/main/java/com/baeldung/inlining/ConsecutiveNumbersSum.java new file mode 100644 index 0000000000..7de642f1c0 --- /dev/null +++ b/core-java-jvm/src/main/java/com/baeldung/inlining/ConsecutiveNumbersSum.java @@ -0,0 +1,19 @@ +package com.baeldung.inlining; + +public class ConsecutiveNumbersSum { + + private long totalSum; + private int totalNumbers; + + public ConsecutiveNumbersSum(int totalNumbers) { + this.totalNumbers = totalNumbers; + } + + public long getTotalSum() { + totalSum = 0; + for (int i = 1; i <= totalNumbers; i++) { + totalSum += i; + } + return totalSum; + } +} diff --git a/core-java-jvm/src/main/java/com/baeldung/inlining/InliningExample.java b/core-java-jvm/src/main/java/com/baeldung/inlining/InliningExample.java new file mode 100644 index 0000000000..4c1802d0e4 --- /dev/null +++ b/core-java-jvm/src/main/java/com/baeldung/inlining/InliningExample.java @@ -0,0 +1,16 @@ +package com.baeldung.inlining; + +public class InliningExample { + + public static final int NUMBERS_OF_ITERATIONS = 15000; + + public static void main(String[] args) { + for (int i = 1; i < NUMBERS_OF_ITERATIONS; i++) { + calculateSum(i); + } + } + + private static long calculateSum(int n) { + return new ConsecutiveNumbersSum(n).getTotalSum(); + } +} diff --git a/core-java-jvm/src/test/java/com/baeldung/inlining/ConsecutiveNumbersSumUnitTest.java b/core-java-jvm/src/test/java/com/baeldung/inlining/ConsecutiveNumbersSumUnitTest.java new file mode 100644 index 0000000000..8e4b0353e6 --- /dev/null +++ b/core-java-jvm/src/test/java/com/baeldung/inlining/ConsecutiveNumbersSumUnitTest.java @@ -0,0 +1,22 @@ +package com.baeldung.inlining; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class ConsecutiveNumbersSumUnitTest { + + private static final int TOTAL_NUMBERS = 10; + + @Test + public void givenTotalIntegersNumber_whenSumCalculated_thenEquals() { + ConsecutiveNumbersSum consecutiveNumbersSum = new ConsecutiveNumbersSum(TOTAL_NUMBERS); + long expectedSum = calculateExpectedSum(TOTAL_NUMBERS); + + assertEquals(expectedSum, consecutiveNumbersSum.getTotalSum()); + } + + private long calculateExpectedSum(int totalNumbers) { + return totalNumbers * (totalNumbers + 1) / 2; + } +} diff --git a/core-java-lambdas/pom.xml b/core-java-lambdas/pom.xml new file mode 100644 index 0000000000..25538a3524 --- /dev/null +++ b/core-java-lambdas/pom.xml @@ -0,0 +1,19 @@ + + + 4.0.0 + core-java-lambdas + 0.1.0-SNAPSHOT + core-java + jar + + + com.baeldung + parent-java + 0.0.1-SNAPSHOT + ../parent-java + + + + \ No newline at end of file diff --git a/core-java-lambdas/src/main/java/com/baeldung/lambdas/LambdaVariables.java b/core-java-lambdas/src/main/java/com/baeldung/lambdas/LambdaVariables.java new file mode 100644 index 0000000000..5c1201150f --- /dev/null +++ b/core-java-lambdas/src/main/java/com/baeldung/lambdas/LambdaVariables.java @@ -0,0 +1,88 @@ +package com.baeldung.lambdas; + +import java.util.Random; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.function.Supplier; +import java.util.stream.IntStream; + +/** + * Class with examples about working with capturing lambdas. + */ +public class LambdaVariables { + + private volatile boolean run = true; + private int start = 0; + + private ExecutorService executor = Executors.newFixedThreadPool(3); + + public static void main(String[] args) { + new LambdaVariables().localVariableMultithreading(); + } + + Supplier incrementer(int start) { + return () -> start; // can't modify start parameter inside the lambda + } + + Supplier incrementer() { + return () -> start++; + } + + public void localVariableMultithreading() { + boolean run = true; + executor.execute(() -> { + while (run) { + // do operation + } + }); + // commented because it doesn't compile, it's just an example of non-final local variables in lambdas + // run = false; + } + + public void instanceVariableMultithreading() { + executor.execute(() -> { + while (run) { + // do operation + } + }); + + run = false; + } + + /** + * WARNING: always avoid this workaround!! + */ + public void workaroundSingleThread() { + int[] holder = new int[] { 2 }; + IntStream sums = IntStream + .of(1, 2, 3) + .map(val -> val + holder[0]); + + holder[0] = 0; + + System.out.println(sums.sum()); + } + + /** + * WARNING: always avoid this workaround!! + */ + public void workaroundMultithreading() { + int[] holder = new int[] { 2 }; + Runnable runnable = () -> System.out.println(IntStream + .of(1, 2, 3) + .map(val -> val + holder[0]) + .sum()); + + new Thread(runnable).start(); + + // simulating some processing + try { + Thread.sleep(new Random().nextInt(3) * 1000L); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + + holder[0] = 0; + } + +} diff --git a/core-java-lang-oop-2/.gitignore b/core-java-lang-oop-2/.gitignore new file mode 100644 index 0000000000..36aba1c242 --- /dev/null +++ b/core-java-lang-oop-2/.gitignore @@ -0,0 +1,4 @@ +target/ +.idea/ +bin/ +*.iml \ No newline at end of file diff --git a/core-java-lang-oop-2/README.md b/core-java-lang-oop-2/README.md new file mode 100644 index 0000000000..af0aed5af3 --- /dev/null +++ b/core-java-lang-oop-2/README.md @@ -0,0 +1,6 @@ +========= + +## Core Java Lang OOP 2 Cookbooks and Examples + +### Relevant Articles: +- [Generic Constructors in Java](https://www.baeldung.com/java-generic-constructors) diff --git a/core-java-lang-oop-2/pom.xml b/core-java-lang-oop-2/pom.xml new file mode 100644 index 0000000000..3faf9fe6ee --- /dev/null +++ b/core-java-lang-oop-2/pom.xml @@ -0,0 +1,27 @@ + + 4.0.0 + com.baeldung + core-java-lang-oop-2 + 0.1.0-SNAPSHOT + core-java-lang-oop-2 + jar + + + com.baeldung + parent-java + 0.0.1-SNAPSHOT + ../parent-java + + + + core-java-lang-oop-2 + + + src/main/resources + true + + + + + diff --git a/core-java-lang-oop-2/src/main/java/com/baeldung/anonymous/Book.java b/core-java-lang-oop-2/src/main/java/com/baeldung/anonymous/Book.java new file mode 100644 index 0000000000..964156e8e4 --- /dev/null +++ b/core-java-lang-oop-2/src/main/java/com/baeldung/anonymous/Book.java @@ -0,0 +1,15 @@ +package com.baeldung.anonymous; + +public class Book { + + final String title; + + public Book(String title) { + this.title = title; + } + + public String description() { + return "Title: " + title; + } + +} diff --git a/core-java-lang-oop-2/src/main/java/com/baeldung/anonymous/Main.java b/core-java-lang-oop-2/src/main/java/com/baeldung/anonymous/Main.java new file mode 100644 index 0000000000..d4eed69567 --- /dev/null +++ b/core-java-lang-oop-2/src/main/java/com/baeldung/anonymous/Main.java @@ -0,0 +1,64 @@ +package com.baeldung.anonymous; + +import java.util.ArrayList; +import java.util.List; + +/** + * Code snippet that illustrates the usage of anonymous classes. + * + * Note that use of Runnable instances in this example does not demonstrate their + * common use. + * + * @author A. Shcherbakov + * + */ +public class Main { + + public static void main(String[] args) { + final List actions = new ArrayList(2); + + Runnable action = new Runnable() { + @Override + public void run() { + System.out.println("Hello from runnable."); + } + + }; + actions.add(action); + + Book book = new Book("Design Patterns") { + @Override + public String description() { + return "Famous GoF book."; + } + }; + + System.out.println(String.format("Title: %s, description: %s", book.title, book.description())); + + actions.add(new Runnable() { + @Override + public void run() { + System.out.println("Hello from runnable #2."); + + } + }); + + int count = 1; + + Runnable action2 = new Runnable() { + static final int x = 0; + // static int y = 0; + + @Override + public void run() { + System.out.println(String.format("Runnable with captured variables: count = %s, x = %s", count, x)); + } + }; + actions.add(action2); + + for (Runnable a : actions) { + a.run(); + } + } + +} diff --git a/core-java-lang-oop-2/src/main/java/com/baeldung/generics/Entry.java b/core-java-lang-oop-2/src/main/java/com/baeldung/generics/Entry.java new file mode 100644 index 0000000000..07759ca9ba --- /dev/null +++ b/core-java-lang-oop-2/src/main/java/com/baeldung/generics/Entry.java @@ -0,0 +1,38 @@ +package com.baeldung.generics; + +import java.io.Serializable; + +public class Entry { + private String data; + private int rank; + + // non-generic constructor + public Entry(String data, int rank) { + this.data = data; + this.rank = rank; + } + + // generic constructor + public Entry(E element) { + this.data = element.toString(); + this.rank = element.getRank(); + } + + // getters and setters + public String getData() { + return data; + } + + public void setData(String data) { + this.data = data; + } + + public int getRank() { + return rank; + } + + public void setRank(int rank) { + this.rank = rank; + } + +} diff --git a/core-java-lang-oop-2/src/main/java/com/baeldung/generics/GenericEntry.java b/core-java-lang-oop-2/src/main/java/com/baeldung/generics/GenericEntry.java new file mode 100644 index 0000000000..27d3a44069 --- /dev/null +++ b/core-java-lang-oop-2/src/main/java/com/baeldung/generics/GenericEntry.java @@ -0,0 +1,53 @@ +package com.baeldung.generics; + +import java.io.Serializable; +import java.util.Optional; + +public class GenericEntry { + private T data; + private int rank; + + // non-generic constructor + public GenericEntry(int rank) { + this.rank = rank; + } + + // generic constructor + public GenericEntry(T data, int rank) { + this.data = data; + this.rank = rank; + } + + // generic constructor with different type + public GenericEntry(E element) { + this.data = (T) element; + this.rank = element.getRank(); + } + + // generic constructor with different type and wild card + public GenericEntry(Optional optional) { + if (optional.isPresent()) { + this.data = (T) optional.get(); + this.rank = optional.get() + .getRank(); + } + } + + // getters and setters + public T getData() { + return data; + } + + public void setData(T data) { + this.data = data; + } + + public int getRank() { + return rank; + } + + public void setRank(int rank) { + this.rank = rank; + } + +} diff --git a/core-java-lang-oop-2/src/main/java/com/baeldung/generics/MapEntry.java b/core-java-lang-oop-2/src/main/java/com/baeldung/generics/MapEntry.java new file mode 100644 index 0000000000..3d626b2fa5 --- /dev/null +++ b/core-java-lang-oop-2/src/main/java/com/baeldung/generics/MapEntry.java @@ -0,0 +1,34 @@ +package com.baeldung.generics; + +public class MapEntry { + private K key; + private V value; + + public MapEntry() { + super(); + } + + // generic constructor with two parameters + public MapEntry(K key, V value) { + this.key = key; + this.value = value; + } + + // getters and setters + public K getKey() { + return key; + } + + public void setKey(K key) { + this.key = key; + } + + public V getValue() { + return value; + } + + public void setValue(V value) { + this.value = value; + } + +} diff --git a/core-java-lang-oop-2/src/main/java/com/baeldung/generics/Product.java b/core-java-lang-oop-2/src/main/java/com/baeldung/generics/Product.java new file mode 100644 index 0000000000..bfc9f63071 --- /dev/null +++ b/core-java-lang-oop-2/src/main/java/com/baeldung/generics/Product.java @@ -0,0 +1,50 @@ +package com.baeldung.generics; + +import java.io.Serializable; + +public class Product implements Rankable, Serializable { + private String name; + private double price; + private int sales; + + public Product(String name, double price) { + this.name = name; + this.price = price; + } + + @Override + public int getRank() { + return sales; + } + + @Override + public String toString() { + return "Product [name=" + name + ", price=" + price + ", sales=" + sales + "]"; + } + + // getters and setters + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public double getPrice() { + return price; + } + + public void setPrice(double price) { + this.price = price; + } + + public int getSales() { + return sales; + } + + public void setSales(int sales) { + this.sales = sales; + } + +} diff --git a/core-java-lang-oop-2/src/main/java/com/baeldung/generics/Rankable.java b/core-java-lang-oop-2/src/main/java/com/baeldung/generics/Rankable.java new file mode 100644 index 0000000000..72bda67d9d --- /dev/null +++ b/core-java-lang-oop-2/src/main/java/com/baeldung/generics/Rankable.java @@ -0,0 +1,5 @@ +package com.baeldung.generics; + +public interface Rankable { + public int getRank(); +} diff --git a/core-java-lang-oop-2/src/main/java/com/baeldung/supertypecompilerexception/MyClass.java b/core-java-lang-oop-2/src/main/java/com/baeldung/supertypecompilerexception/MyClass.java new file mode 100644 index 0000000000..ccf8646f57 --- /dev/null +++ b/core-java-lang-oop-2/src/main/java/com/baeldung/supertypecompilerexception/MyClass.java @@ -0,0 +1,16 @@ +package com.baeldung.supertypecompilerexception; + +public class MyClass { + + private int myField1 = 10; + private int myField2; + + public MyClass() { + //uncomment this to see the supertype compiler error: + //this(myField1); + } + + public MyClass(int i) { + myField2 = i; + } +} \ No newline at end of file diff --git a/core-java-lang-oop-2/src/main/java/com/baeldung/supertypecompilerexception/MyClassSolution1.java b/core-java-lang-oop-2/src/main/java/com/baeldung/supertypecompilerexception/MyClassSolution1.java new file mode 100644 index 0000000000..36fa446302 --- /dev/null +++ b/core-java-lang-oop-2/src/main/java/com/baeldung/supertypecompilerexception/MyClassSolution1.java @@ -0,0 +1,15 @@ +package com.baeldung.supertypecompilerexception; + +public class MyClassSolution1 { + + private int myField1 = 10; + private int myField2; + + public MyClassSolution1() { + myField2 = myField1; + } + + public MyClassSolution1(int i) { + myField2 = i; + } +} diff --git a/core-java-lang-oop-2/src/main/java/com/baeldung/supertypecompilerexception/MyClassSolution2.java b/core-java-lang-oop-2/src/main/java/com/baeldung/supertypecompilerexception/MyClassSolution2.java new file mode 100644 index 0000000000..adaea4bfbe --- /dev/null +++ b/core-java-lang-oop-2/src/main/java/com/baeldung/supertypecompilerexception/MyClassSolution2.java @@ -0,0 +1,19 @@ +package com.baeldung.supertypecompilerexception; + +public class MyClassSolution2 { + + private int myField1 = 10; + private int myField2; + + public MyClassSolution2() { + setupMyFields(myField1); + } + + public MyClassSolution2(int i) { + setupMyFields(i); + } + + private void setupMyFields(int i) { + myField2 = i; + } +} diff --git a/core-java-lang-oop-2/src/main/java/com/baeldung/supertypecompilerexception/MyClassSolution3.java b/core-java-lang-oop-2/src/main/java/com/baeldung/supertypecompilerexception/MyClassSolution3.java new file mode 100644 index 0000000000..04048f01db --- /dev/null +++ b/core-java-lang-oop-2/src/main/java/com/baeldung/supertypecompilerexception/MyClassSolution3.java @@ -0,0 +1,15 @@ +package com.baeldung.supertypecompilerexception; + +public class MyClassSolution3 { + + private static final int SOME_CONSTANT = 10; + private int myField2; + + public MyClassSolution3() { + this(SOME_CONSTANT); + } + + public MyClassSolution3(int i) { + myField2 = i; + } +} diff --git a/core-java-lang-oop-2/src/main/java/com/baeldung/supertypecompilerexception/MyException.java b/core-java-lang-oop-2/src/main/java/com/baeldung/supertypecompilerexception/MyException.java new file mode 100644 index 0000000000..db60deb83f --- /dev/null +++ b/core-java-lang-oop-2/src/main/java/com/baeldung/supertypecompilerexception/MyException.java @@ -0,0 +1,14 @@ +package com.baeldung.supertypecompilerexception; + +public class MyException extends RuntimeException { + private int errorCode = 0; + + public MyException(String message) { + //uncomment this to see the supertype compiler error: + //super(message + getErrorCode()); + } + + public int getErrorCode() { + return errorCode; + } +} diff --git a/core-java-lang-oop-2/src/test/java/com/baeldung/generics/GenericConstructorUnitTest.java b/core-java-lang-oop-2/src/test/java/com/baeldung/generics/GenericConstructorUnitTest.java new file mode 100644 index 0000000000..60907bbfd3 --- /dev/null +++ b/core-java-lang-oop-2/src/test/java/com/baeldung/generics/GenericConstructorUnitTest.java @@ -0,0 +1,76 @@ +package com.baeldung.generics; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import java.io.Serializable; +import java.util.Optional; + +import org.junit.Test; + +public class GenericConstructorUnitTest { + + @Test + public void givenNonGenericConstructor_whenCreateNonGenericEntry_thenOK() { + Entry entry = new Entry("sample", 1); + + assertEquals("sample", entry.getData()); + assertEquals(1, entry.getRank()); + } + + @Test + public void givenGenericConstructor_whenCreateNonGenericEntry_thenOK() { + Product product = new Product("milk", 2.5); + product.setSales(30); + Entry entry = new Entry(product); + + assertEquals(product.toString(), entry.getData()); + assertEquals(30, entry.getRank()); + } + + @Test + public void givenNonGenericConstructor_whenCreateGenericEntry_thenOK() { + GenericEntry entry = new GenericEntry(1); + + assertNull(entry.getData()); + assertEquals(1, entry.getRank()); + } + + @Test + public void givenGenericConstructor_whenCreateGenericEntry_thenOK() { + GenericEntry entry = new GenericEntry("sample", 1); + + assertEquals("sample", entry.getData()); + assertEquals(1, entry.getRank()); + } + + @Test + public void givenGenericConstructorWithDifferentType_whenCreateGenericEntry_thenOK() { + Product product = new Product("milk", 2.5); + product.setSales(30); + GenericEntry entry = new GenericEntry(product); + + assertEquals(product, entry.getData()); + assertEquals(30, entry.getRank()); + } + + @Test + public void givenGenericConstructorWithWildCard_whenCreateGenericEntry_thenOK() { + Product product = new Product("milk", 2.5); + product.setSales(30); + Optional optional = Optional.of(product); + GenericEntry entry = new GenericEntry(optional); + + assertEquals(product, entry.getData()); + assertEquals(30, entry.getRank()); + } + + @Test + public void givenGenericConstructor_whenCreateGenericEntryWithTwoTypes_thenOK() { + MapEntry entry = new MapEntry("sample", 1); + + assertEquals("sample", entry.getKey()); + assertEquals(1, entry.getValue() + .intValue()); + } +} diff --git a/core-java-lang-oop/README.md b/core-java-lang-oop/README.md index 200415fe21..c9ee9a9e94 100644 --- a/core-java-lang-oop/README.md +++ b/core-java-lang-oop/README.md @@ -5,13 +5,12 @@ ### Relevant Articles: - [Guide to hashCode() in Java](http://www.baeldung.com/java-hashcode) - [A Guide to the Static Keyword in Java](http://www.baeldung.com/java-static) -- [A Guide to Java Initialization](http://www.baeldung.com/java-initialization) - [Polymorphism in Java](http://www.baeldung.com/java-polymorphism) - [Method Overloading and Overriding in Java](http://www.baeldung.com/java-method-overload-override) - [How to Make a Deep Copy of an Object in Java](http://www.baeldung.com/java-deep-copy) - [Guide to Inheritance in Java](http://www.baeldung.com/java-inheritance) - [Object Type Casting in Java](http://www.baeldung.com/java-type-casting) -- [The "final" Keyword in Java](http://www.baeldung.com/java-final) +- [The “final” Keyword in Java](http://www.baeldung.com/java-final) - [Type Erasure in Java Explained](http://www.baeldung.com/java-type-erasure) - [Pass-By-Value as a Parameter Passing Mechanism in Java](http://www.baeldung.com/java-pass-by-value-or-pass-by-reference) - [Variable and Method Hiding in Java](http://www.baeldung.com/java-variable-method-hiding) diff --git a/core-java-lang-syntax/src/main/java/com/baeldung/enums/README.md b/core-java-lang-syntax/src/main/java/com/baeldung/enums/README.md deleted file mode 100644 index 6ccfa725f5..0000000000 --- a/core-java-lang-syntax/src/main/java/com/baeldung/enums/README.md +++ /dev/null @@ -1,2 +0,0 @@ -### Relevant Articles: -- [A Guide to Java Enums](http://www.baeldung.com/a-guide-to-java-enums) diff --git a/core-java-lang-syntax/src/main/java/com/baeldung/generics/Generics.java b/core-java-lang-syntax/src/main/java/com/baeldung/generics/Generics.java index e0536ca02e..1c4082c58b 100644 --- a/core-java-lang-syntax/src/main/java/com/baeldung/generics/Generics.java +++ b/core-java-lang-syntax/src/main/java/com/baeldung/generics/Generics.java @@ -1,5 +1,6 @@ package com.baeldung.generics; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.function.Function; @@ -28,4 +29,10 @@ public class Generics { buildings.forEach(Building::paint); } + public static List createList(int a) { + List list = new ArrayList<>(); + list.add(a); + return list; + } + } \ No newline at end of file diff --git a/core-java-lang-syntax/src/test/java/com/baeldung/generics/GenericsUnitTest.java b/core-java-lang-syntax/src/test/java/com/baeldung/generics/GenericsUnitTest.java index aca0b182a0..0bdf0afc15 100644 --- a/core-java-lang-syntax/src/test/java/com/baeldung/generics/GenericsUnitTest.java +++ b/core-java-lang-syntax/src/test/java/com/baeldung/generics/GenericsUnitTest.java @@ -6,6 +6,7 @@ import java.util.ArrayList; import java.util.List; import static org.hamcrest.CoreMatchers.hasItems; +import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.fail; @@ -66,4 +67,12 @@ public class GenericsUnitTest { } } + @Test + public void givenAnInt_whenAddedToAGenericIntegerList_thenAListItemCanBeAssignedToAnInt() { + int number = 7; + List list = Generics.createList(number); + int otherNumber = list.get(0); + assertThat(otherNumber, is(number)); + } + } \ No newline at end of file diff --git a/core-java-lang/README.md b/core-java-lang/README.md index eaedc93eed..e9169a5820 100644 --- a/core-java-lang/README.md +++ b/core-java-lang/README.md @@ -12,7 +12,7 @@ - [Dynamic Proxies in Java](http://www.baeldung.com/java-dynamic-proxies) - [Java Double Brace Initialization](http://www.baeldung.com/java-double-brace-initialization) - [Guide to the Diamond Operator in Java](http://www.baeldung.com/java-diamond-operator) -- [Quick Example - Comparator vs Comparable in Java](http://www.baeldung.com/java-comparator-comparable) +- [Comparator and Comparable in Java](http://www.baeldung.com/java-comparator-comparable) - [The Java continue and break Keywords](http://www.baeldung.com/java-continue-and-break) - [Nested Classes in Java](http://www.baeldung.com/java-nested-classes) - [A Guide to Inner Interfaces in Java](http://www.baeldung.com/java-inner-interfaces) diff --git a/core-java-modules/multimodulemavenproject/daomodule/pom.xml b/core-java-modules/multimodulemavenproject/daomodule/pom.xml new file mode 100644 index 0000000000..a260e15e6d --- /dev/null +++ b/core-java-modules/multimodulemavenproject/daomodule/pom.xml @@ -0,0 +1,27 @@ + + + 4.0.0 + + com.baeldung.multimodulemavenproject + multimodulemavenproject + 1.0 + + com.baeldung.daomodule + daomodule + 1.0 + jar + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + + + + 9 + 9 + + \ No newline at end of file diff --git a/core-java-modules/multimodulemavenproject/daomodule/src/main/java/com/baeldung/daomodule/Dao.java b/core-java-modules/multimodulemavenproject/daomodule/src/main/java/com/baeldung/daomodule/Dao.java new file mode 100644 index 0000000000..9568bae9d9 --- /dev/null +++ b/core-java-modules/multimodulemavenproject/daomodule/src/main/java/com/baeldung/daomodule/Dao.java @@ -0,0 +1,11 @@ +package com.baeldung.daomodule; +import java.util.List; +import java.util.Optional; + +public interface Dao { + + Optional findById(int id); + + List findAll(); + +} diff --git a/core-java-modules/multimodulemavenproject/daomodule/src/main/java/module-info.java b/core-java-modules/multimodulemavenproject/daomodule/src/main/java/module-info.java new file mode 100644 index 0000000000..20c51d316a --- /dev/null +++ b/core-java-modules/multimodulemavenproject/daomodule/src/main/java/module-info.java @@ -0,0 +1,3 @@ +module com.baeldung.daomodule { + exports com.baeldung.daomodule; +} diff --git a/core-java-modules/multimodulemavenproject/entitymodule/pom.xml b/core-java-modules/multimodulemavenproject/entitymodule/pom.xml new file mode 100644 index 0000000000..1fd672d03e --- /dev/null +++ b/core-java-modules/multimodulemavenproject/entitymodule/pom.xml @@ -0,0 +1,28 @@ + + + 4.0.0 + + com.baeldung.multimodulemavenproject + multimodulemavenproject + 1.0 + + com.baeldung.entitymodule + entitymodule + 1.0 + jar + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + + + + 9 + 9 + + + \ No newline at end of file diff --git a/core-java-modules/multimodulemavenproject/entitymodule/src/main/java/com/baeldung/entitymodule/User.java b/core-java-modules/multimodulemavenproject/entitymodule/src/main/java/com/baeldung/entitymodule/User.java new file mode 100644 index 0000000000..c025bffd87 --- /dev/null +++ b/core-java-modules/multimodulemavenproject/entitymodule/src/main/java/com/baeldung/entitymodule/User.java @@ -0,0 +1,19 @@ +package com.baeldung.entitymodule; + +public class User { + + private final String name; + + public User(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + @Override + public String toString() { + return "User{" + "name=" + name + '}'; + } +} \ No newline at end of file diff --git a/core-java-modules/multimodulemavenproject/entitymodule/src/main/java/module-info.java b/core-java-modules/multimodulemavenproject/entitymodule/src/main/java/module-info.java new file mode 100644 index 0000000000..b2c4553357 --- /dev/null +++ b/core-java-modules/multimodulemavenproject/entitymodule/src/main/java/module-info.java @@ -0,0 +1,3 @@ +module com.baeldung.entitymodule { + exports com.baeldung.entitymodule; +} diff --git a/core-java-modules/multimodulemavenproject/mainappmodule/pom.xml b/core-java-modules/multimodulemavenproject/mainappmodule/pom.xml new file mode 100644 index 0000000000..26e6a15b1e --- /dev/null +++ b/core-java-modules/multimodulemavenproject/mainappmodule/pom.xml @@ -0,0 +1,45 @@ + + + 4.0.0 + + com.baeldung.multimodulemavenproject + multimodulemavenproject + 1.0 + + com.baeldung.mainappmodule + mainappmodule + 1.0 + jar + + + + com.baeldung.entitymodule + entitymodule + 1.0 + + + com.baeldung.daomodule + daomodule + 1.0 + + + com.baeldung.userdaomodule + userdaomodule + 1.0 + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + + + + 9 + 9 + + \ No newline at end of file diff --git a/core-java-modules/multimodulemavenproject/mainappmodule/src/main/java/com/baeldung/mainappmodule/Application.java b/core-java-modules/multimodulemavenproject/mainappmodule/src/main/java/com/baeldung/mainappmodule/Application.java new file mode 100644 index 0000000000..cf0ba1d9bc --- /dev/null +++ b/core-java-modules/multimodulemavenproject/mainappmodule/src/main/java/com/baeldung/mainappmodule/Application.java @@ -0,0 +1,19 @@ +package com.baeldung.mainappmodule; + +import com.baeldung.daomodule.Dao; +import com.baeldung.entitymodule.User; +import com.baeldung.userdaomodule.UserDao; +import java.util.HashMap; +import java.util.Map; + +public class Application { + + public static void main(String args[]) { + Map users = new HashMap<>(); + users.put(1, new User("Julie")); + users.put(2, new User("David")); + Dao userDao = new UserDao(users); + userDao.findAll().forEach(System.out::println); + } + +} diff --git a/core-java-modules/multimodulemavenproject/mainappmodule/src/main/java/module-info.java b/core-java-modules/multimodulemavenproject/mainappmodule/src/main/java/module-info.java new file mode 100644 index 0000000000..dd7620c7bf --- /dev/null +++ b/core-java-modules/multimodulemavenproject/mainappmodule/src/main/java/module-info.java @@ -0,0 +1,8 @@ +module com.baeldung.mainppmodule { + + requires com.baeldung.entitymodule; + requires com.baeldung.daomodule; + requires com.baeldung.userdaomodule; + uses com.baeldung.userdaomodule.UserDao; + +} diff --git a/core-java-modules/multimodulemavenproject/pom.xml b/core-java-modules/multimodulemavenproject/pom.xml new file mode 100644 index 0000000000..3d56f1356b --- /dev/null +++ b/core-java-modules/multimodulemavenproject/pom.xml @@ -0,0 +1,62 @@ + + + 4.0.0 + com.baeldung.multimodulemavenproject + multimodulemavenproject + 1.0 + pom + multimodulemavenproject + + + parent-modules + com.baeldung + 1.0.0-SNAPSHOT + ../../ + + + + + + junit + junit + 4.12 + test + + + org.assertj + assertj-core + 3.12.2 + test + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + + 1.9 + 1.9 + + + + + + + + + entitymodule + daomodule + userdaomodule + mainappmodule + + + + UTF-8 + + diff --git a/core-java-modules/multimodulemavenproject/userdaomodule/pom.xml b/core-java-modules/multimodulemavenproject/userdaomodule/pom.xml new file mode 100644 index 0000000000..63968452db --- /dev/null +++ b/core-java-modules/multimodulemavenproject/userdaomodule/pom.xml @@ -0,0 +1,41 @@ + + + 4.0.0 + + com.baeldung.multimodulemavenproject + multimodulemavenproject + 1.0 + + com.baeldung.userdaomodule + userdaomodule + 1.0 + jar + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + + + + + com.baeldung.entitymodule + entitymodule + 1.0 + + + com.baeldung.daomodule + daomodule + 1.0 + + + + + 9 + 9 + + + \ No newline at end of file diff --git a/core-java-modules/multimodulemavenproject/userdaomodule/src/main/java/com/baeldung/userdaomodule/UserDao.java b/core-java-modules/multimodulemavenproject/userdaomodule/src/main/java/com/baeldung/userdaomodule/UserDao.java new file mode 100644 index 0000000000..aba157b431 --- /dev/null +++ b/core-java-modules/multimodulemavenproject/userdaomodule/src/main/java/com/baeldung/userdaomodule/UserDao.java @@ -0,0 +1,32 @@ +package com.baeldung.userdaomodule; + +import com.baeldung.daomodule.Dao; +import com.baeldung.entitymodule.User; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class UserDao implements Dao { + + private final Map users; + + public UserDao() { + users = new HashMap<>(); + } + + public UserDao(Map users) { + this.users = users; + } + + @Override + public List findAll() { + return new ArrayList<>(users.values()); + } + + @Override + public Optional findById(int id) { + return Optional.ofNullable(users.get(id)); + } +} \ No newline at end of file diff --git a/core-java-modules/multimodulemavenproject/userdaomodule/src/main/java/module-info.java b/core-java-modules/multimodulemavenproject/userdaomodule/src/main/java/module-info.java new file mode 100644 index 0000000000..6dd81dabe5 --- /dev/null +++ b/core-java-modules/multimodulemavenproject/userdaomodule/src/main/java/module-info.java @@ -0,0 +1,6 @@ +module com.baeldung.userdaomodule { + requires com.baeldung.entitymodule; + requires com.baeldung.daomodule; + provides com.baeldung.daomodule.Dao with com.baeldung.userdaomodule.UserDao; + exports com.baeldung.userdaomodule; +} diff --git a/core-java-modules/pom.xml b/core-java-modules/pom.xml new file mode 100644 index 0000000000..ed6a056448 --- /dev/null +++ b/core-java-modules/pom.xml @@ -0,0 +1,20 @@ + + + 4.0.0 + com.baeldung.core-java-modules + core-java-modules + core-java-modules + pom + + + parent-modules + com.baeldung + 1.0.0-SNAPSHOT + + + + pre-jpms + + + diff --git a/core-java-modules/pre-jpms/pom.xml b/core-java-modules/pre-jpms/pom.xml new file mode 100644 index 0000000000..169cd21f3e --- /dev/null +++ b/core-java-modules/pre-jpms/pom.xml @@ -0,0 +1,74 @@ + + 4.0.0 + pre-jpms + 0.0.1-SNAPSHOT + jar + pre-jpms + + + parent-modules + com.baeldung + 1.0.0-SNAPSHOT + ../../ + + + + + org.slf4j + slf4j-api + 1.7.25 + + + + pre-jpms + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-dependency-plugin + 3.1.1 + + + copy-dependencies + package + + copy-dependencies + + + + ${project.build.directory}/dependency-jars/ + + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + + com.baeldung.prejpms.App + true + dependency-jars/ + + + + + + + + + UTF-8 + + diff --git a/core-java-modules/pre-jpms/src/main/java/com/baeldung/prejpms/App.java b/core-java-modules/pre-jpms/src/main/java/com/baeldung/prejpms/App.java new file mode 100644 index 0000000000..1afaae30e4 --- /dev/null +++ b/core-java-modules/pre-jpms/src/main/java/com/baeldung/prejpms/App.java @@ -0,0 +1,77 @@ +package com.baeldung.prejpms; + +import java.io.StringWriter; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Marshaller; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.sun.crypto.provider.SunJCE; + +import sun.misc.BASE64Encoder; +import sun.reflect.Reflection; + +public class App { + + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + + public static void main(String[] args) throws Exception { + + getCrytpographyProviderName(); + getCallStackClassNames(); + getXmlFromObject(new Book(100, "Java Modules Architecture")); + getBase64EncodedString("Java"); + } + + private static void getCrytpographyProviderName() { + try { + LOGGER.info("1. JCE Provider Name: {}\n", new SunJCE().getName()); + } catch (Throwable e) { + LOGGER.error(e.toString()); + } + } + + private static void getCallStackClassNames() { + try { + StringBuffer sbStack = new StringBuffer(); + int i = 0; + Class caller = Reflection.getCallerClass(i++); + do { + sbStack.append(i + ".") + .append(caller.getName()) + .append("\n"); + caller = Reflection.getCallerClass(i++); + } while (caller != null); + LOGGER.info("2. Call Stack:\n{}", sbStack); + } catch (Throwable e) { + LOGGER.error(e.toString()); + } + } + + private static void getXmlFromObject(Book book) { + try { + Marshaller marshallerObj = JAXBContext.newInstance(Book.class) + .createMarshaller(); + marshallerObj.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); + + StringWriter sw = new StringWriter(); + marshallerObj.marshal(book, sw); + LOGGER.info("3. Xml for Book object:\n{}", sw); + } catch (Throwable e) { + LOGGER.error(e.toString()); + } + + } + + private static void getBase64EncodedString(String inputString) { + try { + String encodedString = new BASE64Encoder().encode(inputString.getBytes()); + LOGGER.info("4. Base Encoded String: {}", encodedString); + } catch (Throwable e) { + LOGGER.error(e.toString()); + } + } +} diff --git a/core-java-modules/pre-jpms/src/main/java/com/baeldung/prejpms/Book.java b/core-java-modules/pre-jpms/src/main/java/com/baeldung/prejpms/Book.java new file mode 100644 index 0000000000..6780c73738 --- /dev/null +++ b/core-java-modules/pre-jpms/src/main/java/com/baeldung/prejpms/Book.java @@ -0,0 +1,37 @@ +package com.baeldung.prejpms; + +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement(name = "book") +public class Book { + private long id; + private String name; + + public Book() { + } + + public Book(long id, String name) { + this.id = id; + this.name = name; + } + + @XmlAttribute + public void setId(Long id) { + this.id = id; + } + + @XmlElement(name = "title") + public void setName(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public Long getId() { + return id; + } +} diff --git a/core-java-modules/pre-jpms/src/main/resources/logback.xml b/core-java-modules/pre-jpms/src/main/resources/logback.xml new file mode 100644 index 0000000000..7c5914e58e --- /dev/null +++ b/core-java-modules/pre-jpms/src/main/resources/logback.xml @@ -0,0 +1,10 @@ + + + + [%level] %msg%n + + + + + + \ No newline at end of file diff --git a/core-java-networking/README.md b/core-java-networking/README.md index e76f28030d..2341520df7 100644 --- a/core-java-networking/README.md +++ b/core-java-networking/README.md @@ -14,4 +14,5 @@ - [A Guide to Java Sockets](http://www.baeldung.com/a-guide-to-java-sockets) - [Guide to Java URL Encoding/Decoding](http://www.baeldung.com/java-url-encoding-decoding) - [Do a Simple HTTP Request in Java](http://www.baeldung.com/java-http-request) -- [Difference between URL and URI](http://www.baeldung.com/java-url-vs-uri) \ No newline at end of file +- [Difference between URL and URI](http://www.baeldung.com/java-url-vs-uri) +- [Read an InputStream using the Java Server Socket](https://www.baeldung.com/java-inputstream-server-socket) diff --git a/core-java-networking/src/main/java/com/baeldung/networking/cookies/ProxyAcceptCookiePolicy.java b/core-java-networking/src/main/java/com/baeldung/networking/cookies/ProxyAcceptCookiePolicy.java index 0b5f6d7714..9fbbee8501 100644 --- a/core-java-networking/src/main/java/com/baeldung/networking/cookies/ProxyAcceptCookiePolicy.java +++ b/core-java-networking/src/main/java/com/baeldung/networking/cookies/ProxyAcceptCookiePolicy.java @@ -17,8 +17,8 @@ public class ProxyAcceptCookiePolicy implements CookiePolicy { host = uri.getHost(); } - if (!HttpCookie.domainMatches(acceptedProxy, host)) { - return false; + if (HttpCookie.domainMatches(acceptedProxy, host)) { + return true; } return CookiePolicy.ACCEPT_ORIGINAL_SERVER.shouldAccept(uri, cookie); diff --git a/core-java-networking/src/main/java/com/baeldung/socket/read/Client.java b/core-java-networking/src/main/java/com/baeldung/socket/read/Client.java new file mode 100644 index 0000000000..5e2a84a767 --- /dev/null +++ b/core-java-networking/src/main/java/com/baeldung/socket/read/Client.java @@ -0,0 +1,29 @@ +package com.baeldung.socket.read; + +import java.net.*; +import java.nio.charset.StandardCharsets; +import java.io.*; + +public class Client { + + public void runClient(String ip, int port) { + try { + Socket socket = new Socket(ip, port); + System.out.println("Connected to server ..."); + DataInputStream in = new DataInputStream(System.in); + DataOutputStream out = new DataOutputStream(socket.getOutputStream()); + + char type = 's'; // s for string + int length = 29; + String data = "This is a string of length 29"; + byte[] dataInBytes = data.getBytes(StandardCharsets.UTF_8); + //Sending data in TLV format + out.writeChar(type); + out.writeInt(length); + out.write(dataInBytes); + } catch (IOException e) { + e.printStackTrace(); + } + } + +} \ No newline at end of file diff --git a/core-java-networking/src/main/java/com/baeldung/socket/read/Server.java b/core-java-networking/src/main/java/com/baeldung/socket/read/Server.java new file mode 100644 index 0000000000..2ab91c6cdc --- /dev/null +++ b/core-java-networking/src/main/java/com/baeldung/socket/read/Server.java @@ -0,0 +1,49 @@ +package com.baeldung.socket.read; + +import java.net.*; +import java.nio.charset.StandardCharsets; +import java.io.*; + +public class Server { + + public void runServer(int port) { + //Start the server and wait for connection + try { + ServerSocket server = new ServerSocket(port); + System.out.println("Server Started. Waiting for connection ..."); + Socket socket = server.accept(); + System.out.println("Got connection from client."); + //Get input stream from socket variable and convert the same to DataInputStream + DataInputStream in = new DataInputStream(new BufferedInputStream(socket.getInputStream())); + //Read type and length of data + char dataType = in.readChar(); + int length = in.readInt(); + System.out.println("Type : "+dataType); + System.out.println("Lenght :"+length); + if(dataType == 's') { + //Read String data in bytes + byte[] messageByte = new byte[length]; + boolean end = false; + StringBuilder dataString = new StringBuilder(length); + int totalBytesRead = 0; + //We need to run while loop, to read all data in that stream + while(!end) { + int currentBytesRead = in.read(messageByte); + totalBytesRead = currentBytesRead + totalBytesRead; + if(totalBytesRead <= length) { + dataString.append(new String(messageByte,0,currentBytesRead,StandardCharsets.UTF_8)); + } else { + dataString.append(new String(messageByte,0,length - totalBytesRead + currentBytesRead,StandardCharsets.UTF_8)); + } + if(dataString.length()>=length) { + end = true; + } + } + System.out.println("Read "+length+" bytes of message from client. Message = "+dataString); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + +} \ No newline at end of file diff --git a/core-java-networking/src/test/java/com/baeldung/socket/read/SocketReadAllDataLiveTest.java b/core-java-networking/src/test/java/com/baeldung/socket/read/SocketReadAllDataLiveTest.java new file mode 100644 index 0000000000..da7f5b8d3f --- /dev/null +++ b/core-java-networking/src/test/java/com/baeldung/socket/read/SocketReadAllDataLiveTest.java @@ -0,0 +1,37 @@ +package com.baeldung.socket.read; + +import java.util.concurrent.TimeUnit; +import org.junit.jupiter.api.Test; + +public class SocketReadAllDataLiveTest { + + @Test + public void givenServerAndClient_whenClientSendsAndServerReceivesData_thenCorrect() { + //Run server in new thread + Runnable runnable1 = () -> { runServer(); }; + Thread thread1 = new Thread(runnable1); + thread1.start(); + //Wait for 10 seconds + try { + TimeUnit.SECONDS.sleep(10); + } catch (InterruptedException e) { + e.printStackTrace(); + } + //Run client in a new thread + Runnable runnable2 = () -> { runClient(); }; + Thread thread2 = new Thread(runnable2); + thread2.start(); + } + + public static void runServer() { + //Run Server + Server server = new Server(); + server.runServer(5555); + } + + public static void runClient() { + //Run Client + Client client = new Client(); + client.runClient("127.0.0.1", 5555); + } +} \ No newline at end of file diff --git a/core-java-os/.gitignore b/core-java-os/.gitignore new file mode 100644 index 0000000000..3de4cc647e --- /dev/null +++ b/core-java-os/.gitignore @@ -0,0 +1,26 @@ +*.class + +0.* + +#folders# +/target +/neoDb* +/data +/src/main/webapp/WEB-INF/classes +*/META-INF/* +.resourceCache + +# Packaged files # +*.jar +*.war +*.ear + +# Files generated by integration tests +*.txt +backup-pom.xml +/bin/ +/temp + +#IntelliJ specific +.idea/ +*.iml \ No newline at end of file diff --git a/core-java-os/README.md b/core-java-os/README.md new file mode 100644 index 0000000000..5f5d373d9b --- /dev/null +++ b/core-java-os/README.md @@ -0,0 +1,10 @@ +========= + +This module uses Java 9, so make sure to have the JDK 9 installed to run it. + +## +### Relevant Articles: +- [Java 9 Process API Improvements](http://www.baeldung.com/java-9-process-api) +- [Guide to java.lang.Process API](https://www.baeldung.com/java-process-api) +- [Guide to java.lang.ProcessBuilder API](https://www.baeldung.com/java-lang-processbuilder-api) + diff --git a/core-java-os/pom.xml b/core-java-os/pom.xml new file mode 100644 index 0000000000..c9097cb554 --- /dev/null +++ b/core-java-os/pom.xml @@ -0,0 +1,82 @@ + + 4.0.0 + com.baeldung + core-java-os + 0.1.0-SNAPSHOT + core-java-os + jar + + + com.baeldung + parent-java + 0.0.1-SNAPSHOT + ../parent-java + + + + + org.apache.commons + commons-collections4 + ${commons-collections4.version} + + + commons-io + commons-io + ${commons-io.version} + + + org.apache.commons + commons-lang3 + ${commons-lang3.version} + + + log4j + log4j + ${log4j.version} + + + + org.assertj + assertj-core + ${assertj.version} + test + + + + + core-java-os + + + src/main/resources + true + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + ${maven.compiler.source} + ${maven.compiler.target} + + + + + + + + 3.5 + 4.1 + 4.01 + + + 3.6.1 + 1.8.9 + 1.9 + 1.9 + 25.1-jre + + diff --git a/core-java-9/src/main/java/com/baeldung/java9/process/ChildProcess.java b/core-java-os/src/main/java/com/baeldung/java9/process/ChildProcess.java similarity index 100% rename from core-java-9/src/main/java/com/baeldung/java9/process/ChildProcess.java rename to core-java-os/src/main/java/com/baeldung/java9/process/ChildProcess.java diff --git a/core-java-9/src/main/java/com/baeldung/java9/process/OutputStreamExample.java b/core-java-os/src/main/java/com/baeldung/java9/process/OutputStreamExample.java similarity index 100% rename from core-java-9/src/main/java/com/baeldung/java9/process/OutputStreamExample.java rename to core-java-os/src/main/java/com/baeldung/java9/process/OutputStreamExample.java diff --git a/core-java-9/src/main/java/com/baeldung/java9/process/ProcessCompilationError.java b/core-java-os/src/main/java/com/baeldung/java9/process/ProcessCompilationError.java similarity index 87% rename from core-java-9/src/main/java/com/baeldung/java9/process/ProcessCompilationError.java rename to core-java-os/src/main/java/com/baeldung/java9/process/ProcessCompilationError.java index 8b6ae0b441..73eacddc4c 100644 --- a/core-java-9/src/main/java/com/baeldung/java9/process/ProcessCompilationError.java +++ b/core-java-os/src/main/java/com/baeldung/java9/process/ProcessCompilationError.java @@ -3,5 +3,5 @@ package com.baeldung.java9.process; public class ProcessCompilationError { //This method has been written to generate error to display //how process errorStream() can consume error - public static void(); + //public static void(); } diff --git a/core-java-9/src/main/java/com/baeldung/java9/process/ProcessUnderstanding.java b/core-java-os/src/main/java/com/baeldung/java9/process/ProcessUnderstanding.java similarity index 100% rename from core-java-9/src/main/java/com/baeldung/java9/process/ProcessUnderstanding.java rename to core-java-os/src/main/java/com/baeldung/java9/process/ProcessUnderstanding.java diff --git a/core-java-9/src/main/java/com/baeldung/java9/process/ProcessUtils.java b/core-java-os/src/main/java/com/baeldung/java9/process/ProcessUtils.java similarity index 100% rename from core-java-9/src/main/java/com/baeldung/java9/process/ProcessUtils.java rename to core-java-os/src/main/java/com/baeldung/java9/process/ProcessUtils.java diff --git a/core-java-9/src/main/java/com/baeldung/java9/process/ServiceMain.java b/core-java-os/src/main/java/com/baeldung/java9/process/ServiceMain.java similarity index 100% rename from core-java-9/src/main/java/com/baeldung/java9/process/ServiceMain.java rename to core-java-os/src/main/java/com/baeldung/java9/process/ServiceMain.java diff --git a/core-java-os/src/main/resources/logback.xml b/core-java-os/src/main/resources/logback.xml new file mode 100644 index 0000000000..7d900d8ea8 --- /dev/null +++ b/core-java-os/src/main/resources/logback.xml @@ -0,0 +1,13 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + \ No newline at end of file diff --git a/core-java-9/src/test/java/com/baeldung/java9/process/ProcessAPIEnhancementsUnitTest.java b/core-java-os/src/test/java/com/baeldung/java9/process/ProcessAPIEnhancementsUnitTest.java similarity index 89% rename from core-java-9/src/test/java/com/baeldung/java9/process/ProcessAPIEnhancementsUnitTest.java rename to core-java-os/src/test/java/com/baeldung/java9/process/ProcessAPIEnhancementsUnitTest.java index 9a227a9c8f..8cefceef1d 100644 --- a/core-java-9/src/test/java/com/baeldung/java9/process/ProcessAPIEnhancementsUnitTest.java +++ b/core-java-os/src/test/java/com/baeldung/java9/process/ProcessAPIEnhancementsUnitTest.java @@ -18,13 +18,13 @@ import org.slf4j.LoggerFactory; public class ProcessAPIEnhancementsUnitTest { - Logger log = LoggerFactory.getLogger(ProcessAPIEnhancementsTest.class); + Logger log = LoggerFactory.getLogger(ProcessAPIEnhancementsUnitTest.class); @Test public void givenCurrentProcess_whenInvokeGetInfo_thenSuccess() throws IOException { ProcessHandle processHandle = ProcessHandle.current(); ProcessHandle.Info processInfo = processHandle.info(); - assertNotNull(processHandle.getPid()); + assertNotNull(processHandle.pid()); assertEquals(false, processInfo.arguments() .isPresent()); assertEquals(true, processInfo.command() @@ -51,7 +51,7 @@ public class ProcessAPIEnhancementsUnitTest { .start(); ProcessHandle processHandle = process.toHandle(); ProcessHandle.Info processInfo = processHandle.info(); - assertNotNull(processHandle.getPid()); + assertNotNull(processHandle.pid()); assertEquals(false, processInfo.arguments() .isPresent()); assertEquals(true, processInfo.command() @@ -72,7 +72,7 @@ public class ProcessAPIEnhancementsUnitTest { Stream liveProcesses = ProcessHandle.allProcesses(); liveProcesses.filter(ProcessHandle::isAlive) .forEach(ph -> { - assertNotNull(ph.getPid()); + assertNotNull(ph.pid()); assertEquals(true, ph.info() .command() .isPresent()); @@ -102,12 +102,12 @@ public class ProcessAPIEnhancementsUnitTest { Stream children = ProcessHandle.current() .children(); children.filter(ProcessHandle::isAlive) - .forEach(ph -> log.info("PID: {}, Cmd: {}", ph.getPid(), ph.info() + .forEach(ph -> log.info("PID: {}, Cmd: {}", ph.pid(), ph.info() .command())); Stream descendants = ProcessHandle.current() .descendants(); descendants.filter(ProcessHandle::isAlive) - .forEach(ph -> log.info("PID: {}, Cmd: {}", ph.getPid(), ph.info() + .forEach(ph -> log.info("PID: {}, Cmd: {}", ph.pid(), ph.info() .command())); } @@ -121,12 +121,12 @@ public class ProcessAPIEnhancementsUnitTest { .start(); ProcessHandle processHandle = process.toHandle(); - log.info("PID: {} has started", processHandle.getPid()); + log.info("PID: {} has started", processHandle.pid()); CompletableFuture onProcessExit = processHandle.onExit(); onProcessExit.get(); assertEquals(false, processHandle.isAlive()); onProcessExit.thenAccept(ph -> { - log.info("PID: {} has stopped", ph.getPid()); + log.info("PID: {} has stopped", ph.pid()); }); } diff --git a/core-java-9/src/test/java/com/baeldung/java9/process/ProcessApiUnitTest.java b/core-java-os/src/test/java/com/baeldung/java9/process/ProcessApiUnitTest.java similarity index 85% rename from core-java-9/src/test/java/com/baeldung/java9/process/ProcessApiUnitTest.java rename to core-java-os/src/test/java/com/baeldung/java9/process/ProcessApiUnitTest.java index e125f10da7..8bdf8cb09f 100644 --- a/core-java-9/src/test/java/com/baeldung/java9/process/ProcessApiUnitTest.java +++ b/core-java-os/src/test/java/com/baeldung/java9/process/ProcessApiUnitTest.java @@ -30,7 +30,7 @@ public class ProcessApiUnitTest { @Test public void processInfoExample() throws NoSuchAlgorithmException { ProcessHandle self = ProcessHandle.current(); - long PID = self.getPid(); + long PID = self.pid(); ProcessHandle.Info procInfo = self.info(); Optional args = procInfo.arguments(); Optional cmd = procInfo.commandLine(); @@ -45,7 +45,7 @@ public class ProcessApiUnitTest { Stream allProc = ProcessHandle.current().children(); allProc.forEach(p -> { - System.out.println("Proc " + p.getPid()); + System.out.println("Proc " + p.pid()); }); } @@ -54,7 +54,7 @@ public class ProcessApiUnitTest { public void createAndDestroyProcess() throws IOException, InterruptedException { int numberOfChildProcesses = 5; for (int i = 0; i < numberOfChildProcesses; i++) { - createNewJVM(ServiceMain.class, i).getPid(); + createNewJVM(ServiceMain.class, i).pid(); } Stream childProc = ProcessHandle.current().children(); @@ -62,10 +62,10 @@ public class ProcessApiUnitTest { childProc = ProcessHandle.current().children(); childProc.forEach(processHandle -> { - assertTrue("Process " + processHandle.getPid() + " should be alive!", processHandle.isAlive()); + assertTrue("Process " + processHandle.pid() + " should be alive!", processHandle.isAlive()); CompletableFuture onProcExit = processHandle.onExit(); onProcExit.thenAccept(procHandle -> { - System.out.println("Process with PID " + procHandle.getPid() + " has stopped"); + System.out.println("Process with PID " + procHandle.pid() + " has stopped"); }); }); @@ -73,14 +73,14 @@ public class ProcessApiUnitTest { childProc = ProcessHandle.current().children(); childProc.forEach(procHandle -> { - assertTrue("Could not kill process " + procHandle.getPid(), procHandle.destroy()); + assertTrue("Could not kill process " + procHandle.pid(), procHandle.destroy()); }); Thread.sleep(5000); childProc = ProcessHandle.current().children(); childProc.forEach(procHandle -> { - assertFalse("Process " + procHandle.getPid() + " should not be alive!", procHandle.isAlive()); + assertFalse("Process " + procHandle.pid() + " should not be alive!", procHandle.isAlive()); }); } diff --git a/core-java-9/src/test/java/com/baeldung/java9/process/ProcessUnderstandingTest.java b/core-java-os/src/test/java/com/baeldung/java9/process/ProcessUnderstandingUnitTest.java similarity index 99% rename from core-java-9/src/test/java/com/baeldung/java9/process/ProcessUnderstandingTest.java rename to core-java-os/src/test/java/com/baeldung/java9/process/ProcessUnderstandingUnitTest.java index 2c5525b9ed..6ad07c5c3a 100644 --- a/core-java-9/src/test/java/com/baeldung/java9/process/ProcessUnderstandingTest.java +++ b/core-java-os/src/test/java/com/baeldung/java9/process/ProcessUnderstandingUnitTest.java @@ -14,7 +14,7 @@ import java.lang.Integer; import org.junit.jupiter.api.Test; -class ProcessUnderstandingTest { +class ProcessUnderstandingUnitTest { @Test public void givenSourceProgram_whenExecutedFromAnotherProgram_thenSourceProgramOutput3() throws IOException { diff --git a/core-java-9/src/test/java/com/baeldung/processbuilder/ProcessBuilderUnitTest.java b/core-java-os/src/test/java/com/baeldung/processbuilder/ProcessBuilderUnitTest.java similarity index 100% rename from core-java-9/src/test/java/com/baeldung/processbuilder/ProcessBuilderUnitTest.java rename to core-java-os/src/test/java/com/baeldung/processbuilder/ProcessBuilderUnitTest.java diff --git a/core-java-os/src/test/resources/.gitignore b/core-java-os/src/test/resources/.gitignore new file mode 100644 index 0000000000..83c05e60c8 --- /dev/null +++ b/core-java-os/src/test/resources/.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/core-java/README.md b/core-java/README.md index 67538a3895..c2d1b4a06b 100644 --- a/core-java/README.md +++ b/core-java/README.md @@ -29,8 +29,7 @@ - [What is the serialVersionUID?](http://www.baeldung.com/java-serial-version-uid) - [A Guide to the ResourceBundle](http://www.baeldung.com/java-resourcebundle) - [Class Loaders in Java](http://www.baeldung.com/java-classloaders) -- [Double-Checked Locking with Singleton](http://www.baeldung.com/java-singleton-double-checked-locking) -- [Guide to Java Clock Class](http://www.baeldung.com/java-clock) +- [Guide to the Java Clock Class](http://www.baeldung.com/java-clock) - [Importance of Main Manifest Attribute in a Self-Executing JAR](http://www.baeldung.com/java-jar-executable-manifest-main-class) - [Java Global Exception Handler](http://www.baeldung.com/java-global-exception-handler) - [How to Get the Size of an Object in Java](http://www.baeldung.com/java-size-of-object) @@ -51,3 +50,4 @@ - [Finding Leap Years in Java](https://www.baeldung.com/java-leap-year) - [Java Bitwise Operators](https://www.baeldung.com/java-bitwise-operators) - [Guide to Creating and Running a Jar File in Java](https://www.baeldung.com/java-create-jar) +- [Making a JSON POST Request With HttpURLConnection](https://www.baeldung.com/httpurlconnection-post) diff --git a/core-java/src/main/java/com/baeldung/graph/Graph.java b/core-java/src/main/java/com/baeldung/graph/Graph.java index 43b5c0aa08..3f2e17c43c 100644 --- a/core-java/src/main/java/com/baeldung/graph/Graph.java +++ b/core-java/src/main/java/com/baeldung/graph/Graph.java @@ -59,18 +59,43 @@ public class Graph { Vertex(String label) { this.label = label; } - @Override - public boolean equals(Object obj) { - Vertex vertex = (Vertex) obj; - return vertex.label == label; - } + @Override public int hashCode() { - return label.hashCode(); + final int prime = 31; + int result = 1; + result = prime * result + getOuterType().hashCode(); + result = prime * result + ((label == null) ? 0 : label.hashCode()); + return result; } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Vertex other = (Vertex) obj; + if (!getOuterType().equals(other.getOuterType())) + return false; + if (label == null) { + if (other.label != null) + return false; + } else if (!label.equals(other.label)) + return false; + return true; + } + @Override public String toString() { return label; } + + + private Graph getOuterType() { + return Graph.this; + } } } \ No newline at end of file diff --git a/core-kotlin-2/README.md b/core-kotlin-2/README.md index 8d22c4f1a8..6d0b20135d 100644 --- a/core-kotlin-2/README.md +++ b/core-kotlin-2/README.md @@ -2,3 +2,8 @@ - [Void Type in Kotlin](https://www.baeldung.com/kotlin-void-type) - [How to use Kotlin Range Expressions](https://www.baeldung.com/kotlin-ranges) +- [Creating a Kotlin Range Iterator on a Custom Object](https://www.baeldung.com/kotlin-custom-range-iterator) +- [Kotlin Scope Functions](https://www.baeldung.com/kotlin-scope-functions) +- [Kotlin Annotations](https://www.baeldung.com/kotlin-annotations) +- [Split a List into Parts in Kotlin](https://www.baeldung.com/kotlin-split-list-into-parts) +- [String Comparison in Kotlin](https://www.baeldung.com/kotlin-string-comparison) \ No newline at end of file diff --git a/core-kotlin-2/build.gradle b/core-kotlin-2/build.gradle index b058e0ecad..1c52172404 100644 --- a/core-kotlin-2/build.gradle +++ b/core-kotlin-2/build.gradle @@ -5,7 +5,7 @@ version '1.0-SNAPSHOT' buildscript { - ext.kotlin_version = '1.2.41' + ext.kotlin_version = '1.3.30' repositories { mavenCentral() @@ -26,8 +26,6 @@ sourceCompatibility = 1.8 compileKotlin { kotlinOptions.jvmTarget = "1.8" } compileTestKotlin { kotlinOptions.jvmTarget = "1.8" } -kotlin { experimental { coroutines "enable" } } - repositories { mavenCentral() jcenter() @@ -39,10 +37,22 @@ sourceSets { srcDirs 'com/baeldung/ktor' } } +} +test { + useJUnitPlatform() + testLogging { + events "passed", "skipped", "failed" + } } dependencies { - compile "ch.qos.logback:logback-classic:1.2.1" - testCompile group: 'junit', name: 'junit', version: '4.12' -} \ No newline at end of file + implementation "ch.qos.logback:logback-classic:1.2.1" + implementation "org.jetbrains.kotlin:kotlin-stdlib:${kotlin_version}" + testImplementation 'org.junit.jupiter:junit-jupiter:5.4.2' + testImplementation 'junit:junit:4.12' + testImplementation 'org.assertj:assertj-core:3.12.2' + testImplementation 'org.mockito:mockito-core:2.27.0' + testImplementation "org.jetbrains.kotlin:kotlin-test:${kotlin_version}" + testImplementation "org.jetbrains.kotlin:kotlin-test-junit5:${kotlin_version}" +} diff --git a/core-kotlin-2/gradle/wrapper/gradle-wrapper.jar b/core-kotlin-2/gradle/wrapper/gradle-wrapper.jar index 01b8bf6b1f..5c2d1cf016 100644 Binary files a/core-kotlin-2/gradle/wrapper/gradle-wrapper.jar and b/core-kotlin-2/gradle/wrapper/gradle-wrapper.jar differ diff --git a/core-kotlin-2/gradle/wrapper/gradle-wrapper.properties b/core-kotlin-2/gradle/wrapper/gradle-wrapper.properties index 933b6473ce..5f1b1201a7 100644 --- a/core-kotlin-2/gradle/wrapper/gradle-wrapper.properties +++ b/core-kotlin-2/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.4-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-bin.zip diff --git a/core-kotlin-2/gradlew b/core-kotlin-2/gradlew index cccdd3d517..b0d6d0ab5d 100644 --- a/core-kotlin-2/gradlew +++ b/core-kotlin-2/gradlew @@ -1,5 +1,21 @@ #!/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 +# +# http://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 @@ -28,7 +44,7 @@ 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="" +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" diff --git a/core-kotlin-2/gradlew.bat b/core-kotlin-2/gradlew.bat index f9553162f1..9991c50326 100644 --- a/core-kotlin-2/gradlew.bat +++ b/core-kotlin-2/gradlew.bat @@ -1,3 +1,19 @@ +@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 http://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 @@ -14,7 +30,7 @@ set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @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= +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome diff --git a/core-kotlin-2/pom.xml b/core-kotlin-2/pom.xml index 81df3cee81..be2f5fa68f 100644 --- a/core-kotlin-2/pom.xml +++ b/core-kotlin-2/pom.xml @@ -13,4 +13,85 @@ ../parent-kotlin + + + org.jetbrains.kotlin + kotlin-stdlib-jdk8 + ${kotlin.version} + + + org.junit.jupiter + junit-jupiter + ${junit.jupiter.version} + test + + + org.mockito + mockito-core + ${mockito.version} + test + + + net.bytebuddy + byte-buddy + ${byte-buddy.version} + test + + + org.assertj + assertj-core + ${assertj.version} + test + + + org.jetbrains.kotlin + kotlin-test + ${kotlin.version} + test + + + org.jetbrains.kotlin + kotlin-test-junit5 + ${kotlin.version} + test + + + + + + + org.jetbrains.kotlin + kotlin-maven-plugin + ${kotlin.version} + + + compile + compile + + compile + + + + test-compile + test-compile + + test-compile + + + + + 1.8 + + + + + + + 1.3.30 + 5.4.2 + 2.27.0 + 1.9.12 + 3.10.0 + + diff --git a/core-kotlin-2/src/main/kotlin/com/baeldung/annotations/Annotations.kt b/core-kotlin-2/src/main/kotlin/com/baeldung/annotations/Annotations.kt new file mode 100644 index 0000000000..a8f83446dc --- /dev/null +++ b/core-kotlin-2/src/main/kotlin/com/baeldung/annotations/Annotations.kt @@ -0,0 +1,7 @@ +package com.baeldung.annotations + +@Target(AnnotationTarget.FIELD) +annotation class Positive + +@Target(AnnotationTarget.FIELD) +annotation class AllowedNames(val names: Array) diff --git a/core-kotlin-2/src/main/kotlin/com/baeldung/annotations/Item.kt b/core-kotlin-2/src/main/kotlin/com/baeldung/annotations/Item.kt new file mode 100644 index 0000000000..6864fe416e --- /dev/null +++ b/core-kotlin-2/src/main/kotlin/com/baeldung/annotations/Item.kt @@ -0,0 +1,3 @@ +package com.baeldung.annotations + +class Item(@Positive val amount: Float, @AllowedNames(["Alice", "Bob"]) val name: String) \ No newline at end of file diff --git a/core-kotlin-2/src/main/kotlin/com/baeldung/annotations/Main.kt b/core-kotlin-2/src/main/kotlin/com/baeldung/annotations/Main.kt new file mode 100644 index 0000000000..2b7f2c5590 --- /dev/null +++ b/core-kotlin-2/src/main/kotlin/com/baeldung/annotations/Main.kt @@ -0,0 +1,7 @@ +package com.baeldung.annotations + +fun main(args: Array) { + val item = Item(amount = 1.0f, name = "Bob") + val validator = Validator() + println("Is instance valid? ${validator.isValid(item)}") +} diff --git a/core-kotlin-2/src/main/kotlin/com/baeldung/annotations/Validator.kt b/core-kotlin-2/src/main/kotlin/com/baeldung/annotations/Validator.kt new file mode 100644 index 0000000000..40139048ab --- /dev/null +++ b/core-kotlin-2/src/main/kotlin/com/baeldung/annotations/Validator.kt @@ -0,0 +1,38 @@ +package com.baeldung.annotations + +/** + * Naive annotation-based validator. + * @author A.Shcherbakov + */ +class Validator() { + + /** + * Return true if every item's property annotated with @Positive is positive and if + * every item's property annotated with @AllowedNames has a value specified in that annotation. + */ + fun isValid(item: Item): Boolean { + val fields = item::class.java.declaredFields + for (field in fields) { + field.isAccessible = true + for (annotation in field.annotations) { + val value = field.get(item) + if (field.isAnnotationPresent(Positive::class.java)) { + val amount = value as Float + if (amount < 0) { + return false + } + } + if (field.isAnnotationPresent(AllowedNames::class.java)) { + val allowedNames = field.getAnnotation(AllowedNames::class.java)?.names + val name = value as String + allowedNames?.let { + if (!it.contains(name)) { + return false + } + } + } + } + } + return true + } +} \ No newline at end of file diff --git a/core-kotlin-2/src/main/kotlin/com/baeldung/jvmannotations/Document.kt b/core-kotlin-2/src/main/kotlin/com/baeldung/jvmannotations/Document.kt new file mode 100644 index 0000000000..3f9922b88b --- /dev/null +++ b/core-kotlin-2/src/main/kotlin/com/baeldung/jvmannotations/Document.kt @@ -0,0 +1,31 @@ +package com.baeldung.jvmannotations + +import java.util.* + +interface Document { + + @JvmDefault + fun getType() = "document" +} + +class TextDocument : Document { + override fun getType() = "text" + + fun transformList(list : List) : List { + return list.filter { n -> n.toInt() > 1 } + } + + fun transformListInverseWildcards(list : List<@JvmSuppressWildcards Number>) : List<@JvmWildcard Number> { + return list.filter { n -> n.toInt() > 1 } + } + + var list : List<@JvmWildcard Any> = ArrayList() +} + +class XmlDocument(d : Document) : Document by d + +fun main() { + val myDocument = TextDocument() + val myTextDocument = XmlDocument(myDocument) + println("${myDocument.getType()} ${myTextDocument.getType()}") +} diff --git a/core-kotlin-2/src/main/kotlin/com/baeldung/jvmannotations/HtmlDocument.java b/core-kotlin-2/src/main/kotlin/com/baeldung/jvmannotations/HtmlDocument.java new file mode 100644 index 0000000000..feb71772cb --- /dev/null +++ b/core-kotlin-2/src/main/kotlin/com/baeldung/jvmannotations/HtmlDocument.java @@ -0,0 +1,9 @@ +package com.baeldung.jvmannotations; + +public class HtmlDocument implements Document { + + @Override + public String getType() { + return "HTML"; + } +} \ No newline at end of file diff --git a/core-kotlin-2/src/main/kotlin/com/baeldung/jvmannotations/Message.kt b/core-kotlin-2/src/main/kotlin/com/baeldung/jvmannotations/Message.kt new file mode 100644 index 0000000000..80180bd924 --- /dev/null +++ b/core-kotlin-2/src/main/kotlin/com/baeldung/jvmannotations/Message.kt @@ -0,0 +1,66 @@ +@file:JvmName("MessageHelper") +@file:JvmMultifileClass //used +package com.baeldung.jvmannotations + +import java.util.* + +@JvmName("getMyUsername") +fun getMyName() : String { + return "myUserId" +} + +object MessageBroker { + @JvmStatic + var totalMessagesSent = 0 + + const val maxMessageLength = 0 + + @JvmStatic + fun clearAllMessages() { + } + + @JvmStatic + @JvmOverloads + @Throws(Exception::class) + fun findMessages(sender : String, type : String = "text", maxResults : Int = 10) : List { + if(sender.isEmpty()) { + throw Exception() + } + return ArrayList() + } +} + +class Message { + + // this would cause a compilation error since sender is immutable + // @set:JvmName("setSender") + val sender = "myself" + + // this works as name is overridden + @JvmName("getSenderName") + fun getSender() : String = "from:$sender" + + @get:JvmName("getReceiverName") + @set:JvmName("setReceiverName") + var receiver : String = "" + + @get:JvmName("getContent") + @set:JvmName("setContent") + var text = "" + + // generates a warning + @get:JvmName("getId") + private val id = 0 + + @get:JvmName("hasAttachment") + var hasAttachment = true + + var isEncrypted = true + + fun setReceivers(receiverNames : List) { + } + + @JvmName("setReceiverIds") + fun setReceivers(receiverNames : List) { + } +} \ No newline at end of file diff --git a/core-kotlin-2/src/main/kotlin/com/baeldung/jvmannotations/MessageConverter.kt b/core-kotlin-2/src/main/kotlin/com/baeldung/jvmannotations/MessageConverter.kt new file mode 100644 index 0000000000..3b19b12e10 --- /dev/null +++ b/core-kotlin-2/src/main/kotlin/com/baeldung/jvmannotations/MessageConverter.kt @@ -0,0 +1,6 @@ +@file:JvmMultifileClass +@file:JvmName("MessageHelper") //applies to all top level functions / variables / constants +package com.baeldung.jvmannotations + +fun convert(message: Message) { +} diff --git a/core-kotlin-2/src/main/kotlin/com/baeldung/range/CharRange.kt b/core-kotlin-2/src/main/kotlin/com/baeldung/range/CharRange.kt new file mode 100644 index 0000000000..3151674d61 --- /dev/null +++ b/core-kotlin-2/src/main/kotlin/com/baeldung/range/CharRange.kt @@ -0,0 +1,13 @@ +package com.baeldung.range + +fun main(args: Array) { + + for (ch in 'a'..'f') { + print(ch) + } + println() + + for (ch in 'f' downTo 'a') { + print(ch) + } +} \ No newline at end of file diff --git a/core-kotlin-2/src/main/kotlin/com/baeldung/range/Color.kt b/core-kotlin-2/src/main/kotlin/com/baeldung/range/Color.kt new file mode 100644 index 0000000000..ef7adf06b5 --- /dev/null +++ b/core-kotlin-2/src/main/kotlin/com/baeldung/range/Color.kt @@ -0,0 +1,21 @@ +package com.baeldung.range + +enum class Color(val rgb: Int) { + BLUE(0x0000FF), + GREEN(0x008000), + RED(0xFF0000), + MAGENTA(0xFF00FF), + YELLOW(0xFFFF00); +} + +fun main(args: Array) { + + println(Color.values().toList()); + val red = Color.RED + val yellow = Color.YELLOW + val range = red..yellow + + println(range.contains(Color.MAGENTA)) + println(range.contains(Color.BLUE)) + println(range.contains(Color.GREEN)) +} \ No newline at end of file diff --git a/core-kotlin-2/src/main/kotlin/com/baeldung/range/CustomColor.kt b/core-kotlin-2/src/main/kotlin/com/baeldung/range/CustomColor.kt new file mode 100644 index 0000000000..b4fed13b18 --- /dev/null +++ b/core-kotlin-2/src/main/kotlin/com/baeldung/range/CustomColor.kt @@ -0,0 +1,56 @@ +package com.baeldung.range + +import java.lang.IllegalStateException + +class CustomColor(val rgb: Int): Comparable { + + override fun compareTo(other: CustomColor): Int { + return this.rgb.compareTo(other.rgb) + } + + operator fun rangeTo(that: CustomColor) = ColorRange(this,that) + + operator fun inc(): CustomColor { + return CustomColor(rgb + 1) + } + + init { + if(rgb < 0x000000 || rgb > 0xFFFFFF){ + throw IllegalStateException("RGB must be between 0 and 16777215") + } + } + + override fun toString(): String { + return "CustomColor(rgb=$rgb)" + } +} +class ColorRange(override val start: CustomColor, + override val endInclusive: CustomColor) : ClosedRange, Iterable{ + + override fun iterator(): Iterator { + return ColorIterator(start, endInclusive) + } +} + +class ColorIterator(val start: CustomColor, val endInclusive: CustomColor) : Iterator { + + var initValue = start + + override fun hasNext(): Boolean { + return initValue <= endInclusive + } + + override fun next(): CustomColor { + return initValue++ + } +} + +fun main(args: Array) { + val a = CustomColor(0xABCDEF) + val b = CustomColor(-1) + val c = CustomColor(0xABCDFF) + + for(color in a..c){ + println(color) + } +} \ No newline at end of file diff --git a/core-kotlin-2/src/main/kotlin/com/baeldung/range/Filter.kt b/core-kotlin-2/src/main/kotlin/com/baeldung/range/Filter.kt new file mode 100644 index 0000000000..0e611b14cf --- /dev/null +++ b/core-kotlin-2/src/main/kotlin/com/baeldung/range/Filter.kt @@ -0,0 +1,18 @@ +package com.baeldung.range + +fun main(args: Array) { + val r = 1..10 + + //Apply filter + val f = r.filter { it -> it % 2 == 0 } + println(f) + + //Map + val m = r.map { it -> it * it } + println(m) + + //Reduce + val rdc = r.reduce { a, b -> a + b } + println(rdc) + +} \ No newline at end of file diff --git a/core-kotlin-2/src/main/kotlin/com/baeldung/range/FirstLast.kt b/core-kotlin-2/src/main/kotlin/com/baeldung/range/FirstLast.kt new file mode 100644 index 0000000000..b82f5a8b9b --- /dev/null +++ b/core-kotlin-2/src/main/kotlin/com/baeldung/range/FirstLast.kt @@ -0,0 +1,8 @@ +package com.baeldung.range + +fun main(args: Array) { + + println((1..9).first) + println((1..9 step 2).step) + println((3..9).reversed().last) +} \ No newline at end of file diff --git a/core-kotlin-2/src/main/kotlin/com/baeldung/range/OtherRangeFunctions.kt b/core-kotlin-2/src/main/kotlin/com/baeldung/range/OtherRangeFunctions.kt new file mode 100644 index 0000000000..19dcab89b2 --- /dev/null +++ b/core-kotlin-2/src/main/kotlin/com/baeldung/range/OtherRangeFunctions.kt @@ -0,0 +1,14 @@ +package com.baeldung.range + +fun main(args: Array) { + + val r = 1..20 + println(r.min()) + println(r.max()) + println(r.sum()) + println(r.average()) + println(r.count()) + + val repeated = listOf(1, 1, 2, 4, 4, 6, 10) + println(repeated.distinct()) +} \ No newline at end of file diff --git a/core-kotlin-2/src/main/kotlin/com/baeldung/range/Range.kt b/core-kotlin-2/src/main/kotlin/com/baeldung/range/Range.kt new file mode 100644 index 0000000000..c313181599 --- /dev/null +++ b/core-kotlin-2/src/main/kotlin/com/baeldung/range/Range.kt @@ -0,0 +1,28 @@ +package com.baeldung.range + +fun main(args: Array) { + + for (i in 1..9) { + print(i) + } + println() + + for (i in 9 downTo 1) { + print(i) + } + println() + + for (i in 1.rangeTo(9)) { + print(i) + } + println() + + for (i in 9.downTo(1)) { + print(i) + } + println() + + for (i in 1 until 9) { + print(i) + } +} diff --git a/core-kotlin-2/src/main/kotlin/com/baeldung/range/ReverseRange.kt b/core-kotlin-2/src/main/kotlin/com/baeldung/range/ReverseRange.kt new file mode 100644 index 0000000000..875cf62200 --- /dev/null +++ b/core-kotlin-2/src/main/kotlin/com/baeldung/range/ReverseRange.kt @@ -0,0 +1,14 @@ +package com.baeldung.range + +fun main(args: Array) { + + (1..9).reversed().forEach { + print(it) + } + + println() + + (1..9).reversed().step(3).forEach { + print(it) + } +} \ No newline at end of file diff --git a/core-kotlin-2/src/main/kotlin/com/baeldung/range/Step.kt b/core-kotlin-2/src/main/kotlin/com/baeldung/range/Step.kt new file mode 100644 index 0000000000..b9c5d48588 --- /dev/null +++ b/core-kotlin-2/src/main/kotlin/com/baeldung/range/Step.kt @@ -0,0 +1,15 @@ +package com.baeldung.range + +fun main(args: Array) { + + for(i in 1..9 step 2){ + print(i) + } + + println() + + for (i in 9 downTo 1 step 2){ + print(i) + } + +} \ No newline at end of file diff --git a/core-kotlin-2/src/main/kotlin/com/baeldung/range/UntilRange.kt b/core-kotlin-2/src/main/kotlin/com/baeldung/range/UntilRange.kt new file mode 100644 index 0000000000..2c116a286f --- /dev/null +++ b/core-kotlin-2/src/main/kotlin/com/baeldung/range/UntilRange.kt @@ -0,0 +1,8 @@ +package com.baeldung.range + +fun main(args: Array) { + + for (i in 1 until 9) { + print(i) + } +} \ No newline at end of file diff --git a/core-kotlin-2/src/main/kotlin/com/baeldung/scope/ScopeFunctions.kt b/core-kotlin-2/src/main/kotlin/com/baeldung/scope/ScopeFunctions.kt new file mode 100644 index 0000000000..37ad8c65e2 --- /dev/null +++ b/core-kotlin-2/src/main/kotlin/com/baeldung/scope/ScopeFunctions.kt @@ -0,0 +1,25 @@ +package com.baeldung.scope + +data class Student(var studentId: String = "", var name: String = "", var surname: String = "") { +} + +data class Teacher(var teacherId: Int = 0, var name: String = "", var surname: String = "") { + fun setId(anId: Int): Teacher = apply { teacherId = anId } + fun setName(aName: String): Teacher = apply { name = aName } + fun setSurname(aSurname: String): Teacher = apply { surname = aSurname } +} + +data class Headers(val headerInfo: String) + +data class Response(val headers: Headers) + +data class RestClient(val url: String) { + fun getResponse() = Response(Headers("some header info")) +} + +data class BankAccount(val id: Int) { + fun checkAuthorization(username: String) = Unit + fun addPayee(payee: String) = Unit + fun makePayment(paymentDetails: String) = Unit + +} \ No newline at end of file diff --git a/core-kotlin-2/src/test/kotlin/com/baeldung/annotations/ValidationTest.kt b/core-kotlin-2/src/test/kotlin/com/baeldung/annotations/ValidationTest.kt new file mode 100644 index 0000000000..5c2b6ef47f --- /dev/null +++ b/core-kotlin-2/src/test/kotlin/com/baeldung/annotations/ValidationTest.kt @@ -0,0 +1,41 @@ +package com.baeldung.annotations + +import org.junit.Test +import kotlin.test.assertTrue +import kotlin.test.assertFalse + +class ValidationTest { + + @Test + fun whenAmountIsOneAndNameIsAlice_thenTrue() { + assertTrue(Validator().isValid(Item(1f, "Alice"))) + } + + @Test + fun whenAmountIsOneAndNameIsBob_thenTrue() { + assertTrue(Validator().isValid(Item(1f, "Bob"))) + } + + + @Test + fun whenAmountIsMinusOneAndNameIsAlice_thenFalse() { + assertFalse(Validator().isValid(Item(-1f, "Alice"))) + } + + @Test + fun whenAmountIsMinusOneAndNameIsBob_thenFalse() { + assertFalse(Validator().isValid(Item(-1f, "Bob"))) + } + + @Test + fun whenAmountIsOneAndNameIsTom_thenFalse() { + assertFalse(Validator().isValid(Item(1f, "Tom"))) + } + + @Test + fun whenAmountIsMinusOneAndNameIsTom_thenFalse() { + assertFalse(Validator().isValid(Item(-1f, "Tom"))) + } + + +} \ No newline at end of file diff --git a/core-kotlin-2/src/test/kotlin/com/baeldung/range/CharRangeTest.kt b/core-kotlin-2/src/test/kotlin/com/baeldung/range/CharRangeTest.kt new file mode 100644 index 0000000000..0e23f508b6 --- /dev/null +++ b/core-kotlin-2/src/test/kotlin/com/baeldung/range/CharRangeTest.kt @@ -0,0 +1,17 @@ +package com.baeldung.range + +import org.junit.Test +import kotlin.test.assertEquals + +class CharRangeTest { + + @Test + fun testCharRange() { + assertEquals(listOf('a', 'b', 'c'), ('a'..'c').toList()) + } + + @Test + fun testCharDownRange() { + assertEquals(listOf('c', 'b', 'a'), ('c'.downTo('a')).toList()) + } +} \ No newline at end of file diff --git a/core-kotlin-2/src/test/kotlin/com/baeldung/range/ColorTest.kt b/core-kotlin-2/src/test/kotlin/com/baeldung/range/ColorTest.kt new file mode 100644 index 0000000000..4ac3270fcc --- /dev/null +++ b/core-kotlin-2/src/test/kotlin/com/baeldung/range/ColorTest.kt @@ -0,0 +1,20 @@ +package com.baeldung.range + +import org.junit.Test +import kotlin.test.assertFalse +import kotlin.test.assertTrue + +class ColorTest { + + @Test + fun testEnumRange() { + + println(Color.values().toList()); + val red = Color.RED + val yellow = Color.YELLOW + val range = red..yellow + + assertTrue { range.contains(Color.MAGENTA) } + assertFalse { range.contains(Color.BLUE) } + } +} \ No newline at end of file diff --git a/core-kotlin-2/src/test/kotlin/com/baeldung/range/CustomColorTest.kt b/core-kotlin-2/src/test/kotlin/com/baeldung/range/CustomColorTest.kt new file mode 100644 index 0000000000..8c8795ac42 --- /dev/null +++ b/core-kotlin-2/src/test/kotlin/com/baeldung/range/CustomColorTest.kt @@ -0,0 +1,41 @@ +package com.baeldung.range + +import org.junit.Test +import java.lang.IllegalStateException +import kotlin.test.assertFailsWith +import kotlin.test.assertTrue + +class CustomColorTest { + + @Test + fun testInvalidConstructor(){ + assertFailsWith(IllegalStateException::class){ + CustomColor(-1) + } + } + + @Test + fun assertHas10Colors(){ + assertTrue { + val a = CustomColor(1) + val b = CustomColor(10) + val range = a..b + for(cc in range){ + println(cc) + } + range.toList().size == 10 + } + } + + @Test + fun assertContains0xCCCCCC(){ + assertTrue { + val a = CustomColor(0xBBBBBB) + val b = CustomColor(0xDDDDDD) + val range = a..b + range.contains(CustomColor(0xCCCCCC)) + } + } + +} + diff --git a/core-kotlin-2/src/test/kotlin/com/baeldung/range/FilterTest.kt b/core-kotlin-2/src/test/kotlin/com/baeldung/range/FilterTest.kt new file mode 100644 index 0000000000..d0e2df8860 --- /dev/null +++ b/core-kotlin-2/src/test/kotlin/com/baeldung/range/FilterTest.kt @@ -0,0 +1,24 @@ +package com.baeldung.range + +import org.junit.Test +import kotlin.test.assertEquals + +class FilterTest { + + val r = 1..10 + + @Test + fun filterTest() { + assertEquals(listOf(2, 4, 6, 8, 10), r.filter { it -> it % 2 == 0 }.toList()) + } + + @Test + fun mapTest() { + assertEquals(listOf(1, 4, 9, 16, 25, 36, 49, 64, 81, 100), r.map { it -> it * it }.toList()) + } + + @Test + fun reduceTest() { + assertEquals(55, r.reduce { a, b -> a + b }) + } +} \ No newline at end of file diff --git a/core-kotlin-2/src/test/kotlin/com/baeldung/range/FirstLastTest.kt b/core-kotlin-2/src/test/kotlin/com/baeldung/range/FirstLastTest.kt new file mode 100644 index 0000000000..ca797e9c9b --- /dev/null +++ b/core-kotlin-2/src/test/kotlin/com/baeldung/range/FirstLastTest.kt @@ -0,0 +1,22 @@ +package com.baeldung.range + +import org.junit.Test +import kotlin.test.assertEquals + +class FirstLastTest { + + @Test + fun testFirst() { + assertEquals(1, (1..9).first) + } + + @Test + fun testLast() { + assertEquals(9, (1..9).last) + } + + @Test + fun testStep() { + assertEquals(2, (1..9 step 2).step) + } +} \ No newline at end of file diff --git a/core-kotlin-2/src/test/kotlin/com/baeldung/range/OtherRangeFunctionsTest.kt b/core-kotlin-2/src/test/kotlin/com/baeldung/range/OtherRangeFunctionsTest.kt new file mode 100644 index 0000000000..d2d36bbfae --- /dev/null +++ b/core-kotlin-2/src/test/kotlin/com/baeldung/range/OtherRangeFunctionsTest.kt @@ -0,0 +1,40 @@ +package com.baeldung.range + +import org.junit.Test +import kotlin.test.assertEquals + +class OtherRangeFunctionsTest { + + val r = 1..20 + val repeated = listOf(1, 1, 2, 4, 4, 6, 10) + + @Test + fun testMin() { + assertEquals(1, r.min()) + } + + @Test + fun testMax() { + assertEquals(20, r.max()) + } + + @Test + fun testSum() { + assertEquals(210, r.sum()) + } + + @Test + fun testAverage() { + assertEquals(10.5, r.average()) + } + + @Test + fun testCount() { + assertEquals(20, r.count()) + } + + @Test + fun testDistinct() { + assertEquals(listOf(1, 2, 4, 6, 10), repeated.distinct()) + } +} \ No newline at end of file diff --git a/core-kotlin-2/src/test/kotlin/com/baeldung/range/RangeTest.kt b/core-kotlin-2/src/test/kotlin/com/baeldung/range/RangeTest.kt new file mode 100644 index 0000000000..48fa483924 --- /dev/null +++ b/core-kotlin-2/src/test/kotlin/com/baeldung/range/RangeTest.kt @@ -0,0 +1,22 @@ +package com.baeldung.range + +import org.junit.Test +import kotlin.test.assertEquals + +class RangeTest { + + @Test + fun testRange() { + assertEquals(listOf(1,2,3), (1.rangeTo(3).toList())) + } + + @Test + fun testDownTo(){ + assertEquals(listOf(3,2,1), (3.downTo(1).toList())) + } + + @Test + fun testUntil(){ + assertEquals(listOf(1,2), (1.until(3).toList())) + } +} \ No newline at end of file diff --git a/core-kotlin-2/src/test/kotlin/com/baeldung/range/ReverseRangeTest.kt b/core-kotlin-2/src/test/kotlin/com/baeldung/range/ReverseRangeTest.kt new file mode 100644 index 0000000000..7e1c7badb7 --- /dev/null +++ b/core-kotlin-2/src/test/kotlin/com/baeldung/range/ReverseRangeTest.kt @@ -0,0 +1,12 @@ +package com.baeldung.range + +import org.junit.Test +import kotlin.test.assertEquals + +class ReverseRangeTest { + + @Test + fun reversedTest() { + assertEquals(listOf(9, 6, 3), (1..9).reversed().step(3).toList()) + } +} \ No newline at end of file diff --git a/core-kotlin-2/src/test/kotlin/com/baeldung/range/StepTest.kt b/core-kotlin-2/src/test/kotlin/com/baeldung/range/StepTest.kt new file mode 100644 index 0000000000..4570ceeb0a --- /dev/null +++ b/core-kotlin-2/src/test/kotlin/com/baeldung/range/StepTest.kt @@ -0,0 +1,17 @@ +package com.baeldung.range + +import org.junit.Test +import kotlin.test.assertEquals + +class StepTest { + + @Test + fun testStep() { + assertEquals(listOf(1, 3, 5, 7, 9), (1..9 step 2).toList()) + } + + @Test + fun testStepDown() { + assertEquals(listOf(9, 7, 5, 3, 1), (9 downTo 1 step 2).toList()) + } +} \ No newline at end of file diff --git a/core-kotlin-2/src/test/kotlin/com/baeldung/range/UntilRangeTest.kt b/core-kotlin-2/src/test/kotlin/com/baeldung/range/UntilRangeTest.kt new file mode 100644 index 0000000000..f941c7f1e6 --- /dev/null +++ b/core-kotlin-2/src/test/kotlin/com/baeldung/range/UntilRangeTest.kt @@ -0,0 +1,12 @@ +package com.baeldung.range + +import org.junit.Test +import kotlin.test.assertEquals + +class UntilRangeTest { + + @Test + fun testUntil() { + assertEquals(listOf(1, 2, 3, 4), (1 until 5).toList()) + } +} \ No newline at end of file diff --git a/core-kotlin-2/src/test/kotlin/com/baeldung/scope/ScopeFunctionsUnitTest.kt b/core-kotlin-2/src/test/kotlin/com/baeldung/scope/ScopeFunctionsUnitTest.kt new file mode 100644 index 0000000000..cb3ed98006 --- /dev/null +++ b/core-kotlin-2/src/test/kotlin/com/baeldung/scope/ScopeFunctionsUnitTest.kt @@ -0,0 +1,143 @@ +package com.baeldung.scope + +import org.junit.Test +import kotlin.test.assertTrue + + +class ScopeFunctionsUnitTest { + + class Logger { + + var called : Boolean = false + + fun info(message: String) { + called = true + } + + fun wasCalled() = called + } + + @Test + fun shouldTransformWhenLetFunctionUsed() { + val stringBuider = StringBuilder() + val numberOfCharacters = stringBuider.let { + it.append("This is a transformation function.") + it.append("It takes a StringBuilder instance and returns the number of characters in the generated String") + it.length + } + + assertTrue { + numberOfCharacters == 128 + } + } + + @Test + fun shouldHandleNullabilityWhenLetFunctionUsed() { + + val message: String? = "hello there!" + val charactersInMessage = message?.let { + "At this point is safe to reference the variable. Let's print the message: $it" + } ?: "default value" + + assertTrue { + charactersInMessage.equals("At this point is safe to reference the variable. Let's print the message: hello there!") + } + + val aNullMessage = null + val thisIsNull = aNullMessage?.let { + "At this point it would be safe to reference the variable. But it will not really happen because it is null. Let's reference: $it" + } ?: "default value" + + assertTrue { + thisIsNull.equals("default value") + } + } + + @Test + fun shouldInitializeObjectWhenUsingApply() { + val aStudent = Student().apply { + studentId = "1234567" + name = "Mary" + surname = "Smith" + } + + assertTrue { + aStudent.name.equals("Mary") + } + } + + @Test + fun shouldAllowBuilderStyleObjectDesignWhenApplyUsedInClassMethods() { + val teacher = Teacher() + .setId(1000) + .setName("Martha") + .setSurname("Spector") + + assertTrue { + teacher.surname.equals("Spector") + } + } + + @Test + fun shouldAllowSideEffectWhenUsingAlso() { + val restClient = RestClient("http://www.someurl.com") + + val logger = Logger() + + val headers = restClient + .getResponse() + .also { logger.info(it.toString()) } + .headers + + assertTrue { + logger.wasCalled() && headers.headerInfo.equals("some header info") + } + + } + + @Test + fun shouldInitializeFieldWhenAlsoUsed() { + val aStudent = Student().also { it.name = "John"} + + assertTrue { + aStudent.name.equals("John") + } + } + + @Test + fun shouldLogicallyGroupObjectCallsWhenUsingWith() { + val bankAccount = BankAccount(1000) + with (bankAccount) { + checkAuthorization("someone") + addPayee("some payee") + makePayment("payment information") + } + } + + @Test + fun shouldConvertObjectWhenRunUsed() { + val stringBuider = StringBuilder() + val numberOfCharacters = stringBuider.run { + append("This is a transformation function.") + append("It takes a StringBuilder instance and returns the number of characters in the generated String") + length + } + + assertTrue { + numberOfCharacters == 128 + } + } + + @Test + fun shouldHandleNullabilityWhenRunIsUsed() { + val message: String? = "hello there!" + val charactersInMessage = message?.run { + "At this point is safe to reference the variable. Let's print the message: $this" + } ?: "default value" + + assertTrue { + charactersInMessage.equals("At this point is safe to reference the variable. Let's print the message: hello there!") + } + } + +} \ No newline at end of file diff --git a/core-kotlin-2/src/test/kotlin/com/baeldung/splitting/SplittingTest.kt b/core-kotlin-2/src/test/kotlin/com/baeldung/splitting/SplittingTest.kt new file mode 100644 index 0000000000..a9ddc99992 --- /dev/null +++ b/core-kotlin-2/src/test/kotlin/com/baeldung/splitting/SplittingTest.kt @@ -0,0 +1,99 @@ +package com.baeldung.lambda + +import org.junit.jupiter.api.Test +import kotlin.test.assertEquals + +class SplittingTest { + private val evenList = listOf(0, "a", 1, "b", 2, "c"); + + private val unevenList = listOf(0, "a", 1, "b", 2, "c", 3); + + private fun verifyList(resultList: List>) { + assertEquals("[[0, a], [1, b], [2, c]]", resultList.toString()) + } + + private fun verifyPartialList(resultList: List>) { + assertEquals("[[0, a], [1, b], [2, c], [3]]", resultList.toString()) + } + + @Test + fun whenChunked_thenListIsSplit() { + val resultList = evenList.chunked(2) + verifyList(resultList) + } + + @Test + fun whenUnevenChunked_thenListIsSplit() { + val resultList = unevenList.chunked(2) + verifyPartialList(resultList) + } + + @Test + fun whenWindowed_thenListIsSplit() { + val resultList = evenList.windowed(2, 2) + verifyList(resultList) + } + + @Test + fun whenUnevenPartialWindowed_thenListIsSplit() { + val resultList = unevenList.windowed(2, 2, partialWindows = true) + verifyPartialList(resultList) + } + + @Test + fun whenUnevenWindowed_thenListIsSplit() { + val resultList = unevenList.windowed(2, 2, partialWindows = false) + verifyList(resultList) + } + + @Test + fun whenGroupByWithAscendingNumbers_thenListIsSplit() { + val numberList = listOf(1, 2, 3, 4, 5, 6); + val resultList = numberList.groupBy { (it + 1) / 2 } + assertEquals("[[1, 2], [3, 4], [5, 6]]", resultList.values.toString()) + assertEquals("[1, 2, 3]", resultList.keys.toString()) + } + + @Test + fun whenGroupByWithAscendingNumbersUneven_thenListIsSplit() { + val numberList = listOf(1, 2, 3, 4, 5, 6, 7); + val resultList = numberList.groupBy { (it + 1) / 2 }.values + assertEquals("[[1, 2], [3, 4], [5, 6], [7]]", resultList.toString()) + } + + @Test + fun whenGroupByWithRandomNumbers_thenListIsSplitInWrongWay() { + val numberList = listOf(1, 3, 8, 20, 23, 30); + val resultList = numberList.groupBy { (it + 1) / 2 } + assertEquals("[[1], [3], [8], [20], [23], [30]]", resultList.values.toString()) + assertEquals("[1, 2, 4, 10, 12, 15]", resultList.keys.toString()) + } + + @Test + fun whenWithIndexGroupBy_thenListIsSplit() { + val resultList = evenList.withIndex() + .groupBy { it.index / 2 } + .map { it.value.map { it.value } } + verifyList(resultList) + } + + @Test + fun whenWithIndexGroupByUneven_thenListIsSplit() { + val resultList = unevenList.withIndex() + .groupBy { it.index / 2 } + .map { it.value.map { it.value } } + verifyPartialList(resultList) + } + + @Test + fun whenFoldIndexed_thenListIsSplit() { + val resultList = evenList.foldIndexed(ArrayList>(evenList.size / 2)) { index, acc, item -> + if (index % 2 == 0) { + acc.add(ArrayList(2)) + } + acc.last().add(item) + acc + } + verifyList(resultList) + } +} \ No newline at end of file diff --git a/core-kotlin-io/.gitignore b/core-kotlin-io/.gitignore new file mode 100644 index 0000000000..f521947850 --- /dev/null +++ b/core-kotlin-io/.gitignore @@ -0,0 +1,11 @@ +/bin/ + +#ignore gradle +.gradle/ + + +#ignore build and generated files +build/ +node/ +target/ +out/ diff --git a/core-kotlin-io/README.md b/core-kotlin-io/README.md new file mode 100644 index 0000000000..cb4dac7e4d --- /dev/null +++ b/core-kotlin-io/README.md @@ -0,0 +1,5 @@ +## Relevant articles: + +- [InputStream to String in Kotlin](https://www.baeldung.com/kotlin-inputstream-to-string) +- [Console I/O in Kotlin](https://www.baeldung.com/kotlin-console-io) + diff --git a/core-kotlin-io/pom.xml b/core-kotlin-io/pom.xml new file mode 100644 index 0000000000..a0b688a223 --- /dev/null +++ b/core-kotlin-io/pom.xml @@ -0,0 +1,97 @@ + + + 4.0.0 + core-kotlin-io + core-kotlin-io + jar + + + com.baeldung + parent-kotlin + 1.0.0-SNAPSHOT + ../parent-kotlin + + + + + org.jetbrains.kotlin + kotlin-stdlib-jdk8 + ${kotlin.version} + + + org.junit.jupiter + junit-jupiter + ${junit.jupiter.version} + test + + + org.mockito + mockito-core + ${mockito.version} + test + + + net.bytebuddy + byte-buddy + ${byte-buddy.version} + test + + + org.assertj + assertj-core + ${assertj.version} + test + + + org.jetbrains.kotlin + kotlin-test + ${kotlin.version} + test + + + org.jetbrains.kotlin + kotlin-test-junit5 + ${kotlin.version} + test + + + + + + + org.jetbrains.kotlin + kotlin-maven-plugin + ${kotlin.version} + + + compile + compile + + compile + + + + test-compile + test-compile + + test-compile + + + + + 1.8 + + + + + + + 1.3.30 + 5.4.2 + 2.27.0 + 1.9.12 + 3.10.0 + + + diff --git a/core-kotlin-io/src/main/kotlin/com/baeldung/inputstream/InputStreamExtension.kt b/core-kotlin-io/src/main/kotlin/com/baeldung/inputstream/InputStreamExtension.kt new file mode 100644 index 0000000000..e94a2e84ee --- /dev/null +++ b/core-kotlin-io/src/main/kotlin/com/baeldung/inputstream/InputStreamExtension.kt @@ -0,0 +1,18 @@ +package com.baeldung.inputstream + +import java.io.InputStream + +fun InputStream.readUpToChar(stopChar: Char): String { + val stringBuilder = StringBuilder() + var currentChar = this.read().toChar() + while (currentChar != stopChar) { + stringBuilder.append(currentChar) + currentChar = this.read().toChar() + if (this.available() <= 0) { + stringBuilder.append(currentChar) + break + } + } + return stringBuilder.toString() +} + diff --git a/core-kotlin-io/src/test/kotlin/com/baeldung/console/ConsoleIOUnitTest.kt b/core-kotlin-io/src/test/kotlin/com/baeldung/console/ConsoleIOUnitTest.kt new file mode 100644 index 0000000000..c73096fce6 --- /dev/null +++ b/core-kotlin-io/src/test/kotlin/com/baeldung/console/ConsoleIOUnitTest.kt @@ -0,0 +1,79 @@ +package com.baeldung.console + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.Test +import org.mockito.Mockito.`when` +import org.mockito.Mockito.mock +import java.io.BufferedReader +import java.io.ByteArrayInputStream +import java.io.ByteArrayOutputStream +import java.io.Console +import java.io.InputStreamReader +import java.io.PrintStream +import java.util.* + + +class ConsoleIOUnitTest { + + @Test + fun givenText_whenPrint_thenPrintText() { + val expectedTest = "Hello from Kotlin" + val out = ByteArrayOutputStream() + System.setOut(PrintStream(out)) + + print(expectedTest) + out.flush() + val printedText = String(out.toByteArray()) + + assertThat(printedText).isEqualTo(expectedTest) + } + + @Test + fun givenInput_whenRead_thenReadText() { + val expectedTest = "Hello from Kotlin" + val input = ByteArrayInputStream(expectedTest.toByteArray()) + System.setIn(input) + + val readText = readLine() + + assertThat(readText).isEqualTo(expectedTest) + } + + @Test + fun givenInput_whenReadWithScanner_thenReadText() { + val expectedTest = "Hello from Kotlin" + val scanner = Scanner(ByteArrayInputStream(expectedTest.toByteArray())) + + val readText = scanner.nextLine() + + assertThat(readText).isEqualTo(expectedTest) + } + + @Test + fun givenInput_whenReadWithBufferedReader_thenReadText() { + val expectedTest = "Hello from Kotlin" + val reader = BufferedReader(InputStreamReader(ByteArrayInputStream(expectedTest.toByteArray()))) + + val readText = reader.readLine() + + assertThat(readText).isEqualTo(expectedTest) + } + + @Test + fun givenInput_whenReadWithConsole_thenReadText() { + val expectedTest = "Hello from Kotlin" + val console = mock(Console::class.java) + `when`(console.readLine()).thenReturn(expectedTest) + + val readText = console.readLine() + + assertThat(readText).isEqualTo(expectedTest) + } + + @AfterEach + fun resetIO() { + System.setOut(System.out) + System.setIn(System.`in`) + } +} \ No newline at end of file diff --git a/core-kotlin-io/src/test/kotlin/com/baeldung/inputstream/InputStreamToStringTest.kt b/core-kotlin-io/src/test/kotlin/com/baeldung/inputstream/InputStreamToStringTest.kt new file mode 100644 index 0000000000..d10d23bef0 --- /dev/null +++ b/core-kotlin-io/src/test/kotlin/com/baeldung/inputstream/InputStreamToStringTest.kt @@ -0,0 +1,72 @@ +package com.baeldung.inputstream + +import kotlinx.io.core.use +import org.junit.Test +import java.io.BufferedReader +import java.io.File +import kotlin.test.assertEquals + +class InputStreamToStringTest { + private val fileName = "src/test/resources/inputstream2string.txt" + private val endOfLine = System.lineSeparator() + private val fileFullContent = "Computer programming can be a hassle$endOfLine" + + "It's like trying to take a defended castle" + + @Test + fun whenReadFileWithBufferedReader_thenFullFileContentIsReadAsString() { + val file = File(fileName) + val inputStream = file.inputStream() + val content = inputStream.bufferedReader().use(BufferedReader::readText) + assertEquals(fileFullContent, content) + } + @Test + fun whenReadFileWithBufferedReaderReadText_thenFullFileContentIsReadAsString() { + val file = File(fileName) + val inputStream = file.inputStream() + val reader = BufferedReader(inputStream.reader()) + var content: String + try { + content = reader.readText() + } finally { + reader.close() + } + assertEquals(fileFullContent, content) + } + @Test + fun whenReadFileWithBufferedReaderManually_thenFullFileContentIsReadAsString() { + val file = File(fileName) + val inputStream = file.inputStream() + val reader = BufferedReader(inputStream.reader()) + val content = StringBuilder() + try { + var line = reader.readLine() + while (line != null) { + content.append(line) + line = reader.readLine() + } + } finally { + reader.close() + } + assertEquals(fileFullContent.replace(endOfLine, ""), content.toString()) + + } + + @Test + fun whenReadFileUpToStopChar_thenPartBeforeStopCharIsReadAsString() { + val file = File(fileName) + val inputStream = file.inputStream() + val content = inputStream.use { it.readUpToChar(' ') } + assertEquals("Computer", content) + } + + @Test + fun whenReadFileWithoutContainingStopChar_thenFullFileContentIsReadAsString() { + val file = File(fileName) + val inputStream = file.inputStream() + val content = inputStream.use { it.readUpToChar('-') } + assertEquals(fileFullContent, content) + } + + +} + diff --git a/core-kotlin-io/src/test/resources/inputstream2string.txt b/core-kotlin-io/src/test/resources/inputstream2string.txt new file mode 100644 index 0000000000..40ef9fc5f3 --- /dev/null +++ b/core-kotlin-io/src/test/resources/inputstream2string.txt @@ -0,0 +1,2 @@ +Computer programming can be a hassle +It's like trying to take a defended castle \ No newline at end of file diff --git a/core-kotlin-io/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/core-kotlin-io/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker new file mode 100644 index 0000000000..ca6ee9cea8 --- /dev/null +++ b/core-kotlin-io/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker @@ -0,0 +1 @@ +mock-maker-inline \ No newline at end of file diff --git a/core-kotlin/README.md b/core-kotlin/README.md index 7d8001d667..3392db9171 100644 --- a/core-kotlin/README.md +++ b/core-kotlin/README.md @@ -1,7 +1,7 @@ ## Relevant articles: - [Introduction to the Kotlin Language](http://www.baeldung.com/kotlin) -- [A guide to the “when{}” block in Kotlin](http://www.baeldung.com/kotlin-when) +- [Guide to the “when{}” Block in Kotlin](http://www.baeldung.com/kotlin-when) - [Comprehensive Guide to Null Safety in Kotlin](http://www.baeldung.com/kotlin-null-safety) - [Kotlin Java Interoperability](http://www.baeldung.com/kotlin-java-interoperability) - [Difference Between “==” and “===” operators in Kotlin](http://www.baeldung.com/kotlin-equality-operators) @@ -54,3 +54,5 @@ - [Nested forEach in Kotlin](https://www.baeldung.com/kotlin-nested-foreach) - [Building DSLs in Kotlin](https://www.baeldung.com/kotlin-dsl) - [Static Methods Behavior in Kotlin](https://www.baeldung.com/kotlin-static-methods) +- [Inline Functions in Kotlin](https://www.baeldung.com/kotlin-inline-functions) +- [Delegation Pattern in Kotlin](https://www.baeldung.com/kotlin-delegation-pattern) diff --git a/core-kotlin/src/main/kotlin/com/baeldung/filesystem/FileReader.kt b/core-kotlin/src/main/kotlin/com/baeldung/filesystem/FileReader.kt index 8539378c91..886a3fc51e 100644 --- a/core-kotlin/src/main/kotlin/com/baeldung/filesystem/FileReader.kt +++ b/core-kotlin/src/main/kotlin/com/baeldung/filesystem/FileReader.kt @@ -17,4 +17,8 @@ class FileReader { File(fileName).inputStream().readBytes().toString(Charsets.UTF_8) fun readFileDirectlyAsText(fileName: String): String = File(fileName).readText(Charsets.UTF_8) + + fun readFileUsingGetResource(fileName: String) = this::class.java.getResource(fileName).readText(Charsets.UTF_8) + + fun readFileAsLinesUsingGetResourceAsStream(fileName: String) = this::class.java.getResourceAsStream(fileName).bufferedReader().readLines() } \ No newline at end of file diff --git a/core-kotlin/src/main/kotlin/com/baeldung/forEach/forEach.kt b/core-kotlin/src/main/kotlin/com/baeldung/forEach/forEach.kt index ef56009c71..20eda4e64f 100644 --- a/core-kotlin/src/main/kotlin/com/baeldung/forEach/forEach.kt +++ b/core-kotlin/src/main/kotlin/com/baeldung/forEach/forEach.kt @@ -5,6 +5,15 @@ class Country(val name : String, val cities : List) class City(val name : String, val streets : List) +fun City.getStreetsWithCityName() : List { + return streets.map { "$name, $it" }.toList() +} + +fun Country.getCitiesWithCountryName() : List { + return cities.flatMap { it.getStreetsWithCityName() } + .map { "$name, $it" } +} + class World { private val streetsOfAmsterdam = listOf("Herengracht", "Prinsengracht") @@ -45,6 +54,19 @@ class World { } } } + + fun allStreetsFlatMap() { + + countries.flatMap { it.cities} + .flatMap { it.streets} + .forEach { println(it) } + } + + fun allFlatMapTable() { + + countries.flatMap { it.getCitiesWithCountryName() } + .forEach { println(it) } + } } fun main(args : Array) { @@ -56,6 +78,10 @@ fun main(args : Array) { world.allNested() world.allTable() + + world.allStreetsFlatMap() + + world.allFlatMapTable() } diff --git a/core-kotlin/src/main/kotlin/com/baeldung/kotlin/StringUtil.kt b/core-kotlin/src/main/kotlin/com/baeldung/kotlin/StringUtil.kt new file mode 100644 index 0000000000..ca57b2965e --- /dev/null +++ b/core-kotlin/src/main/kotlin/com/baeldung/kotlin/StringUtil.kt @@ -0,0 +1,9 @@ +@file:JvmName("Strings") +package com.baeldung.kotlin + +fun String.escapeForXml() : String { + return this + .replace("&", "&") + .replace("<", "<") + .replace(">", ">") +} diff --git a/core-kotlin/src/main/kotlin/com/baeldung/kotlin/delegates/InterfaceDelegation.kt b/core-kotlin/src/main/kotlin/com/baeldung/kotlin/delegates/InterfaceDelegation.kt new file mode 100644 index 0000000000..8e261aacf2 --- /dev/null +++ b/core-kotlin/src/main/kotlin/com/baeldung/kotlin/delegates/InterfaceDelegation.kt @@ -0,0 +1,64 @@ +package com.baeldung.kotlin.delegates + +import java.util.concurrent.locks.ReentrantLock +import kotlin.concurrent.withLock + +interface Producer { + + fun produce(): String +} + +class ProducerImpl : Producer { + + override fun produce() = "ProducerImpl" +} + +class EnhancedProducer(private val delegate: Producer) : Producer by delegate { + + override fun produce() = "${delegate.produce()} and EnhancedProducer" +} + +interface MessageService { + + fun processMessage(message: String): String +} + +class MessageServiceImpl : MessageService { + override fun processMessage(message: String): String { + return "MessageServiceImpl: $message" + } +} + +interface UserService { + + fun processUser(userId: String): String +} + +class UserServiceImpl : UserService { + + override fun processUser(userId: String): String { + return "UserServiceImpl: $userId" + } +} + +class CompositeService : UserService by UserServiceImpl(), MessageService by MessageServiceImpl() + +interface Service { + + val seed: Int + + fun serve(action: (Int) -> Unit) +} + +class ServiceImpl : Service { + + override val seed = 1 + + override fun serve(action: (Int) -> Unit) { + action(seed) + } +} + +class ServiceDecorator : Service by ServiceImpl() { + override val seed = 2 +} \ No newline at end of file diff --git a/core-kotlin/src/test/java/com/baeldung/kotlin/StringUtilUnitTest.java b/core-kotlin/src/test/java/com/baeldung/kotlin/StringUtilUnitTest.java new file mode 100644 index 0000000000..c7ef18b879 --- /dev/null +++ b/core-kotlin/src/test/java/com/baeldung/kotlin/StringUtilUnitTest.java @@ -0,0 +1,30 @@ +package com.baeldung.kotlin; + +import kotlin.text.StringsKt; +import org.junit.Assert; +import org.junit.Test; + +import static com.baeldung.kotlin.Strings.*; + + +public class StringUtilUnitTest { + + @Test + public void shouldEscapeXmlTagsInString() { + String xml = "hi"; + + String escapedXml = escapeForXml(xml); + + Assert.assertEquals("<a>hi</a>", escapedXml); + } + + @Test + public void callingBuiltInKotlinExtensionMethod() { + String name = "john"; + + String capitalizedName = StringsKt.capitalize(name); + + Assert.assertEquals("John", capitalizedName); + } + +} diff --git a/core-kotlin/src/test/kotlin/com/baeldung/filesystem/FileReaderTest.kt b/core-kotlin/src/test/kotlin/com/baeldung/filesystem/FileReaderTest.kt index 67795dda14..ad541c446e 100644 --- a/core-kotlin/src/test/kotlin/com/baeldung/filesystem/FileReaderTest.kt +++ b/core-kotlin/src/test/kotlin/com/baeldung/filesystem/FileReaderTest.kt @@ -48,4 +48,20 @@ internal class FileReaderTest { assertTrue { text.contains("Hello to Kotlin") } } + + @Test + fun whenReadFileAsTextUsingGetResource_thenCorrect() { + val text = fileReader.readFileUsingGetResource("/Kotlin.in") + + assertTrue { text.contains("1. Concise") } + } + + @Test + fun whenReadFileUsingGetResourceAsStream_thenCorrect() { + val lines = fileReader.readFileAsLinesUsingGetResourceAsStream("/Kotlin.in") + + assertTrue { lines.contains("3. Interoperable") } + } + + } \ No newline at end of file diff --git a/core-kotlin/src/test/kotlin/com/baeldung/kotlin/ExtensionMethods.kt b/core-kotlin/src/test/kotlin/com/baeldung/kotlin/ExtensionMethods.kt index 09ce898860..44c5cd0ece 100644 --- a/core-kotlin/src/test/kotlin/com/baeldung/kotlin/ExtensionMethods.kt +++ b/core-kotlin/src/test/kotlin/com/baeldung/kotlin/ExtensionMethods.kt @@ -6,13 +6,6 @@ import org.junit.Test class ExtensionMethods { @Test fun simpleExtensionMethod() { - fun String.escapeForXml() : String { - return this - .replace("&", "&") - .replace("<", "<") - .replace(">", ">") - } - Assert.assertEquals("Nothing", "Nothing".escapeForXml()) Assert.assertEquals("<Tag>", "".escapeForXml()) Assert.assertEquals("a&b", "a&b".escapeForXml()) diff --git a/core-kotlin/src/test/kotlin/com/baeldung/kotlin/delegates/InterfaceDelegationTest.kt b/core-kotlin/src/test/kotlin/com/baeldung/kotlin/delegates/InterfaceDelegationTest.kt new file mode 100644 index 0000000000..e65032acd4 --- /dev/null +++ b/core-kotlin/src/test/kotlin/com/baeldung/kotlin/delegates/InterfaceDelegationTest.kt @@ -0,0 +1,28 @@ +package com.baeldung.kotlin.delegates + +import org.assertj.core.api.Assertions.assertThat +import org.junit.Test + +class InterfaceDelegationTest { + + @Test + fun `when delegated implementation is used then it works as expected`() { + val producer = EnhancedProducer(ProducerImpl()) + assertThat(producer.produce()).isEqualTo("ProducerImpl and EnhancedProducer") + } + + @Test + fun `when composite delegation is used then it works as expected`() { + val service = CompositeService() + assertThat(service.processMessage("message")).isEqualTo("MessageServiceImpl: message") + assertThat(service.processUser("user")).isEqualTo("UserServiceImpl: user") + } + + @Test + fun `when decoration is used then delegate knows nothing about it`() { + val service = ServiceDecorator() + service.serve { + assertThat(it).isEqualTo(1) + } + } +} \ No newline at end of file diff --git a/couchbase/README.md b/couchbase/README.md index 9b76609593..7a99ce4299 100644 --- a/couchbase/README.md +++ b/couchbase/README.md @@ -3,7 +3,7 @@ ### Relevant Articles: - [Introduction to Couchbase SDK for Java](http://www.baeldung.com/java-couchbase-sdk) - [Using Couchbase in a Spring Application](http://www.baeldung.com/couchbase-sdk-spring) -- [Asynchronous Batch Opereations in Couchbase](http://www.baeldung.com/async-batch-operations-in-couchbase) +- [Asynchronous Batch Operations in Couchbase](http://www.baeldung.com/async-batch-operations-in-couchbase) - [Querying Couchbase with MapReduce Views](http://www.baeldung.com/couchbase-query-mapreduce-view) - [Querying Couchbase with N1QL](http://www.baeldung.com/n1ql-couchbase) diff --git a/google-web-toolkit/README.md b/google-web-toolkit/README.md index 65264375bc..3526fe9962 100644 --- a/google-web-toolkit/README.md +++ b/google-web-toolkit/README.md @@ -1,3 +1,2 @@ ### Relevant Articles: - [Introduction to GWT](http://www.baeldung.com/gwt) -- [Quick Use of FilenameFilter](http://www.baeldung.com/java-filename-filter) diff --git a/gradle/README.md b/gradle/README.md index a1f5c74c57..14e460f225 100644 --- a/gradle/README.md +++ b/gradle/README.md @@ -3,5 +3,4 @@ - [Writing Custom Gradle Plugins](http://www.baeldung.com/gradle-create-plugin) - [Creating a Fat Jar in Gradle](http://www.baeldung.com/gradle-fat-jar) - [A Custom Task in Gradle](http://www.baeldung.com/gradle-custom-task) -- [Kotlin Dependency Injection with Kodein](http://www.baeldung.com/kotlin-kodein-dependency-injection) - [Using JUnit 5 with Gradle](https://www.baeldung.com/junit-5-gradle) diff --git a/gson/README.md b/gson/README.md index 02b06eac20..268116a2ac 100644 --- a/gson/README.md +++ b/gson/README.md @@ -11,3 +11,6 @@ - [Convert JSON to a Map Using Gson](https://www.baeldung.com/gson-json-to-map) - [Working with Primitive Values in Gson](https://www.baeldung.com/java-gson-primitives) - [Convert String to JsonObject with Gson](https://www.baeldung.com/gson-string-to-jsonobject) +- [Mapping Multiple JSON Fields to a Single Java Field](https://www.baeldung.com/json-multiple-fields-single-java-field) +- [Serializing and Deserializing a List with Gson](https://www.baeldung.com/gson-list) + diff --git a/gson/src/main/java/org/baeldung/gson/entities/Animal.java b/gson/src/main/java/org/baeldung/gson/entities/Animal.java new file mode 100644 index 0000000000..2eec5f8704 --- /dev/null +++ b/gson/src/main/java/org/baeldung/gson/entities/Animal.java @@ -0,0 +1,5 @@ +package org.baeldung.gson.entities; + +public abstract class Animal { + public String type = "Animal"; +} diff --git a/gson/src/main/java/org/baeldung/gson/entities/Cow.java b/gson/src/main/java/org/baeldung/gson/entities/Cow.java new file mode 100644 index 0000000000..020bcd5860 --- /dev/null +++ b/gson/src/main/java/org/baeldung/gson/entities/Cow.java @@ -0,0 +1,19 @@ +package org.baeldung.gson.entities; + +public class Cow extends Animal { + private String breed; + + public Cow() { + breed = "Jersey"; + type = "Cow"; + } + + public String getBreed() { + return breed; + } + + public void setBreed(String breed) { + this.breed = breed; + } +} + diff --git a/gson/src/main/java/org/baeldung/gson/entities/Dog.java b/gson/src/main/java/org/baeldung/gson/entities/Dog.java new file mode 100644 index 0000000000..042d73adcf --- /dev/null +++ b/gson/src/main/java/org/baeldung/gson/entities/Dog.java @@ -0,0 +1,18 @@ +package org.baeldung.gson.entities; + +public class Dog extends Animal { + private String petName; + + public Dog() { + petName = "Milo"; + type = "Dog"; + } + + public String getPetName() { + return petName; + } + + public void setPetName(String petName) { + this.petName = petName; + } +} diff --git a/gson/src/main/java/org/baeldung/gson/entities/MyClass.java b/gson/src/main/java/org/baeldung/gson/entities/MyClass.java new file mode 100644 index 0000000000..4e717e72c3 --- /dev/null +++ b/gson/src/main/java/org/baeldung/gson/entities/MyClass.java @@ -0,0 +1,49 @@ +package org.baeldung.gson.entities; + +import java.util.Objects; + +public class MyClass { + private int id; + private String name; + + public MyClass(int id, String name) { + this.id = id; + this.name = name; + } + + public MyClass() { } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + MyClass myClass = (MyClass) o; + return id == myClass.id && Objects.equals(name, myClass.name); + } + + @Override + public int hashCode() { + + return Objects.hash(id, name); + } +} diff --git a/gson/src/main/java/org/baeldung/gson/entities/Weather.java b/gson/src/main/java/org/baeldung/gson/entities/Weather.java new file mode 100644 index 0000000000..383e9ef41c --- /dev/null +++ b/gson/src/main/java/org/baeldung/gson/entities/Weather.java @@ -0,0 +1,40 @@ +package org.baeldung.gson.entities; + +import com.google.gson.annotations.SerializedName; + +public class Weather { + + @SerializedName(value = "location", alternate = "place") + private String location; + + @SerializedName(value = "temp", alternate = "temperature") + private int temp; + + @SerializedName(value = "outlook", alternate = "weather") + private String outlook; + + public String getLocation() { + return location; + } + + public void setLocation(String location) { + this.location = location; + } + + public int getTemp() { + return temp; + } + + public void setTemp(int temp) { + this.temp = temp; + } + + public String getOutlook() { + return outlook; + } + + public void setOutlook(String outlook) { + this.outlook = outlook; + } + +} diff --git a/gson/src/main/java/org/baeldung/gson/serialization/AnimalDeserializer.java b/gson/src/main/java/org/baeldung/gson/serialization/AnimalDeserializer.java new file mode 100644 index 0000000000..9dcef0e10b --- /dev/null +++ b/gson/src/main/java/org/baeldung/gson/serialization/AnimalDeserializer.java @@ -0,0 +1,35 @@ +package org.baeldung.gson.serialization; + +import com.google.gson.Gson; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import java.lang.reflect.Type; +import java.util.HashMap; +import java.util.Map; +import org.baeldung.gson.entities.Animal; + +public class AnimalDeserializer implements JsonDeserializer { + private String animalTypeElementName; + private Gson gson; + private Map> animalTypeRegistry; + + public AnimalDeserializer(String animalTypeElementName) { + this.animalTypeElementName = animalTypeElementName; + this.gson = new Gson(); + this.animalTypeRegistry = new HashMap<>(); + } + + public void registerBarnType(String animalTypeName, Class animalType) { + animalTypeRegistry.put(animalTypeName, animalType); + } + + public Animal deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) { + JsonObject animalObject = json.getAsJsonObject(); + JsonElement animalTypeElement = animalObject.get(animalTypeElementName); + + Class animalType = animalTypeRegistry.get(animalTypeElement.getAsString()); + return gson.fromJson(animalObject, animalType); + } +} \ No newline at end of file diff --git a/gson/src/test/java/org/baeldung/gson/advance/GsonAdvanceUnitTest.java b/gson/src/test/java/org/baeldung/gson/advance/GsonAdvanceUnitTest.java new file mode 100644 index 0000000000..5b787f1956 --- /dev/null +++ b/gson/src/test/java/org/baeldung/gson/advance/GsonAdvanceUnitTest.java @@ -0,0 +1,117 @@ +package org.baeldung.gson.advance; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import org.baeldung.gson.entities.Animal; +import org.baeldung.gson.entities.Cow; +import org.baeldung.gson.entities.Dog; +import org.baeldung.gson.entities.MyClass; +import org.baeldung.gson.serialization.AnimalDeserializer; +import org.junit.Test; + +public class GsonAdvanceUnitTest { + + @Test + public void givenListOfMyClass_whenSerializing_thenCorrect() { + List list = Arrays.asList(new MyClass(1, "name1"), new MyClass(2, "name2")); + + Gson gson = new Gson(); + String jsonString = gson.toJson(list); + String expectedString = "[{\"id\":1,\"name\":\"name1\"},{\"id\":2,\"name\":\"name2\"}]"; + + assertEquals(expectedString, jsonString); + } + + @Test(expected = ClassCastException.class) + public void givenJsonString_whenIncorrectDeserializing_thenThrowClassCastException() { + String inputString = "[{\"id\":1,\"name\":\"name1\"},{\"id\":2,\"name\":\"name2\"}]"; + + Gson gson = new Gson(); + List outputList = gson.fromJson(inputString, ArrayList.class); + + assertEquals(1, outputList.get(0).getId()); + } + + @Test + public void givenJsonString_whenDeserializing_thenReturnListOfMyClass() { + String inputString = "[{\"id\":1,\"name\":\"name1\"},{\"id\":2,\"name\":\"name2\"}]"; + List inputList = Arrays.asList(new MyClass(1, "name1"), new MyClass(2, "name2")); + + Type listOfMyClassObject = new TypeToken>() {}.getType(); + + Gson gson = new Gson(); + List outputList = gson.fromJson(inputString, listOfMyClassObject); + + assertEquals(inputList, outputList); + } + + @Test + public void givenPolymorphicList_whenSerializeWithTypeAdapter_thenCorrect() { + String expectedString = "[{\"petName\":\"Milo\",\"type\":\"Dog\"},{\"breed\":\"Jersey\",\"type\":\"Cow\"}]"; + + List inList = new ArrayList<>(); + inList.add(new Dog()); + inList.add(new Cow()); + + String jsonString = new Gson().toJson(inList); + + assertEquals(expectedString, jsonString); + } + + @Test + public void givenPolymorphicList_whenDeserializeWithTypeAdapter_thenCorrect() { + String inputString = "[{\"petName\":\"Milo\",\"type\":\"Dog\"},{\"breed\":\"Jersey\",\"type\":\"Cow\"}]"; + + AnimalDeserializer deserializer = new AnimalDeserializer("type"); + deserializer.registerBarnType("Dog", Dog.class); + deserializer.registerBarnType("Cow", Cow.class); + Gson gson = new GsonBuilder() + .registerTypeAdapter(Animal.class, deserializer) + .create(); + + List outList = gson.fromJson(inputString, new TypeToken>(){}.getType()); + + assertEquals(2, outList.size()); + assertTrue(outList.get(0) instanceof Dog); + assertTrue(outList.get(1) instanceof Cow); + } + + @Test + public void givenPolymorphicList_whenSerializeWithRuntimeTypeAdapter_thenCorrect() { + String expectedString = "[{\"petName\":\"Milo\",\"type\":\"Dog\"},{\"breed\":\"Jersey\",\"type\":\"Cow\"}]"; + + List inList = new ArrayList<>(); + inList.add(new Dog()); + inList.add(new Cow()); + String jsonString = new Gson().toJson(inList); + + assertEquals(expectedString, jsonString); + } + + @Test + public void givenPolymorphicList_whenDeserializeWithRuntimeTypeAdapter_thenCorrect() { + String inputString = "[{\"petName\":\"Milo\",\"type\":\"Dog\"},{\"breed\":\"Jersey\",\"type\":\"Cow\"}]"; + + Type listOfAnimals = new TypeToken>() {}.getType(); + + RuntimeTypeAdapterFactory adapter = RuntimeTypeAdapterFactory.of(Animal.class, "type") + .registerSubtype(Dog.class) + .registerSubtype(Cow.class); + + Gson gson = new GsonBuilder().registerTypeAdapterFactory(adapter).create(); + + List outList = gson.fromJson(inputString, listOfAnimals); + + assertEquals(2, outList.size()); + assertTrue(outList.get(0) instanceof Dog); + assertTrue(outList.get(1) instanceof Cow); + } +} \ No newline at end of file diff --git a/gson/src/test/java/org/baeldung/gson/advance/RuntimeTypeAdapterFactory.java b/gson/src/test/java/org/baeldung/gson/advance/RuntimeTypeAdapterFactory.java new file mode 100644 index 0000000000..739dd889c7 --- /dev/null +++ b/gson/src/test/java/org/baeldung/gson/advance/RuntimeTypeAdapterFactory.java @@ -0,0 +1,265 @@ +package org.baeldung.gson.advance; + +/* + * Copyright (C) 2011 Google Inc. + * + * 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 + * + * http://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. + */ + +import java.io.IOException; +import java.util.LinkedHashMap; +import java.util.Map; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.JsonPrimitive; +import com.google.gson.TypeAdapter; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.internal.Streams; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; + +/** + * Adapts values whose runtime type may differ from their declaration type. This + * is necessary when a field's type is not the same type that GSON should create + * when deserializing that field. For example, consider these types: + *
   {@code
+ *   abstract class Shape {
+ *     int x;
+ *     int y;
+ *   }
+ *   class Circle extends Shape {
+ *     int radius;
+ *   }
+ *   class Rectangle extends Shape {
+ *     int width;
+ *     int height;
+ *   }
+ *   class Diamond extends Shape {
+ *     int width;
+ *     int height;
+ *   }
+ *   class Drawing {
+ *     Shape bottomShape;
+ *     Shape topShape;
+ *   }
+ * }
+ *

Without additional type information, the serialized JSON is ambiguous. Is + * the bottom shape in this drawing a rectangle or a diamond?

   {@code
+ *   {
+ *     "bottomShape": {
+ *       "width": 10,
+ *       "height": 5,
+ *       "x": 0,
+ *       "y": 0
+ *     },
+ *     "topShape": {
+ *       "radius": 2,
+ *       "x": 4,
+ *       "y": 1
+ *     }
+ *   }}
+ * This class addresses this problem by adding type information to the + * serialized JSON and honoring that type information when the JSON is + * deserialized:
   {@code
+ *   {
+ *     "bottomShape": {
+ *       "type": "Diamond",
+ *       "width": 10,
+ *       "height": 5,
+ *       "x": 0,
+ *       "y": 0
+ *     },
+ *     "topShape": {
+ *       "type": "Circle",
+ *       "radius": 2,
+ *       "x": 4,
+ *       "y": 1
+ *     }
+ *   }}
+ * Both the type field name ({@code "type"}) and the type labels ({@code + * "Rectangle"}) are configurable. + * + *

Registering Types

+ * Create a {@code RuntimeTypeAdapterFactory} by passing the base type and type field + * name to the {@link #of} factory method. If you don't supply an explicit type + * field name, {@code "type"} will be used.
   {@code
+ *   RuntimeTypeAdapterFactory shapeAdapterFactory
+ *       = RuntimeTypeAdapterFactory.of(Shape.class, "type");
+ * }
+ * Next register all of your subtypes. Every subtype must be explicitly + * registered. This protects your application from injection attacks. If you + * don't supply an explicit type label, the type's simple name will be used. + *
   {@code
+ *   shapeAdapterFactory.registerSubtype(Rectangle.class, "Rectangle");
+ *   shapeAdapterFactory.registerSubtype(Circle.class, "Circle");
+ *   shapeAdapterFactory.registerSubtype(Diamond.class, "Diamond");
+ * }
+ * Finally, register the type adapter factory in your application's GSON builder: + *
   {@code
+ *   Gson gson = new GsonBuilder()
+ *       .registerTypeAdapterFactory(shapeAdapterFactory)
+ *       .create();
+ * }
+ * Like {@code GsonBuilder}, this API supports chaining:
   {@code
+ *   RuntimeTypeAdapterFactory shapeAdapterFactory = RuntimeTypeAdapterFactory.of(Shape.class)
+ *       .registerSubtype(Rectangle.class)
+ *       .registerSubtype(Circle.class)
+ *       .registerSubtype(Diamond.class);
+ * }
+ */ +public final class RuntimeTypeAdapterFactory implements TypeAdapterFactory { + private final Class baseType; + private final String typeFieldName; + private final Map> labelToSubtype = new LinkedHashMap>(); + private final Map, String> subtypeToLabel = new LinkedHashMap, String>(); + private final boolean maintainType; + + private RuntimeTypeAdapterFactory(Class baseType, String typeFieldName, boolean maintainType) { + if (typeFieldName == null || baseType == null) { + throw new NullPointerException(); + } + this.baseType = baseType; + this.typeFieldName = typeFieldName; + this.maintainType = maintainType; + } + + /** + * Creates a new runtime type adapter using for {@code baseType} using {@code + * typeFieldName} as the type field name. Type field names are case sensitive. + * {@code maintainType} flag decide if the type will be stored in pojo or not. + */ + public static RuntimeTypeAdapterFactory of(Class baseType, String typeFieldName, boolean maintainType) { + return new RuntimeTypeAdapterFactory(baseType, typeFieldName, maintainType); + } + + /** + * Creates a new runtime type adapter using for {@code baseType} using {@code + * typeFieldName} as the type field name. Type field names are case sensitive. + */ + public static RuntimeTypeAdapterFactory of(Class baseType, String typeFieldName) { + return new RuntimeTypeAdapterFactory(baseType, typeFieldName, false); + } + + /** + * Creates a new runtime type adapter for {@code baseType} using {@code "type"} as + * the type field name. + */ + public static RuntimeTypeAdapterFactory of(Class baseType) { + return new RuntimeTypeAdapterFactory(baseType, "type", false); + } + + /** + * Registers {@code type} identified by {@code label}. Labels are case + * sensitive. + * + * @throws IllegalArgumentException if either {@code type} or {@code label} + * have already been registered on this type adapter. + */ + public RuntimeTypeAdapterFactory registerSubtype(Class type, String label) { + if (type == null || label == null) { + throw new NullPointerException(); + } + if (subtypeToLabel.containsKey(type) || labelToSubtype.containsKey(label)) { + throw new IllegalArgumentException("types and labels must be unique"); + } + labelToSubtype.put(label, type); + subtypeToLabel.put(type, label); + return this; + } + + /** + * Registers {@code type} identified by its {@link Class#getSimpleName simple + * name}. Labels are case sensitive. + * + * @throws IllegalArgumentException if either {@code type} or its simple name + * have already been registered on this type adapter. + */ + public RuntimeTypeAdapterFactory registerSubtype(Class type) { + return registerSubtype(type, type.getSimpleName()); + } + + public TypeAdapter create(Gson gson, TypeToken type) { + if (type.getRawType() != baseType) { + return null; + } + + final Map> labelToDelegate + = new LinkedHashMap>(); + final Map, TypeAdapter> subtypeToDelegate + = new LinkedHashMap, TypeAdapter>(); + for (Map.Entry> entry : labelToSubtype.entrySet()) { + TypeAdapter delegate = gson.getDelegateAdapter(this, TypeToken.get(entry.getValue())); + labelToDelegate.put(entry.getKey(), delegate); + subtypeToDelegate.put(entry.getValue(), delegate); + } + + return new TypeAdapter() { + @Override public R read(JsonReader in) throws IOException { + JsonElement jsonElement = Streams.parse(in); + JsonElement labelJsonElement; + if (maintainType) { + labelJsonElement = jsonElement.getAsJsonObject().get(typeFieldName); + } else { + labelJsonElement = jsonElement.getAsJsonObject().remove(typeFieldName); + } + + if (labelJsonElement == null) { + throw new JsonParseException("cannot deserialize " + baseType + + " because it does not define a field named " + typeFieldName); + } + String label = labelJsonElement.getAsString(); + @SuppressWarnings("unchecked") // registration requires that subtype extends T + TypeAdapter delegate = (TypeAdapter) labelToDelegate.get(label); + if (delegate == null) { + throw new JsonParseException("cannot deserialize " + baseType + " subtype named " + + label + "; did you forget to register a subtype?"); + } + return delegate.fromJsonTree(jsonElement); + } + + @Override public void write(JsonWriter out, R value) throws IOException { + Class srcType = value.getClass(); + String label = subtypeToLabel.get(srcType); + @SuppressWarnings("unchecked") // registration requires that subtype extends T + TypeAdapter delegate = (TypeAdapter) subtypeToDelegate.get(srcType); + if (delegate == null) { + throw new JsonParseException("cannot serialize " + srcType.getName() + + "; did you forget to register a subtype?"); + } + JsonObject jsonObject = delegate.toJsonTree(value).getAsJsonObject(); + + if (maintainType) { + Streams.write(jsonObject, out); + return; + } + + JsonObject clone = new JsonObject(); + + if (jsonObject.has(typeFieldName)) { + throw new JsonParseException("cannot serialize " + srcType.getName() + + " because it already defines a field named " + typeFieldName); + } + clone.add(typeFieldName, new JsonPrimitive(label)); + + for (Map.Entry e : jsonObject.entrySet()) { + clone.add(e.getKey(), e.getValue()); + } + Streams.write(clone, out); + } + }.nullSafe(); + } +} diff --git a/gson/src/test/java/org/baeldung/gson/deserialization/GsonAlternateUnitTest.java b/gson/src/test/java/org/baeldung/gson/deserialization/GsonAlternateUnitTest.java new file mode 100644 index 0000000000..f3a5d24e3e --- /dev/null +++ b/gson/src/test/java/org/baeldung/gson/deserialization/GsonAlternateUnitTest.java @@ -0,0 +1,39 @@ +package org.baeldung.gson.deserialization; + +import static org.junit.Assert.assertEquals; + +import org.baeldung.gson.entities.Weather; +import org.junit.Test; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +public class GsonAlternateUnitTest { + + @Test + public void givenTwoJsonFormats_whenDeserialized_thenWeatherObjectsCreated() throws Exception { + + Gson gson = new GsonBuilder().create(); + + Weather weather = gson.fromJson("{" + + "\"location\": \"London\"," + + "\"temp\": 15," + + "\"weather\": \"Cloudy\"" + + "}", Weather.class); + + assertEquals("London", weather.getLocation()); + assertEquals("Cloudy", weather.getOutlook()); + assertEquals(15, weather.getTemp()); + + weather = gson.fromJson("{" + + "\"place\": \"Lisbon\"," + + "\"temperature\": 35," + + "\"outlook\": \"Sunny\"" + + "}", Weather.class); + + assertEquals("Lisbon", weather.getLocation()); + assertEquals("Sunny", weather.getOutlook()); + assertEquals(35, weather.getTemp()); + + } +} diff --git a/guava-collections-set/.gitignore b/guava-collections-set/.gitignore new file mode 100644 index 0000000000..83c05e60c8 --- /dev/null +++ b/guava-collections-set/.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/guava-collections-set/pom.xml b/guava-collections-set/pom.xml new file mode 100644 index 0000000000..46dcae492d --- /dev/null +++ b/guava-collections-set/pom.xml @@ -0,0 +1,37 @@ + + 4.0.0 + com.baeldung + guava-collections-set + 0.1.0-SNAPSHOT + guava-collections-set + + + com.baeldung + parent-java + 0.0.1-SNAPSHOT + ../parent-java + + + + + + org.assertj + assertj-core + ${assertj.version} + test + + + + + guava-collections-set + + + + + 27.1-jre + + 3.6.1 + + + diff --git a/guava-collections-set/src/test/java/org/baeldung/guava/GuavaMultiSetUnitTest.java b/guava-collections-set/src/test/java/org/baeldung/guava/GuavaMultiSetUnitTest.java new file mode 100644 index 0000000000..e74db29881 --- /dev/null +++ b/guava-collections-set/src/test/java/org/baeldung/guava/GuavaMultiSetUnitTest.java @@ -0,0 +1,92 @@ +package org.baeldung.guava; + +import com.google.common.collect.HashMultiset; +import com.google.common.collect.Multiset; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +public class GuavaMultiSetUnitTest { + + @Test + public void givenMultiSet_whenAddingValues_shouldReturnCorrectCount() { + Multiset bookStore = HashMultiset.create(); + bookStore.add("Potter"); + bookStore.add("Potter"); + bookStore.add("Potter"); + + assertThat(bookStore.contains("Potter")).isTrue(); + assertThat(bookStore.count("Potter")).isEqualTo(3); + } + + @Test + public void givenMultiSet_whenRemovingValues_shouldReturnCorrectCount() { + Multiset bookStore = HashMultiset.create(); + bookStore.add("Potter"); + bookStore.add("Potter"); + + bookStore.remove("Potter"); + assertThat(bookStore.contains("Potter")).isTrue(); + assertThat(bookStore.count("Potter")).isEqualTo(1); + } + + @Test + public void givenMultiSet_whenSetCount_shouldReturnCorrectCount() { + Multiset bookStore = HashMultiset.create(); + bookStore.setCount("Potter", 50); + assertThat(bookStore.count("Potter")).isEqualTo(50); + } + + @Test + public void givenMultiSet_whenSettingNegativeCount_shouldThrowException() { + Multiset bookStore = HashMultiset.create(); + assertThatThrownBy(() -> bookStore.setCount("Potter", -1)) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + public void givenMultiSet_whenSettingCountWithEmptySet_shouldBeSuccessful() { + Multiset bookStore = HashMultiset.create(); + assertThat(bookStore.setCount("Potter", 0, 2)).isTrue(); + } + + @Test + public void givenMultiSet_whenSettingCountWithCorrectValue_shouldBeSuccessful() { + Multiset bookStore = HashMultiset.create(); + bookStore.add("Potter"); + bookStore.add("Potter"); + + assertThat(bookStore.setCount("Potter", 2, 52)).isTrue(); + } + + @Test + public void givenMultiSet_whenSettingCountWithIncorrectValue_shouldFail() { + Multiset bookStore = HashMultiset.create(); + bookStore.add("Potter"); + bookStore.add("Potter"); + + assertThat(bookStore.setCount("Potter", 5, 52)).isFalse(); + } + + @Test + public void givenMap_compareMultiSetOperations() { + Map bookStore = new HashMap<>(); + bookStore.put("Potter", 3); + + assertThat(bookStore.containsKey("Potter")).isTrue(); + assertThat(bookStore.get("Potter")).isEqualTo(3); + + bookStore.put("Potter", 2); + assertThat(bookStore.get("Potter")).isEqualTo(2); + + bookStore.put("Potter", null); + assertThat(bookStore.containsKey("Potter")).isTrue(); + + bookStore.put("Potter", -1); + assertThat(bookStore.containsKey("Potter")).isTrue(); + } +} \ No newline at end of file diff --git a/guava-modules/guava-18/README.md b/guava-modules/guava-18/README.md index 9924d7c16f..fd5de4170a 100644 --- a/guava-modules/guava-18/README.md +++ b/guava-modules/guava-18/README.md @@ -4,9 +4,5 @@ ### Relevant Articles: -- [Guava Collections Cookbook](http://www.baeldung.com/guava-collections) -- [Guava Ordering Cookbook](http://www.baeldung.com/guava-order) - [Guava Functional Cookbook](http://www.baeldung.com/guava-functions-predicates) -- [Hamcrest Collections Cookbook](http://www.baeldung.com/hamcrest-collections-arrays) -- [Partition a List in Java](http://www.baeldung.com/java-list-split) - [Guava 18: What’s New?](http://www.baeldung.com/whats-new-in-guava-18) diff --git a/guava-modules/guava-21/README.md b/guava-modules/guava-21/README.md index 68c1ac4a8e..4e897325b6 100644 --- a/guava-modules/guava-21/README.md +++ b/guava-modules/guava-21/README.md @@ -1,4 +1,4 @@ ### Relevant articles: -- [New Stream, Comparator and Collector Functionality in Guava 21](http://www.baeldung.com/guava-21-new) +- [New Stream, Comparator and Collector in Guava 21](http://www.baeldung.com/guava-21-new) - [New in Guava 21 common.util.concurrent](http://www.baeldung.com/guava-21-util-concurrent) - [Zipping Collections in Java](http://www.baeldung.com/java-collections-zip) diff --git a/helidon/helidon-mp/pom.xml b/helidon/helidon-mp/pom.xml index 1f39431886..82d52ca2ef 100644 --- a/helidon/helidon-mp/pom.xml +++ b/helidon/helidon-mp/pom.xml @@ -15,13 +15,18 @@ io.helidon.microprofile.bundles helidon-microprofile-1.2 - 0.10.4 + ${helidon-microprofile.version} org.glassfish.jersey.media jersey-media-json-binding - 2.26 + ${jersey-media-json-binding.version}
+ + 0.10.4 + 2.26 + + diff --git a/helidon/helidon-se/pom.xml b/helidon/helidon-se/pom.xml index 8982bf048e..ae16fa16e4 100644 --- a/helidon/helidon-se/pom.xml +++ b/helidon/helidon-se/pom.xml @@ -12,10 +12,6 @@ 1.0.0-SNAPSHOT - - 0.10.4 - - @@ -61,4 +57,8 @@ + + 0.10.4 + + \ No newline at end of file diff --git a/httpclient-simple/.gitignore b/httpclient-simple/.gitignore new file mode 100644 index 0000000000..83c05e60c8 --- /dev/null +++ b/httpclient-simple/.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-simple/README.md b/httpclient-simple/README.md new file mode 100644 index 0000000000..492f3bc5b4 --- /dev/null +++ b/httpclient-simple/README.md @@ -0,0 +1,16 @@ +========= +## HttpClient 4.x Cookbooks and Examples + +###The Course +The "REST With Spring" Classes: http://bit.ly/restwithspring + + +### Relevant Articles: + +- [HttpClient 4 – Get the Status Code](http://www.baeldung.com/httpclient-status-code) +- [HttpClient with SSL](http://www.baeldung.com/httpclient-ssl) +- [HttpClient Timeout](http://www.baeldung.com/httpclient-timeout) +- [HttpClient 4 – Send Custom Cookie](http://www.baeldung.com/httpclient-4-cookies) +- [Custom HTTP Header with the HttpClient](http://www.baeldung.com/httpclient-custom-http-header) +- [HttpClient Basic Authentication](http://www.baeldung.com/httpclient-4-basic-authentication) +- [Posting with HttpClient](https://www.baeldung.com/httpclient-post-http-request) diff --git a/httpclient-simple/pom.xml b/httpclient-simple/pom.xml new file mode 100644 index 0000000000..f3d00251d7 --- /dev/null +++ b/httpclient-simple/pom.xml @@ -0,0 +1,315 @@ + + 4.0.0 + com.baeldung + httpclient-simple + 0.1-SNAPSHOT + httpclient-simple + war + + + com.baeldung + parent-spring-5 + 0.0.1-SNAPSHOT + ../parent-spring-5 + + + + + + + + org.springframework.security + spring-security-web + ${spring.version} + + + org.springframework.security + spring-security-config + ${spring.version} + + + + + + org.springframework + spring-core + ${spring.version} + + + commons-logging + commons-logging + + + + + org.springframework + spring-context + ${spring.version} + + + org.springframework + spring-jdbc + ${spring.version} + + + org.springframework + spring-beans + ${spring.version} + + + org.springframework + spring-aop + ${spring.version} + + + org.springframework + spring-tx + ${spring.version} + + + org.springframework + spring-expression + ${spring.version} + + + + org.springframework + spring-web + ${spring.version} + + + org.springframework + spring-webmvc + ${spring.version} + + + + org.springframework + spring-oxm + ${spring.version} + + + + + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} + + + + org.apache.httpcomponents + httpcore + ${httpcore.version} + + + commons-logging + commons-logging + + + + + + + org.apache.commons + commons-lang3 + ${commons-lang3.version} + + + + org.apache.httpcomponents + httpclient + ${httpclient.version} + + + commons-logging + commons-logging + + + + + org.apache.httpcomponents + fluent-hc + ${httpclient.version} + + + commons-logging + commons-logging + + + + + org.apache.httpcomponents + httpmime + ${httpclient.version} + + + commons-codec + commons-codec + ${commons-codec.version} + + + org.apache.httpcomponents + httpasyncclient + ${httpasyncclient.version} + + + commons-logging + commons-logging + + + + + com.github.tomakehurst + wiremock + ${wiremock.version} + test + + + + + + javax.servlet + javax.servlet-api + ${javax.servlet.version} + provided + + + + javax.servlet + jstl + ${jstl.version} + runtime + + + + + + com.google.guava + guava + ${guava.version} + + + + + + org.springframework + spring-test + ${spring.version} + test + + + + + httpclient-simple + + + src/main/resources + true + + + + + + org.apache.maven.plugins + maven-war-plugin + ${maven-war-plugin.version} + + + org.codehaus.cargo + cargo-maven2-plugin + ${cargo-maven2-plugin.version} + + true + + jetty8x + embedded + + + + + + + 8082 + + + + + + + + + + live + + + + org.codehaus.cargo + cargo-maven2-plugin + + + start-server + pre-integration-test + + start + + + + stop-server + post-integration-test + + stop + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + integration-test + + test + + + + none + + + **/*LiveTest.java + + + cargo + + + + + + + + + + + + + + 1.2 + 3.1.0 + + 19.0 + 3.5 + 1.10 + 4.1.4 + + 2.5.1 + 4.4.11 + 4.5.8 + + 2.6 + 1.6.1 + + + \ No newline at end of file diff --git a/httpclient-simple/src/main/java/org/baeldung/basic/MyBasicAuthenticationEntryPoint.java b/httpclient-simple/src/main/java/org/baeldung/basic/MyBasicAuthenticationEntryPoint.java new file mode 100644 index 0000000000..6e580e7a22 --- /dev/null +++ b/httpclient-simple/src/main/java/org/baeldung/basic/MyBasicAuthenticationEntryPoint.java @@ -0,0 +1,30 @@ +package org.baeldung.basic; + +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint; +import org.springframework.stereotype.Component; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.PrintWriter; + +@Component +public class MyBasicAuthenticationEntryPoint extends BasicAuthenticationEntryPoint { + + @Override + public void commence(final HttpServletRequest request, final HttpServletResponse response, final AuthenticationException authException) throws IOException, ServletException { + response.addHeader("WWW-Authenticate", "Basic realm=\"" + getRealmName() + "\""); + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + final PrintWriter writer = response.getWriter(); + writer.println("HTTP Status " + HttpServletResponse.SC_UNAUTHORIZED + " - " + authException.getMessage()); + } + + @Override + public void afterPropertiesSet() throws Exception { + setRealmName("Baeldung"); + super.afterPropertiesSet(); + } + +} diff --git a/httpclient-simple/src/main/java/org/baeldung/client/HttpComponentsClientHttpRequestFactoryBasicAuth.java b/httpclient-simple/src/main/java/org/baeldung/client/HttpComponentsClientHttpRequestFactoryBasicAuth.java new file mode 100644 index 0000000000..a2f51d343b --- /dev/null +++ b/httpclient-simple/src/main/java/org/baeldung/client/HttpComponentsClientHttpRequestFactoryBasicAuth.java @@ -0,0 +1,39 @@ +package org.baeldung.client; + +import java.net.URI; + +import org.apache.http.HttpHost; +import org.apache.http.client.AuthCache; +import org.apache.http.client.protocol.HttpClientContext; +import org.apache.http.impl.auth.BasicScheme; +import org.apache.http.impl.client.BasicAuthCache; +import org.apache.http.protocol.BasicHttpContext; +import org.apache.http.protocol.HttpContext; +import org.springframework.http.HttpMethod; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; + +public class HttpComponentsClientHttpRequestFactoryBasicAuth extends HttpComponentsClientHttpRequestFactory { + + HttpHost host; + + public HttpComponentsClientHttpRequestFactoryBasicAuth(HttpHost host) { + super(); + this.host = host; + } + + protected HttpContext createHttpContext(HttpMethod httpMethod, URI uri) { + return createHttpContext(); + } + + private HttpContext createHttpContext() { + + AuthCache authCache = new BasicAuthCache(); + + BasicScheme basicAuth = new BasicScheme(); + authCache.put(host, basicAuth); + + BasicHttpContext localcontext = new BasicHttpContext(); + localcontext.setAttribute(HttpClientContext.AUTH_CACHE, authCache); + return localcontext; + } +} \ No newline at end of file diff --git a/httpclient-simple/src/main/java/org/baeldung/client/RestTemplateFactory.java b/httpclient-simple/src/main/java/org/baeldung/client/RestTemplateFactory.java new file mode 100644 index 0000000000..3ed0bc82b7 --- /dev/null +++ b/httpclient-simple/src/main/java/org/baeldung/client/RestTemplateFactory.java @@ -0,0 +1,44 @@ +package org.baeldung.client; + +import org.apache.http.HttpHost; +import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.http.client.ClientHttpRequestFactory; +import org.springframework.http.client.support.BasicAuthenticationInterceptor; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + +@Component +public class RestTemplateFactory implements FactoryBean, InitializingBean { + private RestTemplate restTemplate; + + public RestTemplateFactory() { + super(); + } + + // API + + @Override + public RestTemplate getObject() { + return restTemplate; + } + + @Override + public Class getObjectType() { + return RestTemplate.class; + } + + @Override + public boolean isSingleton() { + return true; + } + + @Override + public void afterPropertiesSet() { + HttpHost host = new HttpHost("localhost", 8082, "http"); + final ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactoryBasicAuth(host); + restTemplate = new RestTemplate(requestFactory); + restTemplate.getInterceptors().add(new BasicAuthenticationInterceptor("user1", "user1Pass")); + } + +} \ No newline at end of file diff --git a/httpclient-simple/src/main/java/org/baeldung/client/spring/ClientConfig.java b/httpclient-simple/src/main/java/org/baeldung/client/spring/ClientConfig.java new file mode 100644 index 0000000000..73e602855c --- /dev/null +++ b/httpclient-simple/src/main/java/org/baeldung/client/spring/ClientConfig.java @@ -0,0 +1,16 @@ +package org.baeldung.client.spring; + +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ComponentScan("org.baeldung.client") +public class ClientConfig { + + public ClientConfig() { + super(); + } + + // beans + +} \ No newline at end of file diff --git a/httpclient-simple/src/main/java/org/baeldung/filter/CustomFilter.java b/httpclient-simple/src/main/java/org/baeldung/filter/CustomFilter.java new file mode 100644 index 0000000000..01e5b0b59d --- /dev/null +++ b/httpclient-simple/src/main/java/org/baeldung/filter/CustomFilter.java @@ -0,0 +1,18 @@ +package org.baeldung.filter; + +import org.springframework.web.filter.GenericFilterBean; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import java.io.IOException; + +public class CustomFilter extends GenericFilterBean { + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + chain.doFilter(request, response); + } + +} diff --git a/httpclient-simple/src/main/java/org/baeldung/filter/CustomWebSecurityConfigurerAdapter.java b/httpclient-simple/src/main/java/org/baeldung/filter/CustomWebSecurityConfigurerAdapter.java new file mode 100644 index 0000000000..7ca2a80c52 --- /dev/null +++ b/httpclient-simple/src/main/java/org/baeldung/filter/CustomWebSecurityConfigurerAdapter.java @@ -0,0 +1,49 @@ +package org.baeldung.filter; + +import org.baeldung.security.RestAuthenticationEntryPoint; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +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.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; + +@Configuration +@EnableWebSecurity +public class CustomWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter { + + @Autowired private RestAuthenticationEntryPoint authenticationEntryPoint; + + @Autowired + public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { + auth + .inMemoryAuthentication() + .withUser("user1") + .password(passwordEncoder().encode("user1Pass")) + .authorities("ROLE_USER"); + } + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + .authorizeRequests() + .antMatchers("/securityNone") + .permitAll() + .anyRequest() + .authenticated() + .and() + .httpBasic() + .authenticationEntryPoint(authenticationEntryPoint); + + http.addFilterAfter(new CustomFilter(), BasicAuthenticationFilter.class); + } + + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } +} diff --git a/httpclient-simple/src/main/java/org/baeldung/security/MySavedRequestAwareAuthenticationSuccessHandler.java b/httpclient-simple/src/main/java/org/baeldung/security/MySavedRequestAwareAuthenticationSuccessHandler.java new file mode 100644 index 0000000000..698052fa2b --- /dev/null +++ b/httpclient-simple/src/main/java/org/baeldung/security/MySavedRequestAwareAuthenticationSuccessHandler.java @@ -0,0 +1,48 @@ +package org.baeldung.security; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.security.core.Authentication; +import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler; +import org.springframework.security.web.savedrequest.HttpSessionRequestCache; +import org.springframework.security.web.savedrequest.RequestCache; +import org.springframework.security.web.savedrequest.SavedRequest; +import org.springframework.util.StringUtils; + +public class MySavedRequestAwareAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler { + + private RequestCache requestCache = new HttpSessionRequestCache(); + + @Override + public void onAuthenticationSuccess(final HttpServletRequest request, final HttpServletResponse response, final Authentication authentication) throws ServletException, IOException { + final SavedRequest savedRequest = requestCache.getRequest(request, response); + + if (savedRequest == null) { + super.onAuthenticationSuccess(request, response, authentication); + + return; + } + final String targetUrlParameter = getTargetUrlParameter(); + if (isAlwaysUseDefaultTargetUrl() || (targetUrlParameter != null && StringUtils.hasText(request.getParameter(targetUrlParameter)))) { + requestCache.removeRequest(request, response); + super.onAuthenticationSuccess(request, response, authentication); + + return; + } + + clearAuthenticationAttributes(request); + + // Use the DefaultSavedRequest URL + // final String targetUrl = savedRequest.getRedirectUrl(); + // logger.debug("Redirecting to DefaultSavedRequest Url: " + targetUrl); + // getRedirectStrategy().sendRedirect(request, response, targetUrl); + } + + public void setRequestCache(final RequestCache requestCache) { + this.requestCache = requestCache; + } +} diff --git a/httpclient-simple/src/main/java/org/baeldung/security/RestAuthenticationEntryPoint.java b/httpclient-simple/src/main/java/org/baeldung/security/RestAuthenticationEntryPoint.java new file mode 100644 index 0000000000..77aa32ff97 --- /dev/null +++ b/httpclient-simple/src/main/java/org/baeldung/security/RestAuthenticationEntryPoint.java @@ -0,0 +1,23 @@ +package org.baeldung.security; + +import java.io.IOException; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.stereotype.Component; + +/** + * The Entry Point will not redirect to any sort of Login - it will return the 401 + */ +@Component +public final class RestAuthenticationEntryPoint implements AuthenticationEntryPoint { + + @Override + public void commence(final HttpServletRequest request, final HttpServletResponse response, final AuthenticationException authException) throws IOException { + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized"); + } + +} \ No newline at end of file diff --git a/httpclient-simple/src/main/java/org/baeldung/spring/SecSecurityConfig.java b/httpclient-simple/src/main/java/org/baeldung/spring/SecSecurityConfig.java new file mode 100644 index 0000000000..4ce80dab9f --- /dev/null +++ b/httpclient-simple/src/main/java/org/baeldung/spring/SecSecurityConfig.java @@ -0,0 +1,16 @@ +package org.baeldung.spring; + +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.ImportResource; + +@Configuration +@ImportResource({ "classpath:webSecurityConfig.xml" }) +@ComponentScan("org.baeldung.security") +public class SecSecurityConfig { + + public SecSecurityConfig() { + super(); + } + +} diff --git a/httpclient-simple/src/main/java/org/baeldung/spring/WebConfig.java b/httpclient-simple/src/main/java/org/baeldung/spring/WebConfig.java new file mode 100644 index 0000000000..5876e1307b --- /dev/null +++ b/httpclient-simple/src/main/java/org/baeldung/spring/WebConfig.java @@ -0,0 +1,30 @@ +package org.baeldung.spring; + +import java.util.List; + +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +@EnableWebMvc +@ComponentScan("org.baeldung.web") +public class WebConfig implements WebMvcConfigurer { + + public WebConfig() { + super(); + } + + // beans + + @Override + public void configureMessageConverters(final List> converters) { + converters.add(new MappingJackson2HttpMessageConverter()); + } + + // + +} \ No newline at end of file diff --git a/httpclient-simple/src/main/java/org/baeldung/web/controller/BarController.java b/httpclient-simple/src/main/java/org/baeldung/web/controller/BarController.java new file mode 100644 index 0000000000..2bc314baa2 --- /dev/null +++ b/httpclient-simple/src/main/java/org/baeldung/web/controller/BarController.java @@ -0,0 +1,31 @@ +package org.baeldung.web.controller; + +import org.baeldung.web.dto.Bar; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseBody; + +@Controller +@RequestMapping(value = "/bars") +public class BarController { + + @Autowired + private ApplicationEventPublisher eventPublisher; + + public BarController() { + super(); + } + + // API + + @RequestMapping(value = "/{id}", method = RequestMethod.GET) + @ResponseBody + public Bar findOne(@PathVariable("id") final Long id) { + return new Bar(); + } + +} diff --git a/httpclient-simple/src/main/java/org/baeldung/web/controller/FooController.java b/httpclient-simple/src/main/java/org/baeldung/web/controller/FooController.java new file mode 100644 index 0000000000..b50edb2dcf --- /dev/null +++ b/httpclient-simple/src/main/java/org/baeldung/web/controller/FooController.java @@ -0,0 +1,33 @@ +package org.baeldung.web.controller; + +import org.baeldung.web.dto.Foo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseBody; + +@Controller +@RequestMapping(value = "/foos") +public class FooController { + + @Autowired + private ApplicationEventPublisher eventPublisher; + + public FooController() { + super(); + } + + // API + + @RequestMapping(value = "/{id}", method = RequestMethod.GET) + @ResponseBody + @PreAuthorize("hasRole('ROLE_USER')") + public Foo findOne(@PathVariable("id") final Long id) { + return new Foo(); + } + +} diff --git a/httpclient-simple/src/main/java/org/baeldung/web/dto/Bar.java b/httpclient-simple/src/main/java/org/baeldung/web/dto/Bar.java new file mode 100644 index 0000000000..d33e39a823 --- /dev/null +++ b/httpclient-simple/src/main/java/org/baeldung/web/dto/Bar.java @@ -0,0 +1,14 @@ +package org.baeldung.web.dto; + +import java.io.Serializable; + +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement +public class Bar implements Serializable { + + public Bar() { + super(); + } + +} diff --git a/httpclient-simple/src/main/java/org/baeldung/web/dto/Foo.java b/httpclient-simple/src/main/java/org/baeldung/web/dto/Foo.java new file mode 100644 index 0000000000..09c1dac933 --- /dev/null +++ b/httpclient-simple/src/main/java/org/baeldung/web/dto/Foo.java @@ -0,0 +1,14 @@ +package org.baeldung.web.dto; + +import java.io.Serializable; + +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement +public class Foo implements Serializable { + + public Foo() { + super(); + } + +} diff --git a/httpclient-simple/src/main/resources/logback.xml b/httpclient-simple/src/main/resources/logback.xml new file mode 100644 index 0000000000..56af2d397e --- /dev/null +++ b/httpclient-simple/src/main/resources/logback.xml @@ -0,0 +1,19 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + + + + + \ No newline at end of file diff --git a/httpclient-simple/src/main/resources/webSecurityConfig.xml b/httpclient-simple/src/main/resources/webSecurityConfig.xml new file mode 100644 index 0000000000..a93dc841b6 --- /dev/null +++ b/httpclient-simple/src/main/resources/webSecurityConfig.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/httpclient-simple/src/main/webapp/WEB-INF/api-servlet.xml b/httpclient-simple/src/main/webapp/WEB-INF/api-servlet.xml new file mode 100644 index 0000000000..1dbff70b83 --- /dev/null +++ b/httpclient-simple/src/main/webapp/WEB-INF/api-servlet.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/httpclient-simple/src/main/webapp/WEB-INF/web.xml b/httpclient-simple/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000000..83b4aeb0a7 --- /dev/null +++ b/httpclient-simple/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,43 @@ + + + + Spring Security Custom Application + + + + contextClass + org.springframework.web.context.support.AnnotationConfigWebApplicationContext + + + contextConfigLocation + org.baeldung.spring + + + + org.springframework.web.context.ContextLoaderListener + + + + + api + org.springframework.web.servlet.DispatcherServlet + 1 + + + api + /api/* + + + + + springSecurityFilterChain + org.springframework.web.filter.DelegatingFilterProxy + + + springSecurityFilterChain + /* + + + \ No newline at end of file diff --git a/spring-security-rest-basic-auth/src/test/java/org/baeldung/client/ClientLiveTest.java b/httpclient-simple/src/test/java/org/baeldung/client/ClientLiveTest.java similarity index 88% rename from spring-security-rest-basic-auth/src/test/java/org/baeldung/client/ClientLiveTest.java rename to httpclient-simple/src/test/java/org/baeldung/client/ClientLiveTest.java index 2a668f827a..286ee3c900 100644 --- a/spring-security-rest-basic-auth/src/test/java/org/baeldung/client/ClientLiveTest.java +++ b/httpclient-simple/src/test/java/org/baeldung/client/ClientLiveTest.java @@ -33,13 +33,13 @@ public class ClientLiveTest { @Test public final void whenSecuredRestApiIsConsumed_then200OK() { - final ResponseEntity responseEntity = secureRestTemplate.exchange("http://localhost:8082/spring-security-rest-basic-auth/api/foos/1", HttpMethod.GET, null, Foo.class); + final ResponseEntity responseEntity = secureRestTemplate.exchange("http://localhost:8082/httpclient-simple/api/foos/1", HttpMethod.GET, null, Foo.class); assertThat(responseEntity.getStatusCode().value(), is(200)); } @Test(expected = ResourceAccessException.class) public final void whenHttpsUrlIsConsumed_thenException() { - final String urlOverHttps = "https://localhost:8443/spring-security-rest-basic-auth/api/bars/1"; + final String urlOverHttps = "https://localhost:8443/httpclient-simple/api/bars/1"; final ResponseEntity response = new RestTemplate().exchange(urlOverHttps, HttpMethod.GET, null, String.class); assertThat(response.getStatusCode().value(), equalTo(200)); } diff --git a/spring-security-rest-basic-auth/src/test/java/org/baeldung/client/RestClientLiveManualTest.java b/httpclient-simple/src/test/java/org/baeldung/client/RestClientLiveManualTest.java similarity index 60% rename from spring-security-rest-basic-auth/src/test/java/org/baeldung/client/RestClientLiveManualTest.java rename to httpclient-simple/src/test/java/org/baeldung/client/RestClientLiveManualTest.java index 104129b663..696d414ae7 100644 --- a/spring-security-rest-basic-auth/src/test/java/org/baeldung/client/RestClientLiveManualTest.java +++ b/httpclient-simple/src/test/java/org/baeldung/client/RestClientLiveManualTest.java @@ -8,19 +8,24 @@ import java.io.IOException; import java.security.GeneralSecurityException; import java.security.cert.X509Certificate; -import javax.net.ssl.SSLException; -import javax.net.ssl.SSLPeerUnverifiedException; +import javax.net.ssl.SSLContext; import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.HttpGet; +import org.apache.http.config.Registry; +import org.apache.http.config.RegistryBuilder; import org.apache.http.conn.scheme.Scheme; +import org.apache.http.conn.socket.ConnectionSocketFactory; +import org.apache.http.conn.socket.PlainConnectionSocketFactory; import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.conn.ssl.SSLSocketFactory; import org.apache.http.conn.ssl.TrustStrategy; import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.impl.client.HttpClients; +import org.apache.http.impl.conn.BasicHttpClientConnectionManager; +import org.apache.http.ssl.SSLContexts; import org.junit.Ignore; import org.junit.Test; import org.springframework.http.HttpMethod; @@ -34,29 +39,47 @@ import org.springframework.web.client.RestTemplate; * */ public class RestClientLiveManualTest { - final String urlOverHttps = "http://localhost:8082/spring-security-rest-basic-auth/api/bars/1"; + final String urlOverHttps = "http://localhost:8082/httpclient-simple/api/bars/1"; // tests // old httpClient will throw UnsupportedOperationException @Ignore @Test - public final void givenAcceptingAllCertificates_whenHttpsUrlIsConsumed_thenException() throws GeneralSecurityException { + public final void givenAcceptingAllCertificates_whenHttpsUrlIsConsumed_thenOk_1() throws GeneralSecurityException { final HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(); final CloseableHttpClient httpClient = (CloseableHttpClient) requestFactory.getHttpClient(); - final TrustStrategy acceptingTrustStrategy = new TrustStrategy() { - @Override - public final boolean isTrusted(final X509Certificate[] certificate, final String authType) { - return true; - } - }; + final TrustStrategy acceptingTrustStrategy = (cert, authType) -> true; final SSLSocketFactory sf = new SSLSocketFactory(acceptingTrustStrategy, ALLOW_ALL_HOSTNAME_VERIFIER); httpClient.getConnectionManager().getSchemeRegistry().register(new Scheme("https", 8443, sf)); final ResponseEntity response = new RestTemplate(requestFactory).exchange(urlOverHttps, HttpMethod.GET, null, String.class); assertThat(response.getStatusCode().value(), equalTo(200)); } + + // new httpClient : 4.4 and above + @Test + public final void givenAcceptingAllCertificates_whenHttpsUrlIsConsumed_thenOk_2() throws GeneralSecurityException { + + final TrustStrategy acceptingTrustStrategy = (cert, authType) -> true; + final SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build(); + final SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE); + final Registry socketFactoryRegistry = RegistryBuilder. create() + .register("https", sslsf) + .register("http", new PlainConnectionSocketFactory()) + .build(); + + final BasicHttpClientConnectionManager connectionManager = new BasicHttpClientConnectionManager(socketFactoryRegistry); + final CloseableHttpClient httpClient = HttpClients.custom() + .setSSLSocketFactory(sslsf) + .setConnectionManager(connectionManager) + .build(); + + final HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient); + final ResponseEntity response = new RestTemplate(requestFactory).exchange(urlOverHttps, HttpMethod.GET, null, String.class); + assertThat(response.getStatusCode().value(), equalTo(200)); + } @Test public final void givenAcceptingAllCertificatesUsing4_4_whenHttpsUrlIsConsumed_thenCorrect() throws ClientProtocolException, IOException { diff --git a/httpclient/src/test/java/org/baeldung/httpclient/HttpClientHeadersLiveTest.java b/httpclient-simple/src/test/java/org/baeldung/httpclient/HttpClientHeadersLiveTest.java similarity index 100% rename from httpclient/src/test/java/org/baeldung/httpclient/HttpClientHeadersLiveTest.java rename to httpclient-simple/src/test/java/org/baeldung/httpclient/HttpClientHeadersLiveTest.java diff --git a/httpclient/src/test/java/org/baeldung/httpclient/HttpClientPostingLiveTest.java b/httpclient-simple/src/test/java/org/baeldung/httpclient/HttpClientPostingLiveTest.java similarity index 100% rename from httpclient/src/test/java/org/baeldung/httpclient/HttpClientPostingLiveTest.java rename to httpclient-simple/src/test/java/org/baeldung/httpclient/HttpClientPostingLiveTest.java diff --git a/httpclient/src/test/java/org/baeldung/httpclient/HttpClientTimeoutLiveTest.java b/httpclient-simple/src/test/java/org/baeldung/httpclient/HttpClientTimeoutLiveTest.java similarity index 60% rename from httpclient/src/test/java/org/baeldung/httpclient/HttpClientTimeoutLiveTest.java rename to httpclient-simple/src/test/java/org/baeldung/httpclient/HttpClientTimeoutLiveTest.java index 74255e416c..8041080b3d 100644 --- a/httpclient/src/test/java/org/baeldung/httpclient/HttpClientTimeoutLiveTest.java +++ b/httpclient-simple/src/test/java/org/baeldung/httpclient/HttpClientTimeoutLiveTest.java @@ -1,20 +1,27 @@ package org.baeldung.httpclient; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.config.SocketConfig; -import org.apache.http.conn.HttpHostConnectException; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClientBuilder; -import org.junit.After; -import org.junit.Test; - -import java.io.IOException; - import static org.hamcrest.Matchers.equalTo; import static org.junit.Assert.assertThat; +import java.io.IOException; +import java.util.Timer; +import java.util.TimerTask; + +import org.apache.http.HttpResponse; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.params.ClientPNames; +import org.apache.http.config.SocketConfig; +import org.apache.http.conn.ConnectTimeoutException; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.params.CoreConnectionPNames; +import org.apache.http.params.HttpParams; +import org.junit.After; +import org.junit.Test; + public class HttpClientTimeoutLiveTest { private CloseableHttpResponse response; @@ -25,6 +32,20 @@ public class HttpClientTimeoutLiveTest { } // tests + @Test + public final void givenUsingOldApi_whenSettingTimeoutViaParameter_thenCorrect() throws IOException { + + DefaultHttpClient httpClient = new DefaultHttpClient(); + int timeout = 5; // seconds + HttpParams httpParams = httpClient.getParams(); + httpParams.setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, timeout * 1000); + httpParams.setParameter(CoreConnectionPNames.SO_TIMEOUT, timeout * 1000); + httpParams.setParameter(ClientPNames.CONN_MANAGER_TIMEOUT, new Long(timeout * 1000)); + + final HttpGet request = new HttpGet("http://www.github.com"); + HttpResponse execute = httpClient.execute(request); + assertThat(execute.getStatusLine().getStatusCode(), equalTo(200)); + } @Test public final void givenUsingNewApi_whenSettingTimeoutViaRequestConfig_thenCorrect() throws IOException { @@ -33,8 +54,6 @@ public class HttpClientTimeoutLiveTest { final CloseableHttpClient client = HttpClientBuilder.create().setDefaultRequestConfig(config).build(); final HttpGet request = new HttpGet("http://www.github.com"); - // httpParams.setLongParameter(ClientPNames.CONN_MANAGER_TIMEOUT, new Long(timeout * 1000)); // https://issues.apache.org/jira/browse/HTTPCLIENT-1418 - response = client.execute(request); assertThat(response.getStatusLine().getStatusCode(), equalTo(200)); @@ -71,7 +90,7 @@ public class HttpClientTimeoutLiveTest { /** * This simulates a timeout against a domain with multiple routes/IPs to it (not a single raw IP) */ - @Test(expected = HttpHostConnectException.class) + @Test(expected = ConnectTimeoutException.class) public final void givenTimeoutIsConfigured_whenTimingOut_thenTimeoutException() throws IOException { final int timeout = 3; @@ -81,5 +100,28 @@ public class HttpClientTimeoutLiveTest { final HttpGet request = new HttpGet("http://www.google.com:81"); client.execute(request); } + + @Test + public void whenSecuredRestApiIsConsumed_then200OK() throws IOException { + CloseableHttpClient httpClient = HttpClientBuilder.create().build(); + int timeout = 20; // seconds + RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(timeout * 1000) + .setConnectTimeout(timeout * 1000).setSocketTimeout(timeout * 1000).build(); + HttpGet getMethod = new HttpGet("http://localhost:8082/httpclient-simple/api/bars/1"); + getMethod.setConfig(requestConfig); + + int hardTimeout = 5; // seconds + TimerTask task = new TimerTask() { + @Override + public void run() { + getMethod.abort(); + } + }; + new Timer(true).schedule(task, hardTimeout * 1000); + + HttpResponse response = httpClient.execute(getMethod); + System.out.println("HTTP Status of response: " + response.getStatusLine().getStatusCode()); + } + } diff --git a/httpclient/src/test/java/org/baeldung/httpclient/HttpsClientSslLiveTest.java b/httpclient-simple/src/test/java/org/baeldung/httpclient/HttpsClientSslLiveTest.java similarity index 82% rename from httpclient/src/test/java/org/baeldung/httpclient/HttpsClientSslLiveTest.java rename to httpclient-simple/src/test/java/org/baeldung/httpclient/HttpsClientSslLiveTest.java index 4eadfe24d5..9e95905c70 100644 --- a/httpclient/src/test/java/org/baeldung/httpclient/HttpsClientSslLiveTest.java +++ b/httpclient-simple/src/test/java/org/baeldung/httpclient/HttpsClientSslLiveTest.java @@ -1,32 +1,31 @@ package org.baeldung.httpclient; -import org.apache.http.HttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.conn.ClientConnectionManager; -import org.apache.http.conn.scheme.Scheme; -import org.apache.http.conn.scheme.SchemeRegistry; -import org.apache.http.conn.ssl.NoopHostnameVerifier; -import org.apache.http.conn.ssl.SSLConnectionSocketFactory; -import org.apache.http.conn.ssl.SSLSocketFactory; -import org.apache.http.conn.ssl.TrustSelfSignedStrategy; -import org.apache.http.conn.ssl.TrustStrategy; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.impl.conn.PoolingClientConnectionManager; -import org.apache.http.ssl.SSLContextBuilder; -import org.apache.http.ssl.SSLContexts; -import org.junit.Test; - -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLHandshakeException; -import java.io.IOException; -import java.security.GeneralSecurityException; - import static org.hamcrest.CoreMatchers.equalTo; import static org.junit.Assert.assertThat; +import java.io.IOException; +import java.security.GeneralSecurityException; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLHandshakeException; + +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.config.Registry; +import org.apache.http.config.RegistryBuilder; +import org.apache.http.conn.socket.ConnectionSocketFactory; +import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.conn.ssl.TrustSelfSignedStrategy; +import org.apache.http.conn.ssl.TrustStrategy; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.apache.http.ssl.SSLContextBuilder; +import org.apache.http.ssl.SSLContexts; +import org.junit.Test; + /** * This test requires a localhost server over HTTPS
* It should only be manually run, not part of the automated build @@ -50,16 +49,22 @@ public class HttpsClientSslLiveTest { .getStatusCode(), equalTo(200)); } - @SuppressWarnings("deprecation") @Test public final void givenHttpClientPre4_3_whenAcceptingAllCertificates_thenCanConsumeHttpsUriWithSelfSignedCertificate() throws IOException, GeneralSecurityException { final TrustStrategy acceptingTrustStrategy = (certificate, authType) -> true; - final SSLSocketFactory sf = new SSLSocketFactory(acceptingTrustStrategy, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); - final SchemeRegistry registry = new SchemeRegistry(); - registry.register(new Scheme("https", 443, sf)); - final ClientConnectionManager ccm = new PoolingClientConnectionManager(registry); + + final SSLContext sslContext = SSLContexts.custom() + .loadTrustMaterial(null, acceptingTrustStrategy) + .build(); - final CloseableHttpClient httpClient = new DefaultHttpClient(ccm); + final SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE); + Registry socketFactoryRegistry = RegistryBuilder. create().register("https", sslsf).build(); + PoolingHttpClientConnectionManager clientConnectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry); + + final CloseableHttpClient httpClient = HttpClients.custom() + .setSSLSocketFactory(sslsf) + .setConnectionManager(clientConnectionManager) + .build(); final HttpGet getMethod = new HttpGet(HOST_WITH_SSL); final HttpResponse response = httpClient.execute(getMethod); @@ -76,10 +81,9 @@ public class HttpsClientSslLiveTest { .loadTrustMaterial(null, acceptingTrustStrategy) .build(); - final SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); + final SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE); final CloseableHttpClient httpClient = HttpClients.custom() - .setHostnameVerifier(SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER) .setSSLSocketFactory(sslsf) .build(); diff --git a/httpclient/src/test/java/org/baeldung/httpclient/ProgressEntityWrapper.java b/httpclient-simple/src/test/java/org/baeldung/httpclient/ProgressEntityWrapper.java similarity index 100% rename from httpclient/src/test/java/org/baeldung/httpclient/ProgressEntityWrapper.java rename to httpclient-simple/src/test/java/org/baeldung/httpclient/ProgressEntityWrapper.java diff --git a/httpclient-simple/src/test/java/org/baeldung/httpclient/ResponseUtil.java b/httpclient-simple/src/test/java/org/baeldung/httpclient/ResponseUtil.java new file mode 100644 index 0000000000..fd38b95cbe --- /dev/null +++ b/httpclient-simple/src/test/java/org/baeldung/httpclient/ResponseUtil.java @@ -0,0 +1,26 @@ +package org.baeldung.httpclient; + +import org.apache.http.HttpEntity; +import org.apache.http.client.methods.CloseableHttpResponse; + +import java.io.IOException; + +public final class ResponseUtil { + private ResponseUtil() { + } + + public static void closeResponse(CloseableHttpResponse response) throws IOException { + if (response == null) { + return; + } + + try { + final HttpEntity entity = response.getEntity(); + if (entity != null) { + entity.getContent().close(); + } + } finally { + response.close(); + } + } +} diff --git a/httpclient/src/test/java/org/baeldung/httpclient/base/HttpClientBasicLiveTest.java b/httpclient-simple/src/test/java/org/baeldung/httpclient/base/HttpClientBasicLiveTest.java similarity index 100% rename from httpclient/src/test/java/org/baeldung/httpclient/base/HttpClientBasicLiveTest.java rename to httpclient-simple/src/test/java/org/baeldung/httpclient/base/HttpClientBasicLiveTest.java diff --git a/httpclient/src/test/java/org/baeldung/httpclient/sec/HttpClientAuthLiveTest.java b/httpclient-simple/src/test/java/org/baeldung/httpclient/sec/HttpClientAuthLiveTest.java similarity index 96% rename from httpclient/src/test/java/org/baeldung/httpclient/sec/HttpClientAuthLiveTest.java rename to httpclient-simple/src/test/java/org/baeldung/httpclient/sec/HttpClientAuthLiveTest.java index c9956e5852..96278b481a 100644 --- a/httpclient/src/test/java/org/baeldung/httpclient/sec/HttpClientAuthLiveTest.java +++ b/httpclient-simple/src/test/java/org/baeldung/httpclient/sec/HttpClientAuthLiveTest.java @@ -23,19 +23,18 @@ import org.junit.Before; import org.junit.Test; import java.io.IOException; -import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import static org.hamcrest.Matchers.equalTo; import static org.junit.Assert.assertThat; /* - * NOTE : Need module spring-security-rest-basic-auth to be running + * NOTE : Need module httpclient-simple to be running */ public class HttpClientAuthLiveTest { - private static final String URL_SECURED_BY_BASIC_AUTHENTICATION = "http://localhost:8081/spring-security-rest-basic-auth/api/foos/1"; + private static final String URL_SECURED_BY_BASIC_AUTHENTICATION = "http://localhost:8082/httpclient-simple/api/foos/1"; private static final String DEFAULT_USER = "user1"; private static final String DEFAULT_PASS = "user1Pass"; @@ -111,7 +110,7 @@ public class HttpClientAuthLiveTest { } private HttpContext context() { - final HttpHost targetHost = new HttpHost("localhost", 8080, "http"); + final HttpHost targetHost = new HttpHost("localhost", 8082, "http"); final CredentialsProvider credsProvider = new BasicCredentialsProvider(); credsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(DEFAULT_USER, DEFAULT_PASS)); diff --git a/httpclient/src/test/java/org/baeldung/httpclient/sec/HttpClientCookieLiveTest.java b/httpclient-simple/src/test/java/org/baeldung/httpclient/sec/HttpClientCookieLiveTest.java similarity index 100% rename from httpclient/src/test/java/org/baeldung/httpclient/sec/HttpClientCookieLiveTest.java rename to httpclient-simple/src/test/java/org/baeldung/httpclient/sec/HttpClientCookieLiveTest.java diff --git a/spring-security-rest-basic-auth/src/test/java/org/baeldung/test/LiveTestSuite.java b/httpclient-simple/src/test/java/org/baeldung/test/LiveTestSuite.java similarity index 100% rename from spring-security-rest-basic-auth/src/test/java/org/baeldung/test/LiveTestSuite.java rename to httpclient-simple/src/test/java/org/baeldung/test/LiveTestSuite.java diff --git a/httpclient-simple/src/test/resources/.gitignore b/httpclient-simple/src/test/resources/.gitignore new file mode 100644 index 0000000000..83c05e60c8 --- /dev/null +++ b/httpclient-simple/src/test/resources/.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/README.md b/httpclient/README.md index 7c5122c5b8..a5fc29b089 100644 --- a/httpclient/README.md +++ b/httpclient/README.md @@ -7,15 +7,10 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring ### Relevant Articles: -- [HttpClient 4 – Send Custom Cookie](http://www.baeldung.com/httpclient-4-cookies) -- [HttpClient 4 – Get the Status Code](http://www.baeldung.com/httpclient-status-code) -- [HttpClient 4 – Cancel / Abort Request](http://www.baeldung.com/httpclient-cancel-request) +- [HttpClient 4 – Cancel Request](http://www.baeldung.com/httpclient-cancel-request) - [HttpClient 4 Cookbook](http://www.baeldung.com/httpclient4) - [Unshorten URLs with HttpClient](http://www.baeldung.com/unshorten-url-httpclient) -- [HttpClient with SSL](http://www.baeldung.com/httpclient-ssl) - [HttpClient 4 – Follow Redirects for POST](http://www.baeldung.com/httpclient-redirect-on-http-post) -- [Custom HTTP Header with the HttpClient](http://www.baeldung.com/httpclient-custom-http-header) -- [HttpClient Basic Authentication](http://www.baeldung.com/httpclient-4-basic-authentication) - [Multipart Upload with HttpClient 4](http://www.baeldung.com/httpclient-multipart-upload) - [HttpAsyncClient Tutorial](http://www.baeldung.com/httpasyncclient-tutorial) - [HttpClient 4 Tutorial](http://www.baeldung.com/httpclient-guide) diff --git a/httpclient/pom.xml b/httpclient/pom.xml index c9f9808ede..def3a05816 100644 --- a/httpclient/pom.xml +++ b/httpclient/pom.xml @@ -122,11 +122,10 @@ 19.0 3.5 1.10 - 4.1.2 + 4.1.4 2.5.1 - 4.4.5 - 4.5.3 + 4.5.8 1.6.1
diff --git a/httpclient/src/test/java/org/baeldung/httpclient/HttpAsyncClientLiveTest.java b/httpclient/src/test/java/org/baeldung/httpclient/HttpAsyncClientLiveTest.java index d39697c0a9..47a587885e 100644 --- a/httpclient/src/test/java/org/baeldung/httpclient/HttpAsyncClientLiveTest.java +++ b/httpclient/src/test/java/org/baeldung/httpclient/HttpAsyncClientLiveTest.java @@ -4,7 +4,6 @@ import static org.hamcrest.Matchers.equalTo; import static org.junit.Assert.assertThat; import java.io.IOException; -import java.security.cert.X509Certificate; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; @@ -18,8 +17,7 @@ import org.apache.http.client.CredentialsProvider; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.protocol.HttpClientContext; -import org.apache.http.conn.ssl.SSLConnectionSocketFactory; -import org.apache.http.conn.ssl.SSLContexts; +import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.conn.ssl.TrustStrategy; import org.apache.http.impl.client.BasicCookieStore; import org.apache.http.impl.client.BasicCredentialsProvider; @@ -31,6 +29,7 @@ import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor; import org.apache.http.nio.reactor.ConnectingIOReactor; import org.apache.http.protocol.BasicHttpContext; import org.apache.http.protocol.HttpContext; +import org.apache.http.ssl.SSLContexts; import org.junit.Test; public class HttpAsyncClientLiveTest { @@ -104,7 +103,7 @@ public class HttpAsyncClientLiveTest { final TrustStrategy acceptingTrustStrategy = (certificate, authType) -> true; final SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build(); - final CloseableHttpAsyncClient client = HttpAsyncClients.custom().setSSLHostnameVerifier(SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER).setSSLContext(sslContext).build(); + final CloseableHttpAsyncClient client = HttpAsyncClients.custom().setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE).setSSLContext(sslContext).build(); client.start(); final HttpGet request = new HttpGet(HOST_WITH_SSL); diff --git a/httpclient/src/test/java/org/baeldung/httpclient/conn/HttpClientConnectionManagementLiveTest.java b/httpclient/src/test/java/org/baeldung/httpclient/conn/HttpClientConnectionManagementLiveTest.java index 0f8ebefe6c..cf945098db 100644 --- a/httpclient/src/test/java/org/baeldung/httpclient/conn/HttpClientConnectionManagementLiveTest.java +++ b/httpclient/src/test/java/org/baeldung/httpclient/conn/HttpClientConnectionManagementLiveTest.java @@ -327,7 +327,8 @@ public class HttpClientConnectionManagementLiveTest { // 8.1 public final void whenHttpClientChecksStaleConns_thenNoExceptions() { poolingConnManager = new PoolingHttpClientConnectionManager(); - client = HttpClients.custom().setDefaultRequestConfig(RequestConfig.custom().setStaleConnectionCheckEnabled(true).build()).setConnectionManager(poolingConnManager).build(); + poolingConnManager.setValidateAfterInactivity(1000); + client = HttpClients.custom().setDefaultRequestConfig(RequestConfig.custom().build()).setConnectionManager(poolingConnManager).build(); } @Test diff --git a/jackson-2/.gitignore b/jackson-2/.gitignore new file mode 100644 index 0000000000..83c05e60c8 --- /dev/null +++ b/jackson-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/jackson-2/README.md b/jackson-2/README.md new file mode 100644 index 0000000000..ec147f5fd9 --- /dev/null +++ b/jackson-2/README.md @@ -0,0 +1,9 @@ +========= + +## Jackson Cookbooks and Examples + +###The Course +The "REST With Spring" Classes: http://bit.ly/restwithspring + +### Relevant Articles: +- [Mapping Multiple JSON Fields to a Single Java Field](https://www.baeldung.com/json-multiple-fields-single-java-field) diff --git a/jackson-2/pom.xml b/jackson-2/pom.xml new file mode 100644 index 0000000000..6b973dd6f5 --- /dev/null +++ b/jackson-2/pom.xml @@ -0,0 +1,66 @@ + + 4.0.0 + jackson-2 + 0.1-SNAPSHOT + jackson-2 + + + com.baeldung + parent-java + 0.0.1-SNAPSHOT + ../parent-java + + + + + + + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} + + + + + com.fasterxml.jackson.dataformat + jackson-dataformat-yaml + 2.9.8 + + + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + 2.9.8 + + + + + + + org.assertj + assertj-core + ${assertj.version} + test + + + + + jackson-2 + + + src/main/resources + true + + + + + + + + 3.11.0 + + + diff --git a/jackson-2/src/main/java/com/baeldung/jackson/entities/Order.java b/jackson-2/src/main/java/com/baeldung/jackson/entities/Order.java new file mode 100644 index 0000000000..2075b7879b --- /dev/null +++ b/jackson-2/src/main/java/com/baeldung/jackson/entities/Order.java @@ -0,0 +1,68 @@ +package com.baeldung.jackson.entities; + +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.List; + +public class Order { + private String orderNo; + private LocalDate date; + private String customerName; + private List orderLines; + + public Order() { + + } + + public Order(String orderNo, LocalDate date, String customerName, List orderLines) { + super(); + this.orderNo = orderNo; + this.date = date; + this.customerName = customerName; + this.orderLines = orderLines; + } + + public String getOrderNo() { + return orderNo; + } + + public void setOrderNo(String orderNo) { + this.orderNo = orderNo; + } + + public LocalDate getDate() { + return date; + } + + public void setDate(LocalDate date) { + this.date = date; + } + + public String getCustomerName() { + return customerName; + } + + public void setCustomerName(String customerName) { + this.customerName = customerName; + } + + public List getOrderLines() { + if (orderLines == null) { + orderLines = new ArrayList<>(); + } + return orderLines; + } + + public void setOrderLines(List orderLines) { + if (orderLines == null) { + orderLines = new ArrayList<>(); + } + this.orderLines = orderLines; + } + + @Override + public String toString() { + return "Order [orderNo=" + orderNo + ", date=" + date + ", customerName=" + customerName + ", orderLines=" + orderLines + "]"; + } + +} diff --git a/jackson-2/src/main/java/com/baeldung/jackson/entities/OrderLine.java b/jackson-2/src/main/java/com/baeldung/jackson/entities/OrderLine.java new file mode 100644 index 0000000000..858d094dd1 --- /dev/null +++ b/jackson-2/src/main/java/com/baeldung/jackson/entities/OrderLine.java @@ -0,0 +1,49 @@ +package com.baeldung.jackson.entities; + +import java.math.BigDecimal; + +public class OrderLine { + private String item; + private int quantity; + private BigDecimal unitPrice; + + public OrderLine() { + + } + + public OrderLine(String item, int quantity, BigDecimal unitPrice) { + super(); + this.item = item; + this.quantity = quantity; + this.unitPrice = unitPrice; + } + + public String getItem() { + return item; + } + + public void setItem(String item) { + this.item = item; + } + + public int getQuantity() { + return quantity; + } + + public void setQuantity(int quantity) { + this.quantity = quantity; + } + + public BigDecimal getUnitPrice() { + return unitPrice; + } + + public void setUnitPrice(BigDecimal unitPrice) { + this.unitPrice = unitPrice; + } + + @Override + public String toString() { + return "OrderLine [item=" + item + ", quantity=" + quantity + ", unitPrice=" + unitPrice + "]"; + } +} diff --git a/jackson-2/src/main/java/com/baeldung/jackson/entities/Weather.java b/jackson-2/src/main/java/com/baeldung/jackson/entities/Weather.java new file mode 100644 index 0000000000..4a8cea052f --- /dev/null +++ b/jackson-2/src/main/java/com/baeldung/jackson/entities/Weather.java @@ -0,0 +1,44 @@ +package com.baeldung.jackson.entities; + +import com.fasterxml.jackson.annotation.JsonAlias; +import com.fasterxml.jackson.annotation.JsonProperty; + +public class Weather { + + @JsonProperty("location") + @JsonAlias("place") + private String location; + + @JsonProperty("temp") + @JsonAlias("temperature") + private int temp; + + @JsonProperty("outlook") + @JsonAlias("weather") + private String outlook; + + public String getLocation() { + return location; + } + + public void setLocation(String location) { + this.location = location; + } + + public int getTemp() { + return temp; + } + + public void setTemp(int temp) { + this.temp = temp; + } + + public String getOutlook() { + return outlook; + } + + public void setOutlook(String outlook) { + this.outlook = outlook; + } + +} diff --git a/jackson-2/src/main/resources/logback.xml b/jackson-2/src/main/resources/logback.xml new file mode 100644 index 0000000000..7d900d8ea8 --- /dev/null +++ b/jackson-2/src/main/resources/logback.xml @@ -0,0 +1,13 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + \ No newline at end of file diff --git a/jackson-2/src/main/resources/orderInput.yaml b/jackson-2/src/main/resources/orderInput.yaml new file mode 100644 index 0000000000..0aaa6186a2 --- /dev/null +++ b/jackson-2/src/main/resources/orderInput.yaml @@ -0,0 +1,11 @@ +orderNo: A001 +date: 2019-04-17 +customerName: Customer, Joe +orderLines: + - item: No. 9 Sprockets + quantity: 12 + unitPrice: 1.23 + - item: Widget (10mm) + quantity: 4 + unitPrice: 3.45 + \ No newline at end of file diff --git a/jackson-2/src/test/java/com/baeldung/jackson/deserialization/jsonalias/JsonAliasUnitTest.java b/jackson-2/src/test/java/com/baeldung/jackson/deserialization/jsonalias/JsonAliasUnitTest.java new file mode 100644 index 0000000000..b5940a7bd7 --- /dev/null +++ b/jackson-2/src/test/java/com/baeldung/jackson/deserialization/jsonalias/JsonAliasUnitTest.java @@ -0,0 +1,38 @@ +package com.baeldung.jackson.deserialization.jsonalias; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import com.baeldung.jackson.entities.Weather; +import com.fasterxml.jackson.databind.ObjectMapper; + +public class JsonAliasUnitTest { + + @Test + public void givenTwoJsonFormats_whenDeserialized_thenWeatherObjectsCreated() throws Exception { + + ObjectMapper mapper = new ObjectMapper(); + + Weather weather = mapper.readValue("{" + + "\"location\": \"London\"," + + "\"temp\": 15," + + "\"weather\": \"Cloudy\"" + + "}", Weather.class); + + assertEquals("London", weather.getLocation()); + assertEquals("Cloudy", weather.getOutlook()); + assertEquals(15, weather.getTemp()); + + weather = mapper.readValue("{" + + "\"place\": \"Lisbon\"," + + "\"temperature\": 35," + + "\"outlook\": \"Sunny\"" + + "}", Weather.class); + + assertEquals("Lisbon", weather.getLocation()); + assertEquals("Sunny", weather.getOutlook()); + assertEquals(35, weather.getTemp()); + + } +} diff --git a/jackson-2/src/test/java/com/baeldung/jackson/yaml/YamlUnitTest.java b/jackson-2/src/test/java/com/baeldung/jackson/yaml/YamlUnitTest.java new file mode 100644 index 0000000000..3ed84db60e --- /dev/null +++ b/jackson-2/src/test/java/com/baeldung/jackson/yaml/YamlUnitTest.java @@ -0,0 +1,63 @@ +package com.baeldung.jackson.yaml; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.io.IOException; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.List; + +import org.junit.Before; +import org.junit.Test; + +import com.baeldung.jackson.entities.Order; +import com.baeldung.jackson.entities.OrderLine; +import com.fasterxml.jackson.core.JsonGenerationException; +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; +import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator.Feature; + +public class YamlUnitTest { + private ObjectMapper mapper; + + @Before + public void setup() { + mapper = new ObjectMapper(new YAMLFactory().disable(Feature.WRITE_DOC_START_MARKER)); + mapper.findAndRegisterModules(); + mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); + } + + @Test + public void givenYamlInput_ObjectCreated() throws JsonParseException, JsonMappingException, IOException { + Order order = mapper.readValue(new File("src/main/resources/orderInput.yaml"), Order.class); + assertEquals("A001", order.getOrderNo()); + assertEquals(LocalDate.parse("2019-04-17", DateTimeFormatter.ISO_DATE), order.getDate()); + assertEquals("Customer, Joe", order.getCustomerName()); + assertEquals(2, order.getOrderLines() + .size()); + } + + @Test + public void givenYamlObject_FileWritten() throws JsonGenerationException, JsonMappingException, IOException { + List lines = new ArrayList<>(); + lines.add(new OrderLine("Copper Wire (200ft)", 1, new BigDecimal(50.67).setScale(2, RoundingMode.HALF_UP))); + lines.add(new OrderLine("Washers (1/4\")", 24, new BigDecimal(.15).setScale(2, RoundingMode.HALF_UP))); + Order order = new Order( + "B-9910", + LocalDate.parse("2019-04-18", DateTimeFormatter.ISO_DATE), + "Customer, Jane", + lines); + mapper.writeValue(new File("src/main/resources/orderOutput.yaml"), order); + + File outputYaml = new File("src/main/resources/orderOutput.yaml"); + assertTrue(outputYaml.exists()); + } +} diff --git a/jackson-simple/.gitignore b/jackson-simple/.gitignore new file mode 100644 index 0000000000..83c05e60c8 --- /dev/null +++ b/jackson-simple/.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/jackson-simple/README.md b/jackson-simple/README.md new file mode 100644 index 0000000000..be647e22d5 --- /dev/null +++ b/jackson-simple/README.md @@ -0,0 +1,13 @@ +========= +### Jackson Articles that are also part of the e-book + +###The Course +The "REST With Spring" Classes: http://bit.ly/restwithspring + +### Relevant Articles: +- [Jackson Ignore Properties on Marshalling](http://www.baeldung.com/jackson-ignore-properties-on-serialization) +- [Jackson Unmarshalling json with Unknown Properties](http://www.baeldung.com/jackson-deserialize-json-unknown-properties) +- [Jackson Annotation Examples](http://www.baeldung.com/jackson-annotations) +- [Intro to the Jackson ObjectMapper](http://www.baeldung.com/jackson-object-mapper-tutorial) +- [Ignore Null Fields with Jackson](http://www.baeldung.com/jackson-ignore-null-fields) +- [Jackson – Change Name of Field](http://www.baeldung.com/jackson-name-of-property) diff --git a/jackson-simple/pom.xml b/jackson-simple/pom.xml new file mode 100644 index 0000000000..5023ad87b6 --- /dev/null +++ b/jackson-simple/pom.xml @@ -0,0 +1,131 @@ + + 4.0.0 + jackson-simple + 0.1-SNAPSHOT + jackson-simple + + + com.baeldung + parent-java + 0.0.1-SNAPSHOT + ../parent-java + + + + + + commons-io + commons-io + ${commons-io.version} + + + + com.fasterxml.jackson.dataformat + jackson-dataformat-xml + ${jackson.version} + + + + org.apache.commons + commons-collections4 + ${commons-collections4.version} + + + + org.apache.commons + commons-lang3 + ${commons-lang3.version} + + + + + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} + + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + ${jackson.version} + + + + com.fasterxml.jackson.datatype + jackson-datatype-joda + ${jackson.version} + + + + com.fasterxml.jackson.module + jackson-module-jsonSchema + ${jackson.version} + + + + com.fasterxml.jackson.datatype + jackson-datatype-jdk8 + ${jackson.version} + + + + joda-time + joda-time + ${joda-time.version} + + + + com.google.code.gson + gson + ${gson.version} + + + + + + io.rest-assured + json-schema-validator + ${rest-assured.version} + test + + + + io.rest-assured + json-path + ${rest-assured.version} + test + + + + org.assertj + assertj-core + ${assertj.version} + test + + + + + jackson-simple + + + src/main/resources + true + + + + + + + 3.8 + 2.10 + 2.8.5 + 4.2 + + + 3.1.1 + 3.11.0 + + + diff --git a/jackson-simple/src/main/resources/logback.xml b/jackson-simple/src/main/resources/logback.xml new file mode 100644 index 0000000000..56af2d397e --- /dev/null +++ b/jackson-simple/src/main/resources/logback.xml @@ -0,0 +1,19 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + + + + + \ No newline at end of file diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/annotation/AliasBean.java b/jackson-simple/src/test/java/com/baeldung/jackson/annotation/AliasBean.java new file mode 100644 index 0000000000..1842b2b6f5 --- /dev/null +++ b/jackson-simple/src/test/java/com/baeldung/jackson/annotation/AliasBean.java @@ -0,0 +1,31 @@ +package com.baeldung.jackson.annotation; + +import com.fasterxml.jackson.annotation.JsonAlias; + +public class AliasBean { + + @JsonAlias({ "fName", "f_name" }) + private String firstName; + + private String lastName; + + public AliasBean() { + + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } +} diff --git a/jackson/src/test/java/com/baeldung/jackson/annotation/BeanWithCreator.java b/jackson-simple/src/test/java/com/baeldung/jackson/annotation/BeanWithCreator.java similarity index 100% rename from jackson/src/test/java/com/baeldung/jackson/annotation/BeanWithCreator.java rename to jackson-simple/src/test/java/com/baeldung/jackson/annotation/BeanWithCreator.java diff --git a/jackson/src/test/java/com/baeldung/jackson/annotation/BeanWithCustomAnnotation.java b/jackson-simple/src/test/java/com/baeldung/jackson/annotation/BeanWithCustomAnnotation.java similarity index 100% rename from jackson/src/test/java/com/baeldung/jackson/annotation/BeanWithCustomAnnotation.java rename to jackson-simple/src/test/java/com/baeldung/jackson/annotation/BeanWithCustomAnnotation.java diff --git a/jackson/src/test/java/com/baeldung/jackson/annotation/BeanWithFilter.java b/jackson-simple/src/test/java/com/baeldung/jackson/annotation/BeanWithFilter.java similarity index 100% rename from jackson/src/test/java/com/baeldung/jackson/annotation/BeanWithFilter.java rename to jackson-simple/src/test/java/com/baeldung/jackson/annotation/BeanWithFilter.java diff --git a/jackson/src/test/java/com/baeldung/jackson/annotation/BeanWithGetter.java b/jackson-simple/src/test/java/com/baeldung/jackson/annotation/BeanWithGetter.java similarity index 100% rename from jackson/src/test/java/com/baeldung/jackson/annotation/BeanWithGetter.java rename to jackson-simple/src/test/java/com/baeldung/jackson/annotation/BeanWithGetter.java diff --git a/jackson/src/test/java/com/baeldung/jackson/annotation/BeanWithIgnore.java b/jackson-simple/src/test/java/com/baeldung/jackson/annotation/BeanWithIgnore.java similarity index 100% rename from jackson/src/test/java/com/baeldung/jackson/annotation/BeanWithIgnore.java rename to jackson-simple/src/test/java/com/baeldung/jackson/annotation/BeanWithIgnore.java diff --git a/jackson/src/test/java/com/baeldung/jackson/annotation/BeanWithInject.java b/jackson-simple/src/test/java/com/baeldung/jackson/annotation/BeanWithInject.java similarity index 100% rename from jackson/src/test/java/com/baeldung/jackson/annotation/BeanWithInject.java rename to jackson-simple/src/test/java/com/baeldung/jackson/annotation/BeanWithInject.java diff --git a/jackson/src/test/java/com/baeldung/jackson/annotation/ExtendableBean.java b/jackson-simple/src/test/java/com/baeldung/jackson/annotation/ExtendableBean.java similarity index 100% rename from jackson/src/test/java/com/baeldung/jackson/annotation/ExtendableBean.java rename to jackson-simple/src/test/java/com/baeldung/jackson/annotation/ExtendableBean.java diff --git a/jackson/src/test/java/com/baeldung/jackson/annotation/MyBean.java b/jackson-simple/src/test/java/com/baeldung/jackson/annotation/MyBean.java similarity index 100% rename from jackson/src/test/java/com/baeldung/jackson/annotation/MyBean.java rename to jackson-simple/src/test/java/com/baeldung/jackson/annotation/MyBean.java diff --git a/jackson/src/test/java/com/baeldung/jackson/annotation/PrivateBean.java b/jackson-simple/src/test/java/com/baeldung/jackson/annotation/PrivateBean.java similarity index 100% rename from jackson/src/test/java/com/baeldung/jackson/annotation/PrivateBean.java rename to jackson-simple/src/test/java/com/baeldung/jackson/annotation/PrivateBean.java diff --git a/jackson/src/test/java/com/baeldung/jackson/annotation/RawBean.java b/jackson-simple/src/test/java/com/baeldung/jackson/annotation/RawBean.java similarity index 100% rename from jackson/src/test/java/com/baeldung/jackson/annotation/RawBean.java rename to jackson-simple/src/test/java/com/baeldung/jackson/annotation/RawBean.java diff --git a/jackson/src/test/java/com/baeldung/jackson/annotation/UnwrappedUser.java b/jackson-simple/src/test/java/com/baeldung/jackson/annotation/UnwrappedUser.java similarity index 100% rename from jackson/src/test/java/com/baeldung/jackson/annotation/UnwrappedUser.java rename to jackson-simple/src/test/java/com/baeldung/jackson/annotation/UnwrappedUser.java diff --git a/jackson/src/test/java/com/baeldung/jackson/annotation/UserWithIgnoreType.java b/jackson-simple/src/test/java/com/baeldung/jackson/annotation/UserWithIgnoreType.java similarity index 100% rename from jackson/src/test/java/com/baeldung/jackson/annotation/UserWithIgnoreType.java rename to jackson-simple/src/test/java/com/baeldung/jackson/annotation/UserWithIgnoreType.java diff --git a/jackson/src/test/java/com/baeldung/jackson/annotation/Zoo.java b/jackson-simple/src/test/java/com/baeldung/jackson/annotation/Zoo.java similarity index 100% rename from jackson/src/test/java/com/baeldung/jackson/annotation/Zoo.java rename to jackson-simple/src/test/java/com/baeldung/jackson/annotation/Zoo.java diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/bidirection/ItemWithIdentity.java b/jackson-simple/src/test/java/com/baeldung/jackson/bidirection/ItemWithIdentity.java new file mode 100644 index 0000000000..25de4a8f7a --- /dev/null +++ b/jackson-simple/src/test/java/com/baeldung/jackson/bidirection/ItemWithIdentity.java @@ -0,0 +1,21 @@ +package com.baeldung.jackson.bidirection; + +import com.fasterxml.jackson.annotation.JsonIdentityInfo; +import com.fasterxml.jackson.annotation.ObjectIdGenerators; + +@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id") +public class ItemWithIdentity { + public int id; + public String itemName; + public UserWithIdentity owner; + + public ItemWithIdentity() { + super(); + } + + public ItemWithIdentity(final int id, final String itemName, final UserWithIdentity owner) { + this.id = id; + this.itemName = itemName; + this.owner = owner; + } +} diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/bidirection/ItemWithIgnore.java b/jackson-simple/src/test/java/com/baeldung/jackson/bidirection/ItemWithIgnore.java new file mode 100644 index 0000000000..910ccec174 --- /dev/null +++ b/jackson-simple/src/test/java/com/baeldung/jackson/bidirection/ItemWithIgnore.java @@ -0,0 +1,17 @@ +package com.baeldung.jackson.bidirection; + +public class ItemWithIgnore { + public int id; + public String itemName; + public UserWithIgnore owner; + + public ItemWithIgnore() { + super(); + } + + public ItemWithIgnore(final int id, final String itemName, final UserWithIgnore owner) { + this.id = id; + this.itemName = itemName; + this.owner = owner; + } +} diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/bidirection/ItemWithRef.java b/jackson-simple/src/test/java/com/baeldung/jackson/bidirection/ItemWithRef.java new file mode 100644 index 0000000000..0ca8d721e8 --- /dev/null +++ b/jackson-simple/src/test/java/com/baeldung/jackson/bidirection/ItemWithRef.java @@ -0,0 +1,21 @@ +package com.baeldung.jackson.bidirection; + +import com.fasterxml.jackson.annotation.JsonManagedReference; + +public class ItemWithRef { + public int id; + public String itemName; + + @JsonManagedReference + public UserWithRef owner; + + public ItemWithRef() { + super(); + } + + public ItemWithRef(final int id, final String itemName, final UserWithRef owner) { + this.id = id; + this.itemName = itemName; + this.owner = owner; + } +} diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/bidirection/UserWithIdentity.java b/jackson-simple/src/test/java/com/baeldung/jackson/bidirection/UserWithIdentity.java new file mode 100644 index 0000000000..db83a09389 --- /dev/null +++ b/jackson-simple/src/test/java/com/baeldung/jackson/bidirection/UserWithIdentity.java @@ -0,0 +1,28 @@ +package com.baeldung.jackson.bidirection; + +import java.util.ArrayList; +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonIdentityInfo; +import com.fasterxml.jackson.annotation.ObjectIdGenerators; + +@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id") +public class UserWithIdentity { + public int id; + public String name; + public List userItems; + + public UserWithIdentity() { + super(); + } + + public UserWithIdentity(final int id, final String name) { + this.id = id; + this.name = name; + userItems = new ArrayList(); + } + + public void addItem(final ItemWithIdentity item) { + userItems.add(item); + } +} diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/bidirection/UserWithIgnore.java b/jackson-simple/src/test/java/com/baeldung/jackson/bidirection/UserWithIgnore.java new file mode 100644 index 0000000000..857a373cc5 --- /dev/null +++ b/jackson-simple/src/test/java/com/baeldung/jackson/bidirection/UserWithIgnore.java @@ -0,0 +1,28 @@ +package com.baeldung.jackson.bidirection; + +import java.util.ArrayList; +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +public class UserWithIgnore { + public int id; + public String name; + + @JsonIgnore + public List userItems; + + public UserWithIgnore() { + super(); + } + + public UserWithIgnore(final int id, final String name) { + this.id = id; + this.name = name; + userItems = new ArrayList(); + } + + public void addItem(final ItemWithIgnore item) { + userItems.add(item); + } +} diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/bidirection/UserWithRef.java b/jackson-simple/src/test/java/com/baeldung/jackson/bidirection/UserWithRef.java new file mode 100644 index 0000000000..3de03fc651 --- /dev/null +++ b/jackson-simple/src/test/java/com/baeldung/jackson/bidirection/UserWithRef.java @@ -0,0 +1,28 @@ +package com.baeldung.jackson.bidirection; + +import java.util.ArrayList; +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonBackReference; + +public class UserWithRef { + public int id; + public String name; + + @JsonBackReference + public List userItems; + + public UserWithRef() { + super(); + } + + public UserWithRef(final int id, final String name) { + this.id = id; + this.name = name; + userItems = new ArrayList(); + } + + public void addItem(final ItemWithRef item) { + userItems.add(item); + } +} diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/date/CustomDateDeserializer.java b/jackson-simple/src/test/java/com/baeldung/jackson/date/CustomDateDeserializer.java new file mode 100644 index 0000000000..90c7d9fbac --- /dev/null +++ b/jackson-simple/src/test/java/com/baeldung/jackson/date/CustomDateDeserializer.java @@ -0,0 +1,36 @@ +package com.baeldung.jackson.date; + +import java.io.IOException; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; + +public class CustomDateDeserializer extends StdDeserializer { + + private static final long serialVersionUID = -5451717385630622729L; + private SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss"); + + public CustomDateDeserializer() { + this(null); + } + + public CustomDateDeserializer(final Class vc) { + super(vc); + } + + @Override + public Date deserialize(final JsonParser jsonparser, final DeserializationContext context) throws IOException, JsonProcessingException { + final String date = jsonparser.getText(); + try { + return formatter.parse(date); + } catch (final ParseException e) { + throw new RuntimeException(e); + } + } + +} diff --git a/jackson/src/main/java/com/baeldung/jackson/serialization/jsonserialize/CustomDateSerializer.java b/jackson-simple/src/test/java/com/baeldung/jackson/date/CustomDateSerializer.java similarity index 55% rename from jackson/src/main/java/com/baeldung/jackson/serialization/jsonserialize/CustomDateSerializer.java rename to jackson-simple/src/test/java/com/baeldung/jackson/date/CustomDateSerializer.java index 131f4f3695..d840e1940f 100644 --- a/jackson/src/main/java/com/baeldung/jackson/serialization/jsonserialize/CustomDateSerializer.java +++ b/jackson-simple/src/test/java/com/baeldung/jackson/date/CustomDateSerializer.java @@ -1,34 +1,29 @@ -package com.baeldung.jackson.serialization.jsonserialize; +package com.baeldung.jackson.date; + +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Date; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.ser.std.StdSerializer; -import java.io.IOException; -import java.text.SimpleDateFormat; -import java.util.Date; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ public class CustomDateSerializer extends StdSerializer { - private static SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss"); + private static final long serialVersionUID = -2894356342227378312L; + private SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss"); public CustomDateSerializer() { this(null); } - public CustomDateSerializer(Class t) { + public CustomDateSerializer(final Class t) { super(t); } @Override - public void serialize(Date value, JsonGenerator gen, SerializerProvider arg2) throws IOException, JsonProcessingException { + public void serialize(final Date value, final JsonGenerator gen, final SerializerProvider arg2) throws IOException, JsonProcessingException { gen.writeString(formatter.format(value)); } } diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/date/EventWithFormat.java b/jackson-simple/src/test/java/com/baeldung/jackson/date/EventWithFormat.java new file mode 100644 index 0000000000..607e694cef --- /dev/null +++ b/jackson-simple/src/test/java/com/baeldung/jackson/date/EventWithFormat.java @@ -0,0 +1,29 @@ +package com.baeldung.jackson.date; + +import java.util.Date; + +import com.fasterxml.jackson.annotation.JsonFormat; + +public class EventWithFormat { + public String name; + + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy hh:mm:ss") + public Date eventDate; + + public EventWithFormat() { + super(); + } + + public EventWithFormat(final String name, final Date eventDate) { + this.name = name; + this.eventDate = eventDate; + } + + public Date getEventDate() { + return eventDate; + } + + public String getName() { + return name; + } +} diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/date/EventWithSerializer.java b/jackson-simple/src/test/java/com/baeldung/jackson/date/EventWithSerializer.java new file mode 100644 index 0000000000..c359b5c846 --- /dev/null +++ b/jackson-simple/src/test/java/com/baeldung/jackson/date/EventWithSerializer.java @@ -0,0 +1,31 @@ +package com.baeldung.jackson.date; + +import java.util.Date; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; + +public class EventWithSerializer { + public String name; + + @JsonDeserialize(using = CustomDateDeserializer.class) + @JsonSerialize(using = CustomDateSerializer.class) + public Date eventDate; + + public EventWithSerializer() { + super(); + } + + public EventWithSerializer(final String name, final Date eventDate) { + this.name = name; + this.eventDate = eventDate; + } + + public Date getEventDate() { + return eventDate; + } + + public String getName() { + return name; + } +} diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/deserialization/ItemDeserializerOnClass.java b/jackson-simple/src/test/java/com/baeldung/jackson/deserialization/ItemDeserializerOnClass.java new file mode 100644 index 0000000000..eaba9a7173 --- /dev/null +++ b/jackson-simple/src/test/java/com/baeldung/jackson/deserialization/ItemDeserializerOnClass.java @@ -0,0 +1,41 @@ +package com.baeldung.jackson.deserialization; + +import java.io.IOException; + +import com.baeldung.jackson.dtos.ItemWithSerializer; +import com.baeldung.jackson.dtos.User; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import com.fasterxml.jackson.databind.node.IntNode; + +public class ItemDeserializerOnClass extends StdDeserializer { + + private static final long serialVersionUID = 5579141241817332594L; + + public ItemDeserializerOnClass() { + this(null); + } + + public ItemDeserializerOnClass(final Class vc) { + super(vc); + } + + /** + * {"id":1,"itemNr":"theItem","owner":2} + */ + @Override + public ItemWithSerializer deserialize(final JsonParser jp, final DeserializationContext ctxt) throws IOException, JsonProcessingException { + final JsonNode node = jp.getCodec() + .readTree(jp); + final int id = (Integer) ((IntNode) node.get("id")).numberValue(); + final String itemName = node.get("itemName") + .asText(); + final int userId = (Integer) ((IntNode) node.get("owner")).numberValue(); + + return new ItemWithSerializer(id, itemName, new User(userId, null)); + } + +} \ No newline at end of file diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/dtos/Item.java b/jackson-simple/src/test/java/com/baeldung/jackson/dtos/Item.java new file mode 100644 index 0000000000..6fce2bc88e --- /dev/null +++ b/jackson-simple/src/test/java/com/baeldung/jackson/dtos/Item.java @@ -0,0 +1,32 @@ +package com.baeldung.jackson.dtos; + +public class Item { + public int id; + public String itemName; + public User owner; + + public Item() { + super(); + } + + public Item(final int id, final String itemName, final User owner) { + this.id = id; + this.itemName = itemName; + this.owner = owner; + } + + // API + + public int getId() { + return id; + } + + public String getItemName() { + return itemName; + } + + public User getOwner() { + return owner; + } + +} \ No newline at end of file diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/dtos/ItemWithSerializer.java b/jackson-simple/src/test/java/com/baeldung/jackson/dtos/ItemWithSerializer.java new file mode 100644 index 0000000000..aea9aa770d --- /dev/null +++ b/jackson-simple/src/test/java/com/baeldung/jackson/dtos/ItemWithSerializer.java @@ -0,0 +1,36 @@ +package com.baeldung.jackson.dtos; + +import com.baeldung.jackson.deserialization.ItemDeserializerOnClass; +import com.baeldung.jackson.serialization.ItemSerializerOnClass; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; + +@JsonSerialize(using = ItemSerializerOnClass.class) +@JsonDeserialize(using = ItemDeserializerOnClass.class) +public class ItemWithSerializer { + public final int id; + public final String itemName; + public final User owner; + + public ItemWithSerializer(final int id, final String itemName, final User owner) { + this.id = id; + this.itemName = itemName; + this.owner = owner; + } + + // API + + public int getId() { + return id; + } + + public String getItemName() { + return itemName; + } + + public User getOwner() { + return owner; + } + +} \ No newline at end of file diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/dtos/MyDto.java b/jackson-simple/src/test/java/com/baeldung/jackson/dtos/MyDto.java new file mode 100644 index 0000000000..49cf07baea --- /dev/null +++ b/jackson-simple/src/test/java/com/baeldung/jackson/dtos/MyDto.java @@ -0,0 +1,54 @@ +package com.baeldung.jackson.dtos; + +public class MyDto { + + private String stringValue; + private int intValue; + private boolean booleanValue; + + public MyDto() { + super(); + } + + public MyDto(final String stringValue, final int intValue, final boolean booleanValue) { + super(); + + this.stringValue = stringValue; + this.intValue = intValue; + this.booleanValue = booleanValue; + } + + // API + + public String getStringValue() { + return stringValue; + } + + public void setStringValue(final String stringValue) { + this.stringValue = stringValue; + } + + public int getIntValue() { + return intValue; + } + + public void setIntValue(final int intValue) { + this.intValue = intValue; + } + + public boolean isBooleanValue() { + return booleanValue; + } + + public void setBooleanValue(final boolean booleanValue) { + this.booleanValue = booleanValue; + } + + // + + @Override + public String toString() { + return "MyDto [stringValue=" + stringValue + ", intValue=" + intValue + ", booleanValue=" + booleanValue + "]"; + } + +} diff --git a/jackson/src/test/java/com/baeldung/jackson/dtos/MyDtoFieldNameChanged.java b/jackson-simple/src/test/java/com/baeldung/jackson/dtos/MyDtoFieldNameChanged.java similarity index 100% rename from jackson/src/test/java/com/baeldung/jackson/dtos/MyDtoFieldNameChanged.java rename to jackson-simple/src/test/java/com/baeldung/jackson/dtos/MyDtoFieldNameChanged.java diff --git a/jackson/src/test/java/com/baeldung/jackson/dtos/MyDtoIncludeNonDefault.java b/jackson-simple/src/test/java/com/baeldung/jackson/dtos/MyDtoIncludeNonDefault.java similarity index 100% rename from jackson/src/test/java/com/baeldung/jackson/dtos/MyDtoIncludeNonDefault.java rename to jackson-simple/src/test/java/com/baeldung/jackson/dtos/MyDtoIncludeNonDefault.java diff --git a/jackson/src/test/java/com/baeldung/jackson/dtos/MyDtoNoAccessors.java b/jackson-simple/src/test/java/com/baeldung/jackson/dtos/MyDtoNoAccessors.java similarity index 100% rename from jackson/src/test/java/com/baeldung/jackson/dtos/MyDtoNoAccessors.java rename to jackson-simple/src/test/java/com/baeldung/jackson/dtos/MyDtoNoAccessors.java diff --git a/jackson/src/test/java/com/baeldung/jackson/dtos/MyDtoNoAccessorsAndFieldVisibility.java b/jackson-simple/src/test/java/com/baeldung/jackson/dtos/MyDtoNoAccessorsAndFieldVisibility.java similarity index 100% rename from jackson/src/test/java/com/baeldung/jackson/dtos/MyDtoNoAccessorsAndFieldVisibility.java rename to jackson-simple/src/test/java/com/baeldung/jackson/dtos/MyDtoNoAccessorsAndFieldVisibility.java diff --git a/jackson/src/test/java/com/baeldung/jackson/dtos/MyDtoWithFilter.java b/jackson-simple/src/test/java/com/baeldung/jackson/dtos/MyDtoWithFilter.java similarity index 100% rename from jackson/src/test/java/com/baeldung/jackson/dtos/MyDtoWithFilter.java rename to jackson-simple/src/test/java/com/baeldung/jackson/dtos/MyDtoWithFilter.java diff --git a/jackson/src/test/java/com/baeldung/jackson/dtos/MyDtoWithSpecialField.java b/jackson-simple/src/test/java/com/baeldung/jackson/dtos/MyDtoWithSpecialField.java similarity index 100% rename from jackson/src/test/java/com/baeldung/jackson/dtos/MyDtoWithSpecialField.java rename to jackson-simple/src/test/java/com/baeldung/jackson/dtos/MyDtoWithSpecialField.java diff --git a/jackson/src/test/java/com/baeldung/jackson/dtos/MyMixInForIgnoreType.java b/jackson-simple/src/test/java/com/baeldung/jackson/dtos/MyMixInForIgnoreType.java similarity index 100% rename from jackson/src/test/java/com/baeldung/jackson/dtos/MyMixInForIgnoreType.java rename to jackson-simple/src/test/java/com/baeldung/jackson/dtos/MyMixInForIgnoreType.java diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/dtos/User.java b/jackson-simple/src/test/java/com/baeldung/jackson/dtos/User.java new file mode 100644 index 0000000000..2418e8070d --- /dev/null +++ b/jackson-simple/src/test/java/com/baeldung/jackson/dtos/User.java @@ -0,0 +1,26 @@ +package com.baeldung.jackson.dtos; + +public class User { + public int id; + public String name; + + public User() { + super(); + } + + public User(final int id, final String name) { + this.id = id; + this.name = name; + } + + // API + + public int getId() { + return id; + } + + public String getName() { + return name; + } + +} \ No newline at end of file diff --git a/jackson/src/test/java/com/baeldung/jackson/dtos/ignore/MyDtoIgnoreField.java b/jackson-simple/src/test/java/com/baeldung/jackson/dtos/ignore/MyDtoIgnoreField.java similarity index 100% rename from jackson/src/test/java/com/baeldung/jackson/dtos/ignore/MyDtoIgnoreField.java rename to jackson-simple/src/test/java/com/baeldung/jackson/dtos/ignore/MyDtoIgnoreField.java diff --git a/jackson/src/test/java/com/baeldung/jackson/dtos/ignore/MyDtoIgnoreFieldByName.java b/jackson-simple/src/test/java/com/baeldung/jackson/dtos/ignore/MyDtoIgnoreFieldByName.java similarity index 100% rename from jackson/src/test/java/com/baeldung/jackson/dtos/ignore/MyDtoIgnoreFieldByName.java rename to jackson-simple/src/test/java/com/baeldung/jackson/dtos/ignore/MyDtoIgnoreFieldByName.java diff --git a/jackson/src/test/java/com/baeldung/jackson/dtos/ignore/MyDtoIgnoreNull.java b/jackson-simple/src/test/java/com/baeldung/jackson/dtos/ignore/MyDtoIgnoreNull.java similarity index 100% rename from jackson/src/test/java/com/baeldung/jackson/dtos/ignore/MyDtoIgnoreNull.java rename to jackson-simple/src/test/java/com/baeldung/jackson/dtos/ignore/MyDtoIgnoreNull.java diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/dtos/withEnum/DistanceEnumWithValue.java b/jackson-simple/src/test/java/com/baeldung/jackson/dtos/withEnum/DistanceEnumWithValue.java new file mode 100644 index 0000000000..69c476d8a5 --- /dev/null +++ b/jackson-simple/src/test/java/com/baeldung/jackson/dtos/withEnum/DistanceEnumWithValue.java @@ -0,0 +1,29 @@ +package com.baeldung.jackson.dtos.withEnum; + +import com.fasterxml.jackson.annotation.JsonValue; + +public enum DistanceEnumWithValue { + KILOMETER("km", 1000), MILE("miles", 1609.34), METER("meters", 1), INCH("inches", 0.0254), CENTIMETER("cm", 0.01), MILLIMETER("mm", 0.001); + + private String unit; + private final double meters; + + private DistanceEnumWithValue(String unit, double meters) { + this.unit = unit; + this.meters = meters; + } + + @JsonValue + public double getMeters() { + return meters; + } + + public String getUnit() { + return unit; + } + + public void setUnit(String unit) { + this.unit = unit; + } + +} \ No newline at end of file diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/exception/UserWithRoot.java b/jackson-simple/src/test/java/com/baeldung/jackson/exception/UserWithRoot.java new file mode 100644 index 0000000000..d879c16e6a --- /dev/null +++ b/jackson-simple/src/test/java/com/baeldung/jackson/exception/UserWithRoot.java @@ -0,0 +1,18 @@ +package com.baeldung.jackson.exception; + +import com.fasterxml.jackson.annotation.JsonRootName; + +@JsonRootName(value = "user") +public class UserWithRoot { + public int id; + public String name; + + public UserWithRoot() { + super(); + } + + public UserWithRoot(final int id, final String name) { + this.id = id; + this.name = name; + } +} diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/exception/UserWithRootNamespace.java b/jackson-simple/src/test/java/com/baeldung/jackson/exception/UserWithRootNamespace.java new file mode 100644 index 0000000000..bf8c85efba --- /dev/null +++ b/jackson-simple/src/test/java/com/baeldung/jackson/exception/UserWithRootNamespace.java @@ -0,0 +1,18 @@ +package com.baeldung.jackson.exception; + +import com.fasterxml.jackson.annotation.JsonRootName; + +@JsonRootName(value = "user", namespace="users") +public class UserWithRootNamespace { + public int id; + public String name; + + public UserWithRootNamespace() { + super(); + } + + public UserWithRootNamespace(final int id, final String name) { + this.id = id; + this.name = name; + } +} diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/jsonview/Item.java b/jackson-simple/src/test/java/com/baeldung/jackson/jsonview/Item.java new file mode 100644 index 0000000000..26d20d4847 --- /dev/null +++ b/jackson-simple/src/test/java/com/baeldung/jackson/jsonview/Item.java @@ -0,0 +1,36 @@ +package com.baeldung.jackson.jsonview; + +import com.fasterxml.jackson.annotation.JsonView; + +public class Item { + @JsonView(Views.Public.class) + public int id; + + @JsonView(Views.Public.class) + public String itemName; + + @JsonView(Views.Internal.class) + public String ownerName; + + public Item() { + super(); + } + + public Item(final int id, final String itemName, final String ownerName) { + this.id = id; + this.itemName = itemName; + this.ownerName = ownerName; + } + + public int getId() { + return id; + } + + public String getItemName() { + return itemName; + } + + public String getOwnerName() { + return ownerName; + } +} diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/jsonview/Views.java b/jackson-simple/src/test/java/com/baeldung/jackson/jsonview/Views.java new file mode 100644 index 0000000000..65950b7f9f --- /dev/null +++ b/jackson-simple/src/test/java/com/baeldung/jackson/jsonview/Views.java @@ -0,0 +1,9 @@ +package com.baeldung.jackson.jsonview; + +public class Views { + public static class Public { + } + + public static class Internal extends Public { + } +} diff --git a/jackson/src/test/java/com/baeldung/jackson/objectmapper/CustomCarDeserializer.java b/jackson-simple/src/test/java/com/baeldung/jackson/objectmapper/CustomCarDeserializer.java similarity index 100% rename from jackson/src/test/java/com/baeldung/jackson/objectmapper/CustomCarDeserializer.java rename to jackson-simple/src/test/java/com/baeldung/jackson/objectmapper/CustomCarDeserializer.java diff --git a/jackson/src/test/java/com/baeldung/jackson/objectmapper/CustomCarSerializer.java b/jackson-simple/src/test/java/com/baeldung/jackson/objectmapper/CustomCarSerializer.java similarity index 100% rename from jackson/src/test/java/com/baeldung/jackson/objectmapper/CustomCarSerializer.java rename to jackson-simple/src/test/java/com/baeldung/jackson/objectmapper/CustomCarSerializer.java diff --git a/jackson/src/test/java/com/baeldung/jackson/objectmapper/JavaReadWriteJsonExampleUnitTest.java b/jackson-simple/src/test/java/com/baeldung/jackson/objectmapper/JavaReadWriteJsonExampleUnitTest.java similarity index 100% rename from jackson/src/test/java/com/baeldung/jackson/objectmapper/JavaReadWriteJsonExampleUnitTest.java rename to jackson-simple/src/test/java/com/baeldung/jackson/objectmapper/JavaReadWriteJsonExampleUnitTest.java diff --git a/jackson/src/test/java/com/baeldung/jackson/objectmapper/SerializationDeserializationFeatureUnitTest.java b/jackson-simple/src/test/java/com/baeldung/jackson/objectmapper/SerializationDeserializationFeatureUnitTest.java similarity index 100% rename from jackson/src/test/java/com/baeldung/jackson/objectmapper/SerializationDeserializationFeatureUnitTest.java rename to jackson-simple/src/test/java/com/baeldung/jackson/objectmapper/SerializationDeserializationFeatureUnitTest.java diff --git a/jackson/src/test/java/com/baeldung/jackson/objectmapper/dto/Car.java b/jackson-simple/src/test/java/com/baeldung/jackson/objectmapper/dto/Car.java similarity index 100% rename from jackson/src/test/java/com/baeldung/jackson/objectmapper/dto/Car.java rename to jackson-simple/src/test/java/com/baeldung/jackson/objectmapper/dto/Car.java diff --git a/jackson/src/test/java/com/baeldung/jackson/objectmapper/dto/Request.java b/jackson-simple/src/test/java/com/baeldung/jackson/objectmapper/dto/Request.java similarity index 100% rename from jackson/src/test/java/com/baeldung/jackson/objectmapper/dto/Request.java rename to jackson-simple/src/test/java/com/baeldung/jackson/objectmapper/dto/Request.java diff --git a/jackson/src/test/java/com/baeldung/jackson/serialization/ItemSerializer.java b/jackson-simple/src/test/java/com/baeldung/jackson/serialization/ItemSerializer.java similarity index 100% rename from jackson/src/test/java/com/baeldung/jackson/serialization/ItemSerializer.java rename to jackson-simple/src/test/java/com/baeldung/jackson/serialization/ItemSerializer.java diff --git a/jackson-simple/src/test/java/com/baeldung/jackson/serialization/ItemSerializerOnClass.java b/jackson-simple/src/test/java/com/baeldung/jackson/serialization/ItemSerializerOnClass.java new file mode 100644 index 0000000000..1fdf44e17c --- /dev/null +++ b/jackson-simple/src/test/java/com/baeldung/jackson/serialization/ItemSerializerOnClass.java @@ -0,0 +1,32 @@ +package com.baeldung.jackson.serialization; + +import java.io.IOException; + +import com.baeldung.jackson.dtos.ItemWithSerializer; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; + +public class ItemSerializerOnClass extends StdSerializer { + + private static final long serialVersionUID = -1760959597313610409L; + + public ItemSerializerOnClass() { + this(null); + } + + public ItemSerializerOnClass(final Class t) { + super(t); + } + + @Override + public final void serialize(final ItemWithSerializer value, final JsonGenerator jgen, final SerializerProvider provider) throws IOException, JsonProcessingException { + jgen.writeStartObject(); + jgen.writeNumberField("id", value.id); + jgen.writeStringField("itemName", value.itemName); + jgen.writeNumberField("owner", value.owner.id); + jgen.writeEndObject(); + } + +} \ No newline at end of file diff --git a/jackson/src/test/java/com/baeldung/jackson/serialization/MyDtoNullKeySerializer.java b/jackson-simple/src/test/java/com/baeldung/jackson/serialization/MyDtoNullKeySerializer.java similarity index 100% rename from jackson/src/test/java/com/baeldung/jackson/serialization/MyDtoNullKeySerializer.java rename to jackson-simple/src/test/java/com/baeldung/jackson/serialization/MyDtoNullKeySerializer.java diff --git a/jackson/src/test/java/com/baeldung/jackson/test/JacksonAnnotationUnitTest.java b/jackson-simple/src/test/java/com/baeldung/jackson/test/JacksonAnnotationUnitTest.java similarity index 91% rename from jackson/src/test/java/com/baeldung/jackson/test/JacksonAnnotationUnitTest.java rename to jackson-simple/src/test/java/com/baeldung/jackson/test/JacksonAnnotationUnitTest.java index 935777bad1..ee11f8f20e 100644 --- a/jackson/src/test/java/com/baeldung/jackson/test/JacksonAnnotationUnitTest.java +++ b/jackson-simple/src/test/java/com/baeldung/jackson/test/JacksonAnnotationUnitTest.java @@ -14,6 +14,7 @@ import java.util.TimeZone; import org.junit.Test; +import com.baeldung.jackson.annotation.AliasBean; import com.baeldung.jackson.annotation.BeanWithCreator; import com.baeldung.jackson.annotation.BeanWithCustomAnnotation; import com.baeldung.jackson.annotation.BeanWithFilter; @@ -36,6 +37,7 @@ import com.baeldung.jackson.date.EventWithSerializer; import com.baeldung.jackson.dtos.MyMixInForIgnoreType; import com.baeldung.jackson.dtos.withEnum.DistanceEnumWithValue; import com.baeldung.jackson.exception.UserWithRoot; +import com.baeldung.jackson.exception.UserWithRootNamespace; import com.baeldung.jackson.jsonview.Item; import com.baeldung.jackson.jsonview.Views; import com.fasterxml.jackson.core.JsonProcessingException; @@ -46,6 +48,7 @@ import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.ser.FilterProvider; import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter; import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider; +import com.fasterxml.jackson.dataformat.xml.XmlMapper; public class JacksonAnnotationUnitTest { @@ -372,5 +375,45 @@ public class JacksonAnnotationUnitTest { assertThat(result, containsString("1")); assertThat(result, containsString("name")); } + + @Test + public void whenDeserializingUsingJsonAlias_thenCorrect() throws IOException { + + // arrange + String json = "{\"fName\": \"John\", \"lastName\": \"Green\"}"; + + // act + AliasBean aliasBean = new ObjectMapper().readerFor(AliasBean.class).readValue(json); + + // assert + assertThat(aliasBean.getFirstName(), is("John")); + } + + @Test + public void whenSerializingUsingXMLRootNameWithNameSpace_thenCorrect() throws JsonProcessingException { + + // arrange + UserWithRootNamespace author = new UserWithRootNamespace(1, "John"); + + // act + ObjectMapper mapper = new XmlMapper(); + mapper = mapper.enable(SerializationFeature.WRAP_ROOT_VALUE).enable(SerializationFeature.INDENT_OUTPUT); + String result = mapper.writeValueAsString(author); + + // assert + assertThat(result, containsString("")); + + /* + + 3006b44a-cf62-4cfe-b3d8-30dc6c46ea96 + 1 + John + + + */ + + } + + } diff --git a/jackson/src/test/java/com/baeldung/jackson/test/JacksonSerializationIgnoreUnitTest.java b/jackson-simple/src/test/java/com/baeldung/jackson/test/JacksonSerializationIgnoreUnitTest.java similarity index 100% rename from jackson/src/test/java/com/baeldung/jackson/test/JacksonSerializationIgnoreUnitTest.java rename to jackson-simple/src/test/java/com/baeldung/jackson/test/JacksonSerializationIgnoreUnitTest.java diff --git a/jackson/src/test/java/com/baeldung/jackson/test/JacksonSerializationUnitTest.java b/jackson-simple/src/test/java/com/baeldung/jackson/test/JacksonSerializationUnitTest.java similarity index 100% rename from jackson/src/test/java/com/baeldung/jackson/test/JacksonSerializationUnitTest.java rename to jackson-simple/src/test/java/com/baeldung/jackson/test/JacksonSerializationUnitTest.java diff --git a/jackson-simple/src/test/resources/.gitignore b/jackson-simple/src/test/resources/.gitignore new file mode 100644 index 0000000000..83c05e60c8 --- /dev/null +++ b/jackson-simple/src/test/resources/.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/jackson/README.md b/jackson/README.md index 25194c7255..794ddc04d9 100644 --- a/jackson/README.md +++ b/jackson/README.md @@ -6,9 +6,7 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring ### Relevant Articles: -- [Jackson Ignore Properties on Marshalling](http://www.baeldung.com/jackson-ignore-properties-on-serialization) - [Jackson – Unmarshall to Collection/Array](http://www.baeldung.com/jackson-collection-array) -- [Jackson Unmarshalling json with Unknown Properties](http://www.baeldung.com/jackson-deserialize-json-unknown-properties) - [Jackson – Custom Serializer](http://www.baeldung.com/jackson-custom-serialization) - [Getting Started with Custom Deserialization in Jackson](http://www.baeldung.com/jackson-deserialization) - [Jackson Exceptions – Problems and Solutions](http://www.baeldung.com/jackson-exception) @@ -16,11 +14,9 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring - [Jackson – Bidirectional Relationships](http://www.baeldung.com/jackson-bidirectional-relationships-and-infinite-recursion) - [Jackson JSON Tutorial](http://www.baeldung.com/jackson) - [Jackson – Working with Maps and nulls](http://www.baeldung.com/jackson-map-null-values-or-null-key) -- [Jackson – Decide What Fields Get Serialized/Deserializaed](http://www.baeldung.com/jackson-field-serializable-deserializable-or-not) -- [Jackson Annotation Examples](http://www.baeldung.com/jackson-annotations) +- [Jackson – Decide What Fields Get Serialized/Deserialized](http://www.baeldung.com/jackson-field-serializable-deserializable-or-not) - [Working with Tree Model Nodes in Jackson](http://www.baeldung.com/jackson-json-node-tree-model) - [Jackson vs Gson](http://www.baeldung.com/jackson-vs-gson) -- [Intro to the Jackson ObjectMapper](http://www.baeldung.com/jackson-object-mapper-tutorial) - [XML Serialization and Deserialization with Jackson](http://www.baeldung.com/jackson-xml-serialization-and-deserialization) - [More Jackson Annotations](http://www.baeldung.com/jackson-advanced-annotations) - [Inheritance with Jackson](http://www.baeldung.com/jackson-inheritance) @@ -31,10 +27,10 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring - [Jackson – JsonMappingException (No serializer found for class)](http://www.baeldung.com/jackson-jsonmappingexception) - [How To Serialize Enums as JSON Objects with Jackson](http://www.baeldung.com/jackson-serialize-enums) - [Jackson – Marshall String to JsonNode](http://www.baeldung.com/jackson-json-to-jsonnode) -- [Ignore Null Fields with Jackson](http://www.baeldung.com/jackson-ignore-null-fields) - [Jackson – Unmarshall to Collection/Array](http://www.baeldung.com/jackson-collection-array) -- [Jackson – Change Name of Field](http://www.baeldung.com/jackson-name-of-property) - [Serialize Only Fields that meet a Custom Criteria with Jackson](http://www.baeldung.com/jackson-serialize-field-custom-criteria) - [Mapping Nested Values with Jackson](http://www.baeldung.com/jackson-nested-values) - [Convert XML to JSON Using Jackson](https://www.baeldung.com/jackson-convert-xml-json) - [Deserialize Immutable Objects with Jackson](https://www.baeldung.com/jackson-deserialize-immutable-objects) +- [Mapping a Dynamic JSON Object with Jackson](https://www.baeldung.com/jackson-mapping-dynamic-object) + diff --git a/jackson/src/main/java/com/baeldung/jackson/deserialization/jacksoninject/Author.java b/jackson/src/main/java/com/baeldung/jackson/deserialization/jacksoninject/Author.java deleted file mode 100644 index db8b594509..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/deserialization/jacksoninject/Author.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.baeldung.jackson.deserialization.jacksoninject; - -import com.baeldung.jackson.domain.Item; - -import java.util.ArrayList; -import java.util.List; - -public class Author extends Person { - - List items = new ArrayList<>(); - - public Author() { - } - - public Author(String firstName, String lastName) { - super(firstName, lastName); - } - - public List getItems() { - return items; - } - - public void setItems(List items) { - this.items = items; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/deserialization/jsonanysetter/Inventory.java b/jackson/src/main/java/com/baeldung/jackson/deserialization/jsonanysetter/Inventory.java index c4daf68bd6..d9748e2997 100644 --- a/jackson/src/main/java/com/baeldung/jackson/deserialization/jsonanysetter/Inventory.java +++ b/jackson/src/main/java/com/baeldung/jackson/deserialization/jsonanysetter/Inventory.java @@ -1,24 +1,14 @@ package com.baeldung.jackson.deserialization.jsonanysetter; -import com.baeldung.jackson.domain.Author; -import com.baeldung.jackson.domain.Item; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnore; - import java.util.HashMap; import java.util.Map; +import com.fasterxml.jackson.annotation.JsonAnySetter; + public class Inventory { - private Map stock = new HashMap<>(); - private Map countryDeliveryCost = new HashMap<>(); - @JsonIgnore - public Map getStock() { - return stock; - } - public Map getCountryDeliveryCost() { return countryDeliveryCost; } diff --git a/jackson/src/main/java/com/baeldung/jackson/deserialization/jsoncreator/Author.java b/jackson/src/main/java/com/baeldung/jackson/deserialization/jsoncreator/Author.java deleted file mode 100644 index d48c95b255..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/deserialization/jsoncreator/Author.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.baeldung.jackson.deserialization.jsoncreator; - -import com.baeldung.jackson.domain.Person; -import com.baeldung.jackson.domain.Item; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; - -import java.util.ArrayList; -import java.util.List; - -public class Author extends Person { - - List items = new ArrayList<>(); - - @JsonCreator - public Author(@JsonProperty("christianName") String firstName, @JsonProperty("surname") String lastName) { - super(firstName, lastName); - } - - public List getItems() { - return items; - } - - public void setItems(List items) { - this.items = items; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/deserialization/jsondeserialize/Author.java b/jackson/src/main/java/com/baeldung/jackson/deserialization/jsondeserialize/Author.java deleted file mode 100644 index 62e108facb..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/deserialization/jsondeserialize/Author.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.baeldung.jackson.deserialization.jsondeserialize; - -import com.baeldung.jackson.domain.Item; -import com.baeldung.jackson.domain.Person; - -import java.util.ArrayList; -import java.util.List; - -public class Author extends Person { - - List items = new ArrayList<>(); - - public Author(String firstName, String lastName) { - super(firstName, lastName); - } - - public List getItems() { - return items; - } - - public void setItems(List items) { - this.items = items; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/deserialization/jsondeserialize/Book.java b/jackson/src/main/java/com/baeldung/jackson/deserialization/jsondeserialize/Book.java index dc0d0ee623..1e411da64e 100644 --- a/jackson/src/main/java/com/baeldung/jackson/deserialization/jsondeserialize/Book.java +++ b/jackson/src/main/java/com/baeldung/jackson/deserialization/jsondeserialize/Book.java @@ -1,12 +1,16 @@ package com.baeldung.jackson.deserialization.jsondeserialize; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; - import java.math.BigDecimal; import java.util.Date; +import java.util.UUID; -public class Book extends Item { +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +public class Book { + + private UUID id; + private String title; + private float price; private String ISBN; @JsonDeserialize(using = CustomDateDeserializer.class) @@ -16,8 +20,9 @@ public class Book extends Item { public Book() { } - public Book(String title, Author author) { - super(title, author); + public Book(String title) { + this.id = UUID.randomUUID(); + this.title = title; } public String getISBN() { @@ -43,4 +48,28 @@ public class Book extends Item { public void setPages(BigDecimal pages) { this.pages = pages; } + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public float getPrice() { + return price; + } + + public void setPrice(float price) { + this.price = price; + } } diff --git a/jackson/src/main/java/com/baeldung/jackson/deserialization/jsondeserialize/Item.java b/jackson/src/main/java/com/baeldung/jackson/deserialization/jsondeserialize/Item.java deleted file mode 100644 index fc27a586ac..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/deserialization/jsondeserialize/Item.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.baeldung.jackson.deserialization.jsondeserialize; - -import com.baeldung.jackson.domain.Person; - -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Item { - - private UUID id; - private String title; - private List authors = new ArrayList<>(); - private float price; - - public Item() { - } - - public Item(String title, Author author) { - this.id = UUID.randomUUID(); - this.title = title; - this.authors.add(author); - } - - public UUID getId() { - return id; - } - - public void setId(UUID id) { - this.id = id; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public List getAuthors() { - return authors; - } - - public void setAuthors(List authors) { - this.authors = authors; - } - - public float getPrice() { - return price; - } - - public void setPrice(float price) { - this.price = price; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/deserialization/jsonsetter/Author.java b/jackson/src/main/java/com/baeldung/jackson/deserialization/jsonsetter/Author.java deleted file mode 100644 index 3f9ae70a88..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/deserialization/jsonsetter/Author.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.baeldung.jackson.deserialization.jsonsetter; - -import com.baeldung.jackson.domain.Item; -import com.baeldung.jackson.domain.Person; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonSetter; - -import java.util.ArrayList; -import java.util.List; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Author extends Person { - - private List items = new ArrayList<>(); - - public Author() { - } - - public Author(String firstName, String lastName) { - super(firstName, lastName); - } - - @JsonIgnore - public List getItems() { - return items; - } - - @JsonSetter("publications") - public void setItems(List items) { - this.items = items; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/domain/Author.java b/jackson/src/main/java/com/baeldung/jackson/domain/Author.java deleted file mode 100644 index 9000c00f21..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/domain/Author.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.baeldung.jackson.domain; - -import java.util.ArrayList; -import java.util.List; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Author extends Person { - - private List items = new ArrayList<>(); - - public Author(String firstName, String lastName) { - super(firstName, lastName); - } - - public List getItems() { - return items; - } - - public void setItems(List items) { - this.items = items; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/domain/Book.java b/jackson/src/main/java/com/baeldung/jackson/domain/Book.java deleted file mode 100644 index a5963e33ba..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/domain/Book.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.baeldung.jackson.domain; - -import java.math.BigDecimal; -import java.util.Date; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Book extends Item { - - private String ISBN; - private Date published; - private BigDecimal pages; - - public Book() { - } - - public Book(String title, Author author) { - super(title, author); - } - - public String getISBN() { - return ISBN; - } - - public void setISBN(String ISBN) { - this.ISBN = ISBN; - } - - public Date getPublished() { - return published; - } - - public void setPublished(Date published) { - this.published = published; - } - - public BigDecimal getPages() { - return pages; - } - - public void setPages(BigDecimal pages) { - this.pages = pages; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/domain/Course.java b/jackson/src/main/java/com/baeldung/jackson/domain/Course.java deleted file mode 100644 index 672b0bc250..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/domain/Course.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.baeldung.jackson.domain; - -import java.util.List; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Course extends Item { - - public enum Medium { - CLASSROOM, ONLINE - } - - public enum Level { - BEGINNER("Beginner", 1), INTERMEDIATE("Intermediate", 2), ADVANCED("Advanced", 3); - - private String name; - private int number; - - Level(String name, int number) { - this.name = name; - this.number = number; - } - - public String getName() { - return name; - } - } - - private float duration; - private Medium medium; - private Level level; - private List prerequisite; - - public Course(String title, Author author) { - super(title, author); - } - - public float getDuration() { - return duration; - } - - public void setDuration(float duration) { - this.duration = duration; - } - - public Medium getMedium() { - return medium; - } - - public void setMedium(Medium medium) { - this.medium = medium; - } - - public Level getLevel() { - return level; - } - - public void setLevel(Level level) { - this.level = level; - } - - public List getPrerequisite() { - return prerequisite; - } - - public void setPrerequisite(List prerequisite) { - this.prerequisite = prerequisite; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/domain/Customer.java b/jackson/src/main/java/com/baeldung/jackson/domain/Customer.java deleted file mode 100644 index 1e03ff9a13..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/domain/Customer.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.baeldung.jackson.domain; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Customer extends Person { - - private String configuration; - - public Customer(String firstName, String lastName) { - super(firstName, lastName); - } - - public String getConfiguration() { - return configuration; - } - - public void setConfiguration(String configuration) { - this.configuration = configuration; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/domain/Inventory.java b/jackson/src/main/java/com/baeldung/jackson/domain/Inventory.java deleted file mode 100644 index 41b7dc51da..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/domain/Inventory.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.baeldung.jackson.domain; - -import java.util.HashMap; -import java.util.Map; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Inventory { - - private Map stock; - - private Map countryDeliveryCost = new HashMap<>(); - - public Map getStock() { - return stock; - } - - public void setStock(Map stock) { - this.stock = stock; - } - - public Map getCountryDeliveryCost() { - return countryDeliveryCost; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/domain/Item.java b/jackson/src/main/java/com/baeldung/jackson/domain/Item.java deleted file mode 100644 index d9d1350a8e..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/domain/Item.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.baeldung.jackson.domain; - -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Item { - - private UUID id; - private String title; - private List authors = new ArrayList<>(); - private float price; - - public Item() { - } - - public Item(String title, Author author) { - this.id = UUID.randomUUID(); - this.title = title; - this.authors.add(author); - } - - public UUID getId() { - return id; - } - - public void setId(UUID id) { - this.id = id; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public List getAuthors() { - return authors; - } - - public void setAuthors(List authors) { - this.authors = authors; - } - - public float getPrice() { - return price; - } - - public void setPrice(float price) { - this.price = price; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/domain/Order.java b/jackson/src/main/java/com/baeldung/jackson/domain/Order.java deleted file mode 100644 index 91f87f74df..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/domain/Order.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.baeldung.jackson.domain; - -import java.util.UUID; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Order { - - private UUID id; - private Type type; - private int internalAudit; - - public static class Type { - public long id; - public String name; - } - - public Order() { - this.id = UUID.randomUUID(); - } - - public Order(Type type) { - this(); - this.type = type; - } - - public Order(int internalAudit) { - this(); - this.type = new Type(); - this.type.id = 20; - this.type.name = "Order"; - this.internalAudit = internalAudit; - } - - public UUID getId() { - return id; - } - - public Type getType() { - return type; - } - - public void setType(Type type) { - this.type = type; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/domain/Person.java b/jackson/src/main/java/com/baeldung/jackson/domain/Person.java index 785efff755..f11ba41113 100644 --- a/jackson/src/main/java/com/baeldung/jackson/domain/Person.java +++ b/jackson/src/main/java/com/baeldung/jackson/domain/Person.java @@ -1,24 +1,12 @@ package com.baeldung.jackson.domain; -import java.util.UUID; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ public class Person { - private UUID id; private String firstName; private String lastName; - - public Person() { - } - + public Person(String firstName, String lastName) { - this.id = UUID.randomUUID(); + super(); this.firstName = firstName; this.lastName = lastName; } @@ -38,8 +26,5 @@ public class Person { public void setLastName(String lastName) { this.lastName = lastName; } - - public UUID getId() { - return id; - } } + diff --git a/jackson/src/main/java/com/baeldung/jackson/inclusion/jsonautodetect/Order.java b/jackson/src/main/java/com/baeldung/jackson/inclusion/jsonautodetect/Order.java deleted file mode 100644 index f2ff5eeb08..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/inclusion/jsonautodetect/Order.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.baeldung.jackson.inclusion.jsonautodetect; - -import com.fasterxml.jackson.annotation.JsonAutoDetect; -import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility; - -import java.util.UUID; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -@JsonAutoDetect(fieldVisibility = Visibility.ANY) -public class Order { - - private UUID id; - private Type type; - private int internalAudit; - - public static class Type { - public long id; - public String name; - } - - public Order() { - this.id = UUID.randomUUID(); - } - - public Order(Type type) { - this(); - this.type = type; - } - - public Order(int internalAudit) { - this(); - this.type = new Type(); - this.type.id = 20; - this.type.name = "Order"; - this.internalAudit = internalAudit; - } - - public UUID getId() { - return id; - } - - public Type getType() { - return type; - } - - public void setType(Type type) { - this.type = type; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/inclusion/jsonignore/Author.java b/jackson/src/main/java/com/baeldung/jackson/inclusion/jsonignore/Author.java deleted file mode 100644 index a7801493bf..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/inclusion/jsonignore/Author.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.baeldung.jackson.inclusion.jsonignore; - -import com.baeldung.jackson.domain.Item; - -import java.util.ArrayList; -import java.util.List; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Author extends Person { - - private List items = new ArrayList<>(); - - public Author(String firstName, String lastName) { - super(firstName, lastName); - } - - public List getItems() { - return items; - } - - public void setItems(List items) { - this.items = items; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/inclusion/jsonignore/Person.java b/jackson/src/main/java/com/baeldung/jackson/inclusion/jsonignore/Person.java deleted file mode 100644 index 0037d83148..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/inclusion/jsonignore/Person.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.baeldung.jackson.inclusion.jsonignore; - -import com.fasterxml.jackson.annotation.JsonIgnore; - -import java.util.UUID; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Person { - - @JsonIgnore - private UUID id; - private String firstName; - private String lastName; - - public Person() { - } - - public Person(String firstName, String lastName) { - this.id = UUID.randomUUID(); - this.firstName = firstName; - this.lastName = lastName; - } - - public String getFirstName() { - return firstName; - } - - public void setFirstName(String firstName) { - this.firstName = firstName; - } - - public String getLastName() { - return lastName; - } - - public void setLastName(String lastName) { - this.lastName = lastName; - } - - public UUID getId() { - return id; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/inclusion/jsonignoreproperties/Course.java b/jackson/src/main/java/com/baeldung/jackson/inclusion/jsonignoreproperties/Course.java deleted file mode 100644 index 70b4dd9842..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/inclusion/jsonignoreproperties/Course.java +++ /dev/null @@ -1,78 +0,0 @@ -package com.baeldung.jackson.inclusion.jsonignoreproperties; - -import com.baeldung.jackson.domain.Author; -import com.baeldung.jackson.domain.Item; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -import java.util.List; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -@JsonIgnoreProperties({ "medium" }) -public class Course extends Item { - - public enum Medium { - CLASSROOM, ONLINE - } - - public enum Level { - BEGINNER("Beginner", 1), INTERMEDIATE("Intermediate", 2), ADVANCED("Advanced", 3); - - private String name; - private int number; - - Level(String name, int number) { - this.name = name; - this.number = number; - } - - public String getName() { - return name; - } - } - - private float duration; - private Medium medium; - private Level level; - private List prerequisite; - - public Course(String title, Author author) { - super(title, author); - } - - public float getDuration() { - return duration; - } - - public void setDuration(float duration) { - this.duration = duration; - } - - public Medium getMedium() { - return medium; - } - - public void setMedium(Medium medium) { - this.medium = medium; - } - - public Level getLevel() { - return level; - } - - public void setLevel(Level level) { - this.level = level; - } - - public List getPrerequisite() { - return prerequisite; - } - - public void setPrerequisite(List prerequisite) { - this.prerequisite = prerequisite; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/inclusion/jsonignoretype/Order.java b/jackson/src/main/java/com/baeldung/jackson/inclusion/jsonignoretype/Order.java deleted file mode 100644 index 0d8867933f..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/inclusion/jsonignoretype/Order.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.baeldung.jackson.inclusion.jsonignoretype; - -import com.fasterxml.jackson.annotation.JsonIgnoreType; - -import java.util.UUID; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Order { - - private UUID id; - private Type type; - - @JsonIgnoreType - public static class Type { - public long id; - public String name; - } - - public Order() { - this.id = UUID.randomUUID(); - } - - public Order(Type type) { - this(); - this.type = type; - } - - public UUID getId() { - return id; - } - - public Type getType() { - return type; - } - - public void setType(Type type) { - this.type = type; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/inclusion/jsoninclude/Author.java b/jackson/src/main/java/com/baeldung/jackson/inclusion/jsoninclude/Author.java deleted file mode 100644 index 30cb2735c2..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/inclusion/jsoninclude/Author.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.baeldung.jackson.inclusion.jsoninclude; - -import com.baeldung.jackson.domain.Person; -import com.baeldung.jackson.domain.Item; -import com.fasterxml.jackson.annotation.JsonInclude; - -import java.util.ArrayList; -import java.util.List; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -@JsonInclude(NON_NULL) -public class Author extends Person { - - private List items = new ArrayList<>(); - - public Author(String firstName, String lastName) { - super(firstName, lastName); - } - - public List getItems() { - return items; - } - - public void setItems(List items) { - this.items = items; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/miscellaneous/custom/Course.java b/jackson/src/main/java/com/baeldung/jackson/miscellaneous/custom/Course.java deleted file mode 100644 index a44492b9f7..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/miscellaneous/custom/Course.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.baeldung.jackson.miscellaneous.custom; - -import com.baeldung.jackson.domain.Author; - -import java.util.List; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -@CustomCourseAnnotation -public class Course extends Item { - - public enum Medium { - CLASSROOM, ONLINE - } - - public enum Level { - BEGINNER("Beginner", 1), INTERMEDIATE("Intermediate", 2), ADVANCED("Advanced", 3); - - private String name; - private int number; - - Level(String name, int number) { - this.name = name; - this.number = number; - } - - public String getName() { - return name; - } - } - - private float duration; - private Medium medium; - private Level level; - private List prerequisite; - - public Course(String title, Author author) { - super(title, author); - } - - public float getDuration() { - return duration; - } - - public void setDuration(float duration) { - this.duration = duration; - } - - public Medium getMedium() { - return medium; - } - - public void setMedium(Medium medium) { - this.medium = medium; - } - - public Level getLevel() { - return level; - } - - public void setLevel(Level level) { - this.level = level; - } - - public List getPrerequisite() { - return prerequisite; - } - - public void setPrerequisite(List prerequisite) { - this.prerequisite = prerequisite; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/miscellaneous/custom/CustomCourseAnnotation.java b/jackson/src/main/java/com/baeldung/jackson/miscellaneous/custom/CustomCourseAnnotation.java deleted file mode 100644 index d7f72ca6ec..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/miscellaneous/custom/CustomCourseAnnotation.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.baeldung.jackson.miscellaneous.custom; - -import com.fasterxml.jackson.annotation.*; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -@Retention(RetentionPolicy.RUNTIME) -@JacksonAnnotationsInside -@JsonInclude(JsonInclude.Include.NON_NULL) -@JsonPropertyOrder({ "title", "price", "id", "duration", "authors", "level" }) -@JsonIgnoreProperties({ "prerequisite" }) -public @interface CustomCourseAnnotation { -} diff --git a/jackson/src/main/java/com/baeldung/jackson/miscellaneous/custom/Item.java b/jackson/src/main/java/com/baeldung/jackson/miscellaneous/custom/Item.java deleted file mode 100644 index 6625283dec..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/miscellaneous/custom/Item.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.baeldung.jackson.miscellaneous.custom; - -import com.baeldung.jackson.domain.Author; -import com.baeldung.jackson.domain.Person; - -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Item { - - private UUID id; - private String title; - private List authors = new ArrayList<>(); - private float price; - - public Item() { - } - - public Item(String title, Author author) { - this.id = UUID.randomUUID(); - this.title = title; - this.authors.add(author); - } - - public UUID getId() { - return id; - } - - public void setId(UUID id) { - this.id = id; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public List getAuthors() { - return authors; - } - - public void setAuthors(List authors) { - this.authors = authors; - } - - public float getPrice() { - return price; - } - - public void setPrice(float price) { - this.price = price; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/miscellaneous/disable/Author.java b/jackson/src/main/java/com/baeldung/jackson/miscellaneous/disable/Author.java deleted file mode 100644 index 0638e32925..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/miscellaneous/disable/Author.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.baeldung.jackson.miscellaneous.disable; - -import com.baeldung.jackson.domain.Item; -import com.baeldung.jackson.domain.Person; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; - -import java.util.ArrayList; -import java.util.List; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -@JsonInclude(JsonInclude.Include.NON_NULL) -@JsonPropertyOrder({ "lastName", "items", "firstName", "id" }) -public class Author extends Person { - - @JsonIgnore - private List items = new ArrayList<>(); - - public Author(String firstName, String lastName) { - super(firstName, lastName); - } - - public List getItems() { - return items; - } - - public void setItems(List items) { - this.items = items; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/miscellaneous/mixin/Author.java b/jackson/src/main/java/com/baeldung/jackson/miscellaneous/mixin/Author.java deleted file mode 100644 index 26e3e4b647..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/miscellaneous/mixin/Author.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.baeldung.jackson.miscellaneous.mixin; - -import com.baeldung.jackson.domain.Item; -import com.baeldung.jackson.domain.Person; - -import java.util.ArrayList; -import java.util.List; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Author extends Person { - - private List items = new ArrayList<>(); - - public Author(String firstName, String lastName) { - super(firstName, lastName); - } - - public List getItems() { - return items; - } - - public void setItems(List items) { - this.items = items; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/miscellaneous/mixin/IgnoreListMixIn.java b/jackson/src/main/java/com/baeldung/jackson/miscellaneous/mixin/IgnoreListMixIn.java deleted file mode 100644 index 418c09c251..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/miscellaneous/mixin/IgnoreListMixIn.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.baeldung.jackson.miscellaneous.mixin; - -import com.fasterxml.jackson.annotation.JsonIgnoreType; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -@JsonIgnoreType -public class IgnoreListMixIn { -} diff --git a/jackson/src/main/java/com/baeldung/jackson/polymorphism/Order.java b/jackson/src/main/java/com/baeldung/jackson/polymorphism/Order.java deleted file mode 100644 index 1813148b2b..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/polymorphism/Order.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.baeldung.jackson.polymorphism; - -import com.fasterxml.jackson.annotation.JsonSubTypes; -import com.fasterxml.jackson.annotation.JsonTypeInfo; -import com.fasterxml.jackson.annotation.JsonTypeName; - -import java.util.UUID; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Order { - - private UUID id; - private Type type; - private int internalAudit; - - @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "ordertype") - @JsonSubTypes({ @JsonSubTypes.Type(value = InternalType.class, name = "internal") }) - public static class Type { - public long id; - public String name; - } - - @JsonTypeName("internal") - public static class InternalType extends Type { - public long id; - public String name; - } - - public Order() { - this.id = UUID.randomUUID(); - } - - public Order(Type type) { - this(); - this.type = type; - } - - public Order(int internalAudit) { - this(); - this.type = new Type(); - this.type.id = 20; - this.type.name = "Order"; - this.internalAudit = internalAudit; - } - - public UUID getId() { - return id; - } - - public Type getType() { - return type; - } - - public void setType(Type type) { - this.type = type; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/serialization/jsonanygetter/Inventory.java b/jackson/src/main/java/com/baeldung/jackson/serialization/jsonanygetter/Inventory.java deleted file mode 100644 index 52f586d93b..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/serialization/jsonanygetter/Inventory.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.baeldung.jackson.serialization.jsonanygetter; - -import com.baeldung.jackson.domain.Author; -import com.baeldung.jackson.domain.Item; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonIgnore; - -import java.util.HashMap; -import java.util.Map; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Inventory { - - private String location; - - private Map stock = new HashMap<>(); - - private Map countryDeliveryCost = new HashMap<>(); - - public String getLocation() { - return location; - } - - public void setLocation(String location) { - this.location = location; - } - - @JsonIgnore - public Map getStock() { - return stock; - } - - @JsonAnyGetter - public Map getCountryDeliveryCost() { - return countryDeliveryCost; - } - -} diff --git a/jackson/src/main/java/com/baeldung/jackson/serialization/jsongetter/Author.java b/jackson/src/main/java/com/baeldung/jackson/serialization/jsongetter/Author.java deleted file mode 100644 index 8d89fefce7..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/serialization/jsongetter/Author.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.baeldung.jackson.serialization.jsongetter; - -import com.baeldung.jackson.domain.Item; -import com.baeldung.jackson.domain.Person; -import com.fasterxml.jackson.annotation.JsonGetter; - -import java.util.ArrayList; -import java.util.List; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Author extends Person { - - List items = new ArrayList<>(); - - public Author(String firstName, String lastName) { - super(firstName, lastName); - } - - @JsonGetter("publications") - public List getItems() { - return items; - } - - public void setItems(List items) { - this.items = items; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/serialization/jsonpropertyorder/Author.java b/jackson/src/main/java/com/baeldung/jackson/serialization/jsonpropertyorder/Author.java deleted file mode 100644 index dadf893cf9..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/serialization/jsonpropertyorder/Author.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.baeldung.jackson.serialization.jsonpropertyorder; - -import com.baeldung.jackson.domain.Item; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; - -import java.util.ArrayList; -import java.util.List; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -@JsonPropertyOrder({ "items", "firstName", "lastName", "id" }) -public class Author extends Person { - - List items = new ArrayList<>(); - - public Author(String firstName, String lastName) { - super(firstName, lastName); - } - - public List getItems() { - return items; - } - - public void setItems(List items) { - this.items = items; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/serialization/jsonpropertyorder/Person.java b/jackson/src/main/java/com/baeldung/jackson/serialization/jsonpropertyorder/Person.java deleted file mode 100644 index 519e48aada..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/serialization/jsonpropertyorder/Person.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.baeldung.jackson.serialization.jsonpropertyorder; - -import java.util.UUID; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Person { - - private UUID id; - private String firstName; - private String lastName; - - public Person(String firstName, String lastName) { - this.id = UUID.randomUUID(); - this.firstName = firstName; - this.lastName = lastName; - } - - public String getFirstName() { - return firstName; - } - - public void setFirstName(String firstName) { - this.firstName = firstName; - } - - public String getLastName() { - return lastName; - } - - public void setLastName(String lastName) { - this.lastName = lastName; - } - - public UUID getId() { - return id; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/serialization/jsonrawvalue/Customer.java b/jackson/src/main/java/com/baeldung/jackson/serialization/jsonrawvalue/Customer.java deleted file mode 100644 index f19c5314d2..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/serialization/jsonrawvalue/Customer.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.baeldung.jackson.serialization.jsonrawvalue; - -import com.baeldung.jackson.domain.Person; -import com.fasterxml.jackson.annotation.JsonRawValue; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Customer extends Person { - - @JsonRawValue - private String configuration; - - public Customer(String firstName, String lastName) { - super(firstName, lastName); - } - - public String getConfiguration() { - return configuration; - } - - public void setConfiguration(String configuration) { - this.configuration = configuration; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/serialization/jsonrootname/Author.java b/jackson/src/main/java/com/baeldung/jackson/serialization/jsonrootname/Author.java deleted file mode 100644 index c6ebfd10fb..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/serialization/jsonrootname/Author.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.baeldung.jackson.serialization.jsonrootname; - -import com.baeldung.jackson.domain.Item; -import com.baeldung.jackson.domain.Person; -import com.fasterxml.jackson.annotation.JsonRootName; - -import java.util.ArrayList; -import java.util.List; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -@JsonRootName("writer") -public class Author extends Person { - - List items = new ArrayList<>(); - - public Author(String firstName, String lastName) { - super(firstName, lastName); - } - - public List getItems() { - return items; - } - - public void setItems(List items) { - this.items = items; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/serialization/jsonserialize/Author.java b/jackson/src/main/java/com/baeldung/jackson/serialization/jsonserialize/Author.java deleted file mode 100644 index 5a6e90d712..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/serialization/jsonserialize/Author.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.baeldung.jackson.serialization.jsonserialize; - -import com.baeldung.jackson.domain.Person; - -import java.util.ArrayList; -import java.util.List; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Author extends Person { - - List items = new ArrayList<>(); - - public Author(String firstName, String lastName) { - super(firstName, lastName); - } - - public List getItems() { - return items; - } - - public void setItems(List items) { - this.items = items; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/serialization/jsonserialize/Book.java b/jackson/src/main/java/com/baeldung/jackson/serialization/jsonserialize/Book.java deleted file mode 100644 index 0ecc4e72ce..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/serialization/jsonserialize/Book.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.baeldung.jackson.serialization.jsonserialize; - -import com.fasterxml.jackson.databind.annotation.JsonSerialize; - -import java.math.BigDecimal; -import java.util.Date; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Book extends Item { - - private String ISBN; - - @JsonSerialize(using = CustomDateSerializer.class) - private Date published; - private BigDecimal pages; - - public Book() { - } - - public Book(String title, Author author) { - super(title, author); - } - - public String getISBN() { - return ISBN; - } - - public void setISBN(String ISBN) { - this.ISBN = ISBN; - } - - public Date getPublished() { - return published; - } - - public void setPublished(Date published) { - this.published = published; - } - - public BigDecimal getPages() { - return pages; - } - - public void setPages(BigDecimal pages) { - this.pages = pages; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/serialization/jsonserialize/Item.java b/jackson/src/main/java/com/baeldung/jackson/serialization/jsonserialize/Item.java deleted file mode 100644 index 56cfa85793..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/serialization/jsonserialize/Item.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.baeldung.jackson.serialization.jsonserialize; - -import com.baeldung.jackson.domain.Person; - -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Item { - - private UUID id; - private String title; - private List authors = new ArrayList<>(); - private float price; - - public Item() { - } - - public Item(String title, Author author) { - this.id = UUID.randomUUID(); - this.title = title; - this.authors.add(author); - } - - public UUID getId() { - return id; - } - - public void setId(UUID id) { - this.id = id; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public List getAuthors() { - return authors; - } - - public void setAuthors(List authors) { - this.authors = authors; - } - - public float getPrice() { - return price; - } - - public void setPrice(float price) { - this.price = price; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/serialization/jsonvalue/Course.java b/jackson/src/main/java/com/baeldung/jackson/serialization/jsonvalue/Course.java deleted file mode 100644 index a3fdc2d8eb..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/serialization/jsonvalue/Course.java +++ /dev/null @@ -1,78 +0,0 @@ -package com.baeldung.jackson.serialization.jsonvalue; - -import com.baeldung.jackson.domain.Author; -import com.baeldung.jackson.domain.Item; -import com.fasterxml.jackson.annotation.JsonValue; - -import java.util.List; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Course extends Item { - - public enum Medium { - CLASSROOM, ONLINE - } - - public enum Level { - BEGINNER("Beginner", 1), INTERMEDIATE("Intermediate", 2), ADVANCED("Advanced", 3); - - private String name; - private int number; - - Level(String name, int number) { - this.name = name; - this.number = number; - } - - @JsonValue - public String getName() { - return name; - } - } - - private float duration; - private Medium medium; - private Level level; - private List prerequisite; - - public Course(String title, Author author) { - super(title, author); - } - - public float getDuration() { - return duration; - } - - public void setDuration(float duration) { - this.duration = duration; - } - - public Medium getMedium() { - return medium; - } - - public void setMedium(Medium medium) { - this.medium = medium; - } - - public Level getLevel() { - return level; - } - - public void setLevel(Level level) { - this.level = level; - } - - public List getPrerequisite() { - return prerequisite; - } - - public void setPrerequisite(List prerequisite) { - this.prerequisite = prerequisite; - } -} diff --git a/jackson/src/test/java/com/baeldung/jackson/deserialization/jacksoninject/JacksonInjectUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/deserialization/jacksoninject/JacksonInjectUnitTest.java deleted file mode 100644 index 96dbff6f3c..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/deserialization/jacksoninject/JacksonInjectUnitTest.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.baeldung.jackson.deserialization.jacksoninject; - -import com.fasterxml.jackson.databind.InjectableValues; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import java.io.IOException; -import java.util.UUID; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class JacksonInjectUnitTest { - - @Test - public void whenDeserializingUsingJacksonInject_thenCorrect() throws IOException { - - UUID id = UUID.fromString("9616dc8c-bad3-11e6-a4a6-cec0c932ce01"); - - // arrange - String authorJson = "{\"firstName\": \"Alex\", \"lastName\": \"Theedom\"}"; - - // act - InjectableValues inject = new InjectableValues.Std().addValue(UUID.class, id); - Author author = new ObjectMapper().reader(inject) - .forType(Author.class) - .readValue(authorJson); - - // assert - assertThat(author.getId()).isEqualTo(id); - - /* - { - "firstName": "Alex", - "lastName": "Theedom", - "publications": [] - } - */ - - } -} \ No newline at end of file diff --git a/jackson/src/test/java/com/baeldung/jackson/deserialization/jsonanysetter/JsonAnySetterUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/deserialization/jsonanysetter/JsonAnySetterUnitTest.java deleted file mode 100644 index 2e1f94bc3c..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/deserialization/jsonanysetter/JsonAnySetterUnitTest.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.baeldung.jackson.deserialization.jsonanysetter; - -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import java.io.IOException; - -import static io.restassured.path.json.JsonPath.from; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class JsonAnySetterUnitTest { - - @Test - public void whenDeserializingUsingJsonAnySetter_thenCorrect() throws IOException { - - // arrange - String json = "{\"USA\":10.00,\"UK\":15.00,\"China\":23.00,\"Brazil\":12.00,\"France\":8.00,\"Russia\":18.00}"; - - // act - Inventory inventory = new ObjectMapper().readerFor(Inventory.class) - .readValue(json); - - // assert - assertThat(from(json).getMap(".") - .get("USA")).isEqualTo(inventory.getCountryDeliveryCost() - .get("USA")); - assertThat(from(json).getMap(".") - .get("UK")).isEqualTo(inventory.getCountryDeliveryCost() - .get("UK")); - assertThat(from(json).getMap(".") - .get("China")).isEqualTo(inventory.getCountryDeliveryCost() - .get("China")); - assertThat(from(json).getMap(".") - .get("Brazil")).isEqualTo(inventory.getCountryDeliveryCost() - .get("Brazil")); - assertThat(from(json).getMap(".") - .get("France")).isEqualTo(inventory.getCountryDeliveryCost() - .get("France")); - assertThat(from(json).getMap(".") - .get("Russia")).isEqualTo(inventory.getCountryDeliveryCost() - .get("Russia")); - - } -} \ No newline at end of file diff --git a/jackson/src/test/java/com/baeldung/jackson/deserialization/jsoncreator/JsonCreatorUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/deserialization/jsoncreator/JsonCreatorUnitTest.java deleted file mode 100644 index cc245dab66..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/deserialization/jsoncreator/JsonCreatorUnitTest.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.baeldung.jackson.deserialization.jsoncreator; - -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import java.io.IOException; - -import static io.restassured.path.json.JsonPath.from; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class JsonCreatorUnitTest { - - @Test - public void whenDeserializingUsingJsonCreator_thenCorrect() throws IOException { - - // arrange - String authorJson = "{" + " \"christianName\": \"Alex\"," + " \"surname\": \"Theedom\"" + "}"; - - // act - final Author author = new ObjectMapper().readerFor(Author.class) - .readValue(authorJson); - - // assert - assertThat(from(authorJson).getString("christianName")).isEqualTo(author.getFirstName()); - assertThat(from(authorJson).getString("surname")).isEqualTo(author.getLastName()); - - /* - { - "christianName": "Alex", - "surname": "Theedom" - } - */ - - } -} \ No newline at end of file diff --git a/jackson/src/test/java/com/baeldung/jackson/deserialization/jsondeserialize/JsonDeserializeUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/deserialization/jsondeserialize/JsonDeserializeUnitTest.java deleted file mode 100644 index 1bcde998d6..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/deserialization/jsondeserialize/JsonDeserializeUnitTest.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.baeldung.jackson.deserialization.jsondeserialize; - -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import java.io.IOException; -import java.text.SimpleDateFormat; - -import static io.restassured.path.json.JsonPath.from; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class JsonDeserializeUnitTest { - - @Test - public void whenDeserializingUsingJsonDeserialize_thenCorrect() throws IOException { - - // arrange - String bookJson = "{\"id\":\"957c43f2-fa2e-42f9-bf75-6e3d5bb6960a\",\"title\":\"Effective Java\",\"authors\":[{\"id\":\"9bcd817d-0141-42e6-8f04-e5aaab0980b6\",\"firstName\":\"Joshua\",\"lastName\":\"Bloch\"}],\"price\":0,\"published\":\"25-12-2017 13:30:25\",\"pages\":null,\"isbn\":null}"; - - // act - Book book = new ObjectMapper().readerFor(Book.class) - .readValue(bookJson); - - // assert - SimpleDateFormat df = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss"); - assertThat(from(bookJson).getString("published")).isEqualTo(df.format(book.getPublished())); - - } -} \ No newline at end of file diff --git a/jackson/src/test/java/com/baeldung/jackson/deserialization/jsonsetter/JsonSetterUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/deserialization/jsonsetter/JsonSetterUnitTest.java deleted file mode 100644 index 4379fe376c..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/deserialization/jsonsetter/JsonSetterUnitTest.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.baeldung.jackson.deserialization.jsonsetter; - -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import java.io.IOException; - -import static io.restassured.path.json.JsonPath.from; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class JsonSetterUnitTest { - - @Test - public void whenDeserializingUsingJsonSetter_thenCorrect() throws IOException { - - // arrange - String json = "{\"firstName\":\"Alex\",\"lastName\":\"Theedom\",\"publications\":[{\"title\":\"Professional Java EE Design Patterns\"}]}"; - - // act - Author author = new ObjectMapper().readerFor(Author.class) - .readValue(json); - - // assert - assertThat(from(json).getList("publications") - .size()).isEqualTo(author.getItems() - .size()); - - } -} \ No newline at end of file diff --git a/jackson/src/test/java/com/baeldung/jackson/general/jsonfilter/Author.java b/jackson/src/test/java/com/baeldung/jackson/general/jsonfilter/Author.java deleted file mode 100644 index 3d5a9c907c..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/general/jsonfilter/Author.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.baeldung.jackson.general.jsonfilter; - -import com.baeldung.jackson.domain.Person; -import com.baeldung.jackson.domain.Item; -import com.fasterxml.jackson.annotation.JsonFilter; - -import java.util.ArrayList; -import java.util.List; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -@JsonFilter("authorFilter") -public class Author extends Person { - - private List items = new ArrayList<>(); - - public Author(String firstName, String lastName) { - super(firstName, lastName); - } - - public List getItems() { - return items; - } - - public void setItems(List items) { - this.items = items; - } -} diff --git a/jackson/src/test/java/com/baeldung/jackson/general/jsonfilter/JsonFilterUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/general/jsonfilter/JsonFilterUnitTest.java deleted file mode 100644 index 6fcc57faa7..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/general/jsonfilter/JsonFilterUnitTest.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.baeldung.jackson.general.jsonfilter; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.ser.FilterProvider; -import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter; -import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider; -import org.junit.Test; - -import static io.restassured.path.json.JsonPath.from; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class JsonFilterUnitTest { - - @Test - public void whenSerializingUsingJsonFilter_thenCorrect() throws JsonProcessingException { - - // arrange - Author author = new Author("Alex", "Theedom"); - FilterProvider filters = new SimpleFilterProvider().addFilter("authorFilter", SimpleBeanPropertyFilter.filterOutAllExcept("lastName")); - - // act - String result = new ObjectMapper().writer(filters) - .writeValueAsString(author); - - // assert - assertThat(from(result).getList("items")).isNull(); - - /* - { - "lastName": "Theedom" - } - */ - - } -} \ No newline at end of file diff --git a/jackson/src/test/java/com/baeldung/jackson/general/jsonformat/Book.java b/jackson/src/test/java/com/baeldung/jackson/general/jsonformat/Book.java deleted file mode 100644 index e2eb4aa48a..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/general/jsonformat/Book.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.baeldung.jackson.general.jsonformat; - -import com.baeldung.jackson.domain.Author; -import com.baeldung.jackson.domain.Item; -import com.fasterxml.jackson.annotation.JsonFormat; - -import java.math.BigDecimal; -import java.util.Date; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Book extends Item { - - private String ISBN; - - @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy HH:mm:ss") - private Date published; - private BigDecimal pages; - - public Book() { - } - - public Book(String title, Author author) { - super(title, author); - } - - public String getISBN() { - return ISBN; - } - - public void setISBN(String ISBN) { - this.ISBN = ISBN; - } - - public Date getPublished() { - return published; - } - - public void setPublished(Date published) { - this.published = published; - } - - public BigDecimal getPages() { - return pages; - } - - public void setPages(BigDecimal pages) { - this.pages = pages; - } -} diff --git a/jackson/src/test/java/com/baeldung/jackson/general/jsonformat/JsonFormatUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/general/jsonformat/JsonFormatUnitTest.java deleted file mode 100644 index 1fe217cef6..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/general/jsonformat/JsonFormatUnitTest.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.baeldung.jackson.general.jsonformat; - -import com.baeldung.jackson.domain.Author; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.TimeZone; - -import static io.restassured.path.json.JsonPath.from; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class JsonFormatUnitTest { - - @Test - public void whenSerializingUsingJsonFormat_thenCorrect() throws JsonProcessingException, ParseException { - - // arrange - SimpleDateFormat df = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss"); - df.setTimeZone(TimeZone.getTimeZone("UTC")); - - String toParse = "20-12-2014 14:30:00"; - Date date = df.parse(toParse); - - Book book = new Book("Design Patterns: Elements of Reusable Object-oriented Software", new Author("The", "GoF")); - book.setPublished(date); - - // act - String result = new ObjectMapper().writeValueAsString(book); - - // assert - assertThat(from(result).getString("published")).isEqualTo(toParse); - - /* - { - "id": "762b39be-fd5b-489e-8688-aeb3b9bbf019", - "title": "Design Patterns: Elements of Reusable Object-oriented Software", - "authors": [ - { - "id": "6941b780-0f54-4259-adcb-85523c8f25f4", - "firstName": "The", - "lastName": "GoF", - "items": [] - } - ], - "price": 0, - "published": "20-12-2014 02:30:00", - "pages": null, - "isbn": null - } - */ - - } -} \ No newline at end of file diff --git a/jackson/src/test/java/com/baeldung/jackson/general/jsonidentityinfo/Author.java b/jackson/src/test/java/com/baeldung/jackson/general/jsonidentityinfo/Author.java deleted file mode 100644 index 1f36b95b2a..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/general/jsonidentityinfo/Author.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.baeldung.jackson.general.jsonidentityinfo; - -import com.fasterxml.jackson.annotation.JsonIdentityInfo; -import com.fasterxml.jackson.annotation.ObjectIdGenerators; - -import java.util.ArrayList; -import java.util.List; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id") -public class Author extends Person { - - private List items = new ArrayList<>(); - - public Author(String firstName, String lastName) { - super(firstName, lastName); - } - - public List getItems() { - return items; - } - - public void setItems(List items) { - this.items = items; - } -} diff --git a/jackson/src/test/java/com/baeldung/jackson/general/jsonidentityinfo/Course.java b/jackson/src/test/java/com/baeldung/jackson/general/jsonidentityinfo/Course.java deleted file mode 100644 index 80dd9c275e..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/general/jsonidentityinfo/Course.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.baeldung.jackson.general.jsonidentityinfo; - -import java.util.List; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Course extends Item { - - public enum Medium { - CLASSROOM, ONLINE - } - - public enum Level { - BEGINNER("Beginner", 1), INTERMEDIATE("Intermediate", 2), ADVANCED("Advanced", 3); - - private String name; - private int number; - - Level(String name, int number) { - this.name = name; - this.number = number; - } - - public String getName() { - return name; - } - } - - private float duration; - private Medium medium; - private Level level; - private List prerequisite; - - public Course(String title, Author author) { - super(title, author); - } - - public float getDuration() { - return duration; - } - - public void setDuration(float duration) { - this.duration = duration; - } - - public Medium getMedium() { - return medium; - } - - public void setMedium(Medium medium) { - this.medium = medium; - } - - public Level getLevel() { - return level; - } - - public void setLevel(Level level) { - this.level = level; - } - - public List getPrerequisite() { - return prerequisite; - } - - public void setPrerequisite(List prerequisite) { - this.prerequisite = prerequisite; - } -} diff --git a/jackson/src/test/java/com/baeldung/jackson/general/jsonidentityinfo/Item.java b/jackson/src/test/java/com/baeldung/jackson/general/jsonidentityinfo/Item.java deleted file mode 100644 index bad6562122..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/general/jsonidentityinfo/Item.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.baeldung.jackson.general.jsonidentityinfo; - -import com.fasterxml.jackson.annotation.JsonIdentityInfo; -import com.fasterxml.jackson.annotation.ObjectIdGenerators; - -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id") -public class Item { - - private UUID id; - private String title; - private List authors = new ArrayList<>(); - private float price; - - public Item() { - } - - public Item(String title, Author author) { - this.id = UUID.randomUUID(); - this.title = title; - this.authors.add(author); - } - - public UUID getId() { - return id; - } - - public void setId(UUID id) { - this.id = id; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public List getAuthors() { - return authors; - } - - public void setAuthors(List authors) { - this.authors = authors; - } - - public float getPrice() { - return price; - } - - public void setPrice(float price) { - this.price = price; - } -} diff --git a/jackson/src/test/java/com/baeldung/jackson/general/jsonidentityinfo/JsonIdentityInfoUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/general/jsonidentityinfo/JsonIdentityInfoUnitTest.java deleted file mode 100644 index 014f1a8f69..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/general/jsonidentityinfo/JsonIdentityInfoUnitTest.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.baeldung.jackson.general.jsonidentityinfo; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import java.util.Collections; - -import static io.restassured.path.json.JsonPath.from; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class JsonIdentityInfoUnitTest { - - @Test - public void whenSerializingUsingJsonIdentityInfo_thenCorrect() throws JsonProcessingException { - - // arrange - Author author = new Author("Alex", "Theedom"); - - Course course = new Course("Java EE Introduction", author); - author.setItems(Collections.singletonList(course)); - course.setAuthors(Collections.singletonList(author)); - - // act - String result = new ObjectMapper().writeValueAsString(author); - - // assert - assertThat(from(result).getString("items[0].authors")).isNotNull(); - - /* - Authors are included. - { - "id": "1b408bf9-5946-4a14-a112-fde2953a7fe7", - "firstName": "Alex", - "lastName": "Theedom", - "items": [ - { - "id": "5ed30530-f0a5-42eb-b786-be2c655da968", - "title": "Java EE Introduction", - "authors": [ - "1b408bf9-5946-4a14-a112-fde2953a7fe7" - ], - "price": 0, - "duration": 0, - "medium": null, - "level": null, - "prerequisite": null - } - ] - } - */ - - } -} \ No newline at end of file diff --git a/jackson/src/test/java/com/baeldung/jackson/general/jsonidentityinfo/Person.java b/jackson/src/test/java/com/baeldung/jackson/general/jsonidentityinfo/Person.java deleted file mode 100644 index ea80814124..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/general/jsonidentityinfo/Person.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.baeldung.jackson.general.jsonidentityinfo; - -import java.util.UUID; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Person { - - private UUID id; - private String firstName; - private String lastName; - - public Person() { - } - - public Person(String firstName, String lastName) { - this.id = UUID.randomUUID(); - this.firstName = firstName; - this.lastName = lastName; - } - - public String getFirstName() { - return firstName; - } - - public void setFirstName(String firstName) { - this.firstName = firstName; - } - - public String getLastName() { - return lastName; - } - - public void setLastName(String lastName) { - this.lastName = lastName; - } - - public UUID getId() { - return id; - } -} diff --git a/jackson/src/test/java/com/baeldung/jackson/general/jsonproperty/Author.java b/jackson/src/test/java/com/baeldung/jackson/general/jsonproperty/Author.java deleted file mode 100644 index 01552df729..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/general/jsonproperty/Author.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.baeldung.jackson.general.jsonproperty; - -import com.baeldung.jackson.domain.Person; - -import java.util.ArrayList; -import java.util.List; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Author extends Person { - - private List items = new ArrayList<>(); - - public Author(String firstName, String lastName) { - super(firstName, lastName); - } - - public List getItems() { - return items; - } - - public void setItems(List items) { - this.items = items; - } -} diff --git a/jackson/src/test/java/com/baeldung/jackson/general/jsonproperty/Book.java b/jackson/src/test/java/com/baeldung/jackson/general/jsonproperty/Book.java deleted file mode 100644 index 100d9634f5..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/general/jsonproperty/Book.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.baeldung.jackson.general.jsonproperty; - -import com.fasterxml.jackson.annotation.JsonProperty; - -import java.math.BigDecimal; -import java.util.Date; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Book extends Item { - - private String ISBN; - private Date published; - private BigDecimal pages; - private String binding; - - public Book() { - } - - public Book(String title, Author author) { - super(title, author); - } - - public String getISBN() { - return ISBN; - } - - public void setISBN(String ISBN) { - this.ISBN = ISBN; - } - - public Date getPublished() { - return published; - } - - public void setPublished(Date published) { - this.published = published; - } - - public BigDecimal getPages() { - return pages; - } - - public void setPages(BigDecimal pages) { - this.pages = pages; - } - - @JsonProperty("binding") - public String coverBinding() { - return binding; - } - - @JsonProperty("binding") - public void configureBinding(String binding) { - this.binding = binding; - } -} diff --git a/jackson/src/test/java/com/baeldung/jackson/general/jsonproperty/Item.java b/jackson/src/test/java/com/baeldung/jackson/general/jsonproperty/Item.java deleted file mode 100644 index d7ee430d51..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/general/jsonproperty/Item.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.baeldung.jackson.general.jsonproperty; - -import com.baeldung.jackson.domain.Person; - -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Item { - - private UUID id; - private String title; - private List authors = new ArrayList<>(); - private float price; - - public Item() { - } - - public Item(String title, Author author) { - this.id = UUID.randomUUID(); - this.title = title; - this.authors.add(author); - } - - public UUID getId() { - return id; - } - - public void setId(UUID id) { - this.id = id; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public List getAuthors() { - return authors; - } - - public void setAuthors(List authors) { - this.authors = authors; - } - - public float getPrice() { - return price; - } - - public void setPrice(float price) { - this.price = price; - } -} diff --git a/jackson/src/test/java/com/baeldung/jackson/general/jsonproperty/JsonPropertyUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/general/jsonproperty/JsonPropertyUnitTest.java deleted file mode 100644 index 0b88e7fc47..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/general/jsonproperty/JsonPropertyUnitTest.java +++ /dev/null @@ -1,70 +0,0 @@ -package com.baeldung.jackson.general.jsonproperty; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import java.io.IOException; - -import static io.restassured.path.json.JsonPath.from; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class JsonPropertyUnitTest { - - @Test - public void whenSerializingUsingJsonProperty_thenCorrect() throws JsonProcessingException { - - // arrange - Book book = new Book("Design Patterns: Elements of Reusable Object-oriented Software", new Author("The", "GoF")); - book.configureBinding("Hardback"); - - // act - String result = new ObjectMapper().writeValueAsString(book); - - // assert - assertThat(from(result).getString("binding")).isEqualTo("Hardback"); - - /* - { - "id": "cd941587-d1ae-4c2a-9a36-29533bf50411", - "title": "Design Patterns: Elements of Reusable Object-oriented Software", - "authors": [ - { - "id": "c8e26318-2f5b-4fa2-9fdc-6e99be021fca", - "firstName": "The", - "lastName": "GoF", - "items": [] - } - ], - "price": 0, - "published": null, - "pages": null, - "isbn": null, - "binding": "Hardback" - } - */ - - } - - @Test - public void whenDeserializingUsingJsonProperty_thenCorrect() throws IOException { - - // arrange - String result = "{\"id\":\"cd941587-d1ae-4c2a-9a36-29533bf50411\",\"title\":\"Design Patterns: Elements of Reusable Object-oriented Software\",\"authors\":[{\"id\":\"c8e26318-2f5b-4fa2-9fdc-6e99be021fca\",\"firstName\":\"The\",\"lastName\":\"GoF\"}],\"binding\":\"Hardback\"}"; - - // act - Book book = new ObjectMapper().readerFor(Book.class) - .readValue(result); - - // assert - assertThat(book.coverBinding()).isEqualTo("Hardback"); - - } - -} \ No newline at end of file diff --git a/jackson/src/test/java/com/baeldung/jackson/general/jsonunwrapped/JsonUnwrappedUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/general/jsonunwrapped/JsonUnwrappedUnitTest.java deleted file mode 100644 index 5130e037d5..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/general/jsonunwrapped/JsonUnwrappedUnitTest.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.baeldung.jackson.general.jsonunwrapped; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import static io.restassured.path.json.JsonPath.from; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class JsonUnwrappedUnitTest { - - @Test - public void whenSerializingUsingJsonUnwrapped_thenCorrect() throws JsonProcessingException { - - // arrange - Order.Type preorderType = new Order.Type(); - preorderType.id = 10; - preorderType.name = "pre-order"; - - Order order = new Order(preorderType); - - // act - String result = new ObjectMapper().writeValueAsString(order); - - // assert - assertThat(from(result).getInt("id")).isEqualTo(10); - assertThat(from(result).getString("name")).isEqualTo("pre-order"); - - /* - { - "id": 10, - "name": "pre-order" - } - */ - - } -} \ No newline at end of file diff --git a/jackson/src/test/java/com/baeldung/jackson/general/jsonunwrapped/Order.java b/jackson/src/test/java/com/baeldung/jackson/general/jsonunwrapped/Order.java deleted file mode 100644 index b1c5b832c3..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/general/jsonunwrapped/Order.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.baeldung.jackson.general.jsonunwrapped; - -import com.fasterxml.jackson.annotation.JsonUnwrapped; - -import java.util.UUID; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Order { - - private UUID id; - - @JsonUnwrapped - private Type type; - private int internalAudit; - - public static class Type { - public long id; - public String name; - } - - public Order() { - this.id = UUID.randomUUID(); - } - - public Order(Type type) { - this(); - this.type = type; - } - - public Order(int internalAudit) { - this(); - this.type = new Type(); - this.type.id = 20; - this.type.name = "Order"; - this.internalAudit = internalAudit; - } - - public UUID getId() { - return id; - } - - public Type getType() { - return type; - } - - public void setType(Type type) { - this.type = type; - } -} diff --git a/jackson/src/test/java/com/baeldung/jackson/general/jsonview/JsonViewUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/general/jsonview/JsonViewUnitTest.java deleted file mode 100644 index ab609008ce..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/general/jsonview/JsonViewUnitTest.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.baeldung.jackson.general.jsonview; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import static io.restassured.path.json.JsonPath.from; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class JsonViewUnitTest { - - @Test - public void whenSerializingUsingJsonView_andInternalView_thenCorrect() throws JsonProcessingException { - - // arrange - Order order = new Order(120); - - // act - String result = new ObjectMapper().writerWithView(Views.Internal.class) - .writeValueAsString(order); - - // assert - assertThat(from(result).getUUID("id")).isNotNull(); - assertThat(from(result).getObject("type", Order.Type.class)).isNotNull(); - assertThat(from(result).getInt("internalAudit")).isEqualTo(120); - - /* - { - "id": "33806388-795b-4812-b90a-60292111bc5c", - "type": { - "id": 20, - "name": "Order" - }, - "internalAudit": 120 - } - */ - - } - - @Test - public void whenSerializingUsingJsonView_andPublicView_thenCorrect() throws JsonProcessingException { - - // arrange - Order order = new Order(120); - - // act - String result = new ObjectMapper().writerWithView(Views.Public.class) - .writeValueAsString(order); - - // assert - assertThat(from(result).getUUID("id")).isNotNull(); - assertThat(from(result).getObject("type", Order.Type.class)).isNotNull(); - assertThat(result).doesNotContain("internalAudit"); - - /* - { - "id": "5184d5fc-e359-4cdf-93fa-4054025bef4e", - "type": { - "id": 20, - "name": "Order" - } - } - */ - - } - -} \ No newline at end of file diff --git a/jackson/src/test/java/com/baeldung/jackson/general/jsonview/Order.java b/jackson/src/test/java/com/baeldung/jackson/general/jsonview/Order.java deleted file mode 100644 index 69adf1b59d..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/general/jsonview/Order.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.baeldung.jackson.general.jsonview; - -import com.fasterxml.jackson.annotation.JsonView; - -import java.util.UUID; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Order { - - @JsonView(Views.Public.class) - private UUID id; - - @JsonView(Views.Public.class) - private Type type; - - @JsonView(Views.Internal.class) - private int internalAudit; - - public static class Type { - public long id; - public String name; - } - - public Order() { - this.id = UUID.randomUUID(); - } - - public Order(Type type) { - this(); - this.type = type; - } - - public Order(int internalAudit) { - this(); - this.type = new Type(); - this.type.id = 20; - this.type.name = "Order"; - this.internalAudit = internalAudit; - } - - public UUID getId() { - return id; - } - - public Type getType() { - return type; - } - - public void setType(Type type) { - this.type = type; - } -} diff --git a/jackson/src/test/java/com/baeldung/jackson/general/jsonview/Views.java b/jackson/src/test/java/com/baeldung/jackson/general/jsonview/Views.java deleted file mode 100644 index b55997554d..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/general/jsonview/Views.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.baeldung.jackson.general.jsonview; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Views { - public static class Public { - } - - public static class Internal extends Public { - } -} diff --git a/jackson/src/test/java/com/baeldung/jackson/general/reference/Author.java b/jackson/src/test/java/com/baeldung/jackson/general/reference/Author.java deleted file mode 100644 index 02dd9470d7..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/general/reference/Author.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.baeldung.jackson.general.reference; - -import com.fasterxml.jackson.annotation.JsonManagedReference; - -import java.util.ArrayList; -import java.util.List; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Author extends Person { - - private List items = new ArrayList<>(); - - public Author(String firstName, String lastName) { - super(firstName, lastName); - } - - @JsonManagedReference - public List getItems() { - return items; - } - - public void setItems(List items) { - this.items = items; - } -} diff --git a/jackson/src/test/java/com/baeldung/jackson/general/reference/Course.java b/jackson/src/test/java/com/baeldung/jackson/general/reference/Course.java deleted file mode 100644 index 251d25a517..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/general/reference/Course.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.baeldung.jackson.general.reference; - -import java.util.List; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Course extends Item { - - public enum Medium { - CLASSROOM, ONLINE - } - - public enum Level { - BEGINNER("Beginner", 1), INTERMEDIATE("Intermediate", 2), ADVANCED("Advanced", 3); - - private String name; - private int number; - - Level(String name, int number) { - this.name = name; - this.number = number; - } - - public String getName() { - return name; - } - } - - private float duration; - private Medium medium; - private Level level; - private List prerequisite; - - public Course(String title, Author author) { - super(title, author); - } - - public float getDuration() { - return duration; - } - - public void setDuration(float duration) { - this.duration = duration; - } - - public Medium getMedium() { - return medium; - } - - public void setMedium(Medium medium) { - this.medium = medium; - } - - public Level getLevel() { - return level; - } - - public void setLevel(Level level) { - this.level = level; - } - - public List getPrerequisite() { - return prerequisite; - } - - public void setPrerequisite(List prerequisite) { - this.prerequisite = prerequisite; - } -} diff --git a/jackson/src/test/java/com/baeldung/jackson/general/reference/Item.java b/jackson/src/test/java/com/baeldung/jackson/general/reference/Item.java deleted file mode 100644 index 5dd66a8ca3..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/general/reference/Item.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.baeldung.jackson.general.reference; - -import com.fasterxml.jackson.annotation.JsonBackReference; - -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Item { - - private UUID id; - private String title; - - @JsonBackReference - private List authors = new ArrayList<>(); - private float price; - - public Item() { - } - - public Item(String title, Author author) { - this.id = UUID.randomUUID(); - this.title = title; - this.authors.add(author); - } - - public UUID getId() { - return id; - } - - public void setId(UUID id) { - this.id = id; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public List getAuthors() { - return authors; - } - - public void setAuthors(List authors) { - this.authors = authors; - } - - public float getPrice() { - return price; - } - - public void setPrice(float price) { - this.price = price; - } -} diff --git a/jackson/src/test/java/com/baeldung/jackson/general/reference/Person.java b/jackson/src/test/java/com/baeldung/jackson/general/reference/Person.java deleted file mode 100644 index 95c0b35b8b..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/general/reference/Person.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.baeldung.jackson.general.reference; - -import java.util.UUID; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Person { - - private UUID id; - private String firstName; - private String lastName; - - public Person() { - } - - public Person(String firstName, String lastName) { - this.id = UUID.randomUUID(); - this.firstName = firstName; - this.lastName = lastName; - } - - public String getFirstName() { - return firstName; - } - - public void setFirstName(String firstName) { - this.firstName = firstName; - } - - public String getLastName() { - return lastName; - } - - public void setLastName(String lastName) { - this.lastName = lastName; - } - - public UUID getId() { - return id; - } -} diff --git a/jackson/src/test/java/com/baeldung/jackson/general/reference/ReferenceUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/general/reference/ReferenceUnitTest.java deleted file mode 100644 index 7a52a69656..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/general/reference/ReferenceUnitTest.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.baeldung.jackson.general.reference; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import java.util.Collections; - -import static io.restassured.path.json.JsonPath.from; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class ReferenceUnitTest { - - @Test - public void whenSerializingUsingReference_thenCorrect() throws JsonProcessingException { - - // arrange - Author author = new Author("Alex", "Theedom"); - - Course course = new Course("Java EE Introduction", author); - author.setItems(Collections.singletonList(course)); - course.setAuthors(Collections.singletonList(author)); - - // act - String result = new ObjectMapper().writeValueAsString(author); - - // assert - assertThat(from(result).getString("items[0].authors")).isNull(); - - /* - Without references defined it throws StackOverflowError. - Authors excluded. - - { - "id": "9c45d9b3-4888-4c24-8b74-65ef35627cd7", - "firstName": "Alex", - "lastName": "Theedom", - "items": [ - { - "id": "f8309629-d178-4d67-93a4-b513ec4a7f47", - "title": "Java EE Introduction", - "price": 0, - "duration": 0, - "medium": null, - "level": null, - "prerequisite": null - } - ] - } - */ - - } -} \ No newline at end of file diff --git a/jackson/src/test/java/com/baeldung/jackson/inclusion/jsonautodetect/JsonAutoDetectUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/inclusion/jsonautodetect/JsonAutoDetectUnitTest.java deleted file mode 100644 index a3e29776a9..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/inclusion/jsonautodetect/JsonAutoDetectUnitTest.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.baeldung.jackson.inclusion.jsonautodetect; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import static io.restassured.path.json.JsonPath.from; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class JsonAutoDetectUnitTest { - - @Test - public void whenSerializingUsingJsonAutoDetect_thenCorrect() throws JsonProcessingException { - - // arrange - Order order = new Order(1234567890); - - // act - String result = new ObjectMapper().writeValueAsString(order); - - // assert - assertThat(from(result).getInt("internalAudit")).isEqualTo(1234567890); - - /* - With @JsonAutoDetect - { - "id": "c94774d9-de8f-4244-85d5-624bd3a4567a", - "type": { - "id": 20, - "name": "Order" - }, - "internalAudit": 1234567890 - } - - Without @JsonAutoDetect - { - "id": "c94774d9-de8f-4244-85d5-624bd3a4567a", - "type": { - "id": 20, - "name": "Order" - } - } - */ - - } -} \ No newline at end of file diff --git a/jackson/src/test/java/com/baeldung/jackson/inclusion/jsonignore/JsonIgnoreUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/inclusion/jsonignore/JsonIgnoreUnitTest.java deleted file mode 100644 index 89e3c15f04..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/inclusion/jsonignore/JsonIgnoreUnitTest.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.baeldung.jackson.inclusion.jsonignore; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import static io.restassured.path.json.JsonPath.from; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class JsonIgnoreUnitTest { - - @Test - public void whenSerializingUsingJsonIgnore_thenCorrect() throws JsonProcessingException { - - // arrange - Author author = new Author("Alex", "Theedom"); - - // act - String result = new ObjectMapper().writeValueAsString(author); - - // assert - assertThat(from(result).getString("firstName")).isEqualTo("Alex"); - assertThat(from(result).getString("lastName")).isEqualTo("Theedom"); - assertThat(from(result).getString("id")).isNull(); - - /* - { - "firstName": "Alex", - "lastName": "Theedom", - "items": [] - } - */ - - } -} \ No newline at end of file diff --git a/jackson/src/test/java/com/baeldung/jackson/inclusion/jsonignoreproperties/JsonIgnorePropertiesUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/inclusion/jsonignoreproperties/JsonIgnorePropertiesUnitTest.java deleted file mode 100644 index be20d242c9..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/inclusion/jsonignoreproperties/JsonIgnorePropertiesUnitTest.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.baeldung.jackson.inclusion.jsonignoreproperties; - -import com.baeldung.jackson.domain.Author; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import static io.restassured.path.json.JsonPath.from; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class JsonIgnorePropertiesUnitTest { - - @Test - public void whenSerializingUsingJsonIgnoreProperties_thenCorrect() throws JsonProcessingException { - - // arrange - Course course = new Course("Spring Security", new Author("Eugen", "Paraschiv")); - course.setMedium(Course.Medium.ONLINE); - - // act - String result = new ObjectMapper().writeValueAsString(course); - - // assert - assertThat(from(result).getString("medium")).isNull(); - - /* - { - "id": "ef0c8d2b-b088-409e-905c-95ac88dc0ed0", - "title": "Spring Security", - "authors": [ - { - "id": "47a4f498-b0f3-4daf-909f-d2c35a0fe3c2", - "firstName": "Eugen", - "lastName": "Paraschiv", - "items": [] - } - ], - "price": 0, - "duration": 0, - "level": null, - "prerequisite": null - } - */ - - } -} \ No newline at end of file diff --git a/jackson/src/test/java/com/baeldung/jackson/inclusion/jsonignoretype/JsonIgnoreTypeUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/inclusion/jsonignoretype/JsonIgnoreTypeUnitTest.java deleted file mode 100644 index e8917ff526..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/inclusion/jsonignoretype/JsonIgnoreTypeUnitTest.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.baeldung.jackson.inclusion.jsonignoretype; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import static io.restassured.path.json.JsonPath.from; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class JsonIgnoreTypeUnitTest { - - @Test - public void whenSerializingUsingJsonIgnoreType_thenCorrect() throws JsonProcessingException { - - // arrange - Order.Type type = new Order.Type(); - type.id = 10; - type.name = "Pre-order"; - - Order order = new Order(type); - - // act - String result = new ObjectMapper().writeValueAsString(order); - - // assert - assertThat(from(result).getString("id")).isNotNull(); - assertThat(from(result).getString("type")).isNull(); - - /* - {"id":"ac2428da-523e-443c-a18a-4ea4d2791fea"} - */ - - } -} \ No newline at end of file diff --git a/jackson/src/test/java/com/baeldung/jackson/inclusion/jsoninclude/JsonIncludeUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/inclusion/jsoninclude/JsonIncludeUnitTest.java deleted file mode 100644 index ca4c4b751a..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/inclusion/jsoninclude/JsonIncludeUnitTest.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.baeldung.jackson.inclusion.jsoninclude; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import static io.restassured.path.json.JsonPath.from; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class JsonIncludeUnitTest { - - @Test - public void whenSerializingUsingJsonInclude_thenCorrect() throws JsonProcessingException { - - // arrange - Author author = new Author("Alex", null); - - // act - String result = new ObjectMapper().writeValueAsString(author); - - // assert - assertThat(from(result).getString("firstName")).isEqualTo("Alex"); - assertThat(result).doesNotContain("lastName"); - - /* - { - "id": "e8bb4802-6e0c-4fa5-9f68-c233272399cd", - "firstName": "Alex", - "items": [] - } - */ - - } -} \ No newline at end of file diff --git a/jackson/src/test/java/com/baeldung/jackson/miscellaneous/custom/CustomUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/miscellaneous/custom/CustomUnitTest.java deleted file mode 100644 index 8f90c02875..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/miscellaneous/custom/CustomUnitTest.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.baeldung.jackson.miscellaneous.custom; - -import com.baeldung.jackson.domain.Author; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import static io.restassured.path.json.JsonPath.from; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class CustomUnitTest { - - @Test - public void whenSerializingUsingCustom_thenCorrect() throws JsonProcessingException { - - // arrange - Course course = new Course("Spring Security", new Author("Eugen", "Paraschiv")); - course.setMedium(Course.Medium.ONLINE); - - // act - String result = new ObjectMapper().writeValueAsString(course); - - // assert - assertThat(from(result).getString("title")).isEqualTo("Spring Security"); - - /* - { - "title": "Spring Security", - "price": 0, - "id": "7dfd4db9-1175-432f-a53b-687423f7bb9b", - "duration": 0, - "authors": [ - { - "id": "da0738f6-033c-4974-8d87-92820e5ccf27", - "firstName": "Eugen", - "lastName": "Paraschiv", - "items": [] - } - ], - "medium": "ONLINE" - } - */ - - } -} \ No newline at end of file diff --git a/jackson/src/test/java/com/baeldung/jackson/miscellaneous/disable/DisableUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/miscellaneous/disable/DisableUnitTest.java deleted file mode 100644 index f9bc14291e..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/miscellaneous/disable/DisableUnitTest.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.baeldung.jackson.miscellaneous.disable; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.MapperFeature; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import static io.restassured.path.json.JsonPath.from; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class DisableUnitTest { - - @Test - public void whenSerializingUsingDisable_thenCorrect() throws JsonProcessingException { - - // arrange - Author author = new Author("Alex", "Theedom"); - - // act - ObjectMapper mapper = new ObjectMapper(); - String result = mapper.writeValueAsString(author); - - // assert - assertThat(from(result).getList("items")).isNull(); - - /* - { - "lastName": "Theedom", - "firstName": "Alex", - "id": "de4afbb4-b24d-45c8-bb00-fd6b9acb42f1" - } - */ - - // act - mapper = new ObjectMapper(); - mapper.disable(MapperFeature.USE_ANNOTATIONS); - result = mapper.writeValueAsString(author); - - // assert - assertThat(from(result).getList("items")).isNotNull(); - - /* - { - "id": "81e6ed72-6b27-4fe9-a36f-e3171c5b55ef", - "firstName": "Alex", - "lastName": "Theedom", - "items": [] - } - */ - - } -} \ No newline at end of file diff --git a/jackson/src/test/java/com/baeldung/jackson/miscellaneous/mixin/MixInUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/miscellaneous/mixin/MixInUnitTest.java deleted file mode 100644 index 732cda58d0..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/miscellaneous/mixin/MixInUnitTest.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.baeldung.jackson.miscellaneous.mixin; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import java.util.List; - -import static io.restassured.path.json.JsonPath.from; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class MixInUnitTest { - - @Test - public void whenSerializingUsingMixIn_thenCorrect() throws JsonProcessingException { - - // arrange - Author author = new Author("Alex", "Theedom"); - - // act - String result = new ObjectMapper().writeValueAsString(author); - - // assert - assertThat(from(result).getList("items")).isNotNull(); - - /* - { - "id": "f848b076-00a4-444a-a50b-328595dd9bf5", - "firstName": "Alex", - "lastName": "Theedom", - "items": [] - } - */ - - ObjectMapper mapper = new ObjectMapper(); - mapper.addMixIn(List.class, IgnoreListMixIn.class); - - result = mapper.writeValueAsString(author); - - // assert - assertThat(from(result).getList("items")).isNull(); - - /* - { - "id": "9ffefb7d-e56f-447c-9009-e92e142f8347", - "firstName": "Alex", - "lastName": "Theedom" - } - */ - - } -} \ No newline at end of file diff --git a/jackson/src/test/java/com/baeldung/jackson/polymorphism/PolymorphismUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/polymorphism/PolymorphismUnitTest.java deleted file mode 100644 index e922cf9976..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/polymorphism/PolymorphismUnitTest.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.baeldung.jackson.polymorphism; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import java.io.IOException; - -import static io.restassured.path.json.JsonPath.from; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class PolymorphismUnitTest { - - @Test - public void whenSerializingUsingPolymorphism_thenCorrect() throws JsonProcessingException { - - // arrange - Order.InternalType internalType = new Order.InternalType(); - internalType.id = 250; - internalType.name = "staff"; - - Order order = new Order(internalType); - - // act - String result = new ObjectMapper().writeValueAsString(order); - - // assert - assertThat(from(result).getString("type.ordertype")).isEqualTo("internal"); - - /* - { - "id": "7fc898e3-b4e7-41b0-8ffa-664cf3663f2e", - "type": { - "ordertype": "internal", - "id": 250, - "name": "staff" - } - } - */ - - } - - @Test - public void whenDeserializingPolymorphic_thenCorrect() throws IOException { - - // arrange - String orderJson = "{\"type\":{\"ordertype\":\"internal\",\"id\":100,\"name\":\"directors\"}}"; - - // act - Order order = new ObjectMapper().readerFor(Order.class) - .readValue(orderJson); - - // assert - assertThat(from(orderJson).getString("type.ordertype")).isEqualTo("internal"); - assertThat(((Order.InternalType) order.getType()).name).isEqualTo("directors"); - assertThat(((Order.InternalType) order.getType()).id).isEqualTo(100); - assertThat(order.getType() - .getClass()).isEqualTo(Order.InternalType.class); - } -} \ No newline at end of file diff --git a/jackson/src/test/java/com/baeldung/jackson/serialization/jsonanygetter/JsonAnyGetterUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/serialization/jsonanygetter/JsonAnyGetterUnitTest.java deleted file mode 100644 index 7a786e0bd6..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/serialization/jsonanygetter/JsonAnyGetterUnitTest.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.baeldung.jackson.serialization.jsonanygetter; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import java.util.Map; - -import static io.restassured.path.json.JsonPath.from; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class JsonAnyGetterUnitTest { - - @Test - public void whenSerializingUsingJsonAnyGetter_thenCorrect() throws JsonProcessingException { - - // arrange - Inventory inventory = new Inventory(); - Map countryDeliveryCost = inventory.getCountryDeliveryCost(); - inventory.setLocation("France"); - - countryDeliveryCost.put("USA", 10.00f); - countryDeliveryCost.put("UK", 15.00f); - - // act - String result = new ObjectMapper().writeValueAsString(inventory); - - // assert - assertThat(from(result).getString("location")).isEqualTo("France"); - assertThat(from(result).getFloat("USA")).isEqualTo(10.00f); - assertThat(from(result).getFloat("UK")).isEqualTo(15.00f); - - /* - { - "location": "France", - "USA": 10, - "UK": 15 - } - */ - - } - -} diff --git a/jackson/src/test/java/com/baeldung/jackson/serialization/jsongetter/JsonGetterUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/serialization/jsongetter/JsonGetterUnitTest.java deleted file mode 100644 index 4bc9c51e83..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/serialization/jsongetter/JsonGetterUnitTest.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.baeldung.jackson.serialization.jsongetter; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import static io.restassured.path.json.JsonPath.from; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class JsonGetterUnitTest { - - @Test - public void whenSerializingUsingJsonGetter_thenCorrect() throws JsonProcessingException { - - // arrange - Author author = new Author("Alex", "Theedom"); - - // act - String result = new ObjectMapper().writeValueAsString(author); - - // assert - assertThat(from(result).getList("publications")).isNotNull(); - assertThat(from(result).getList("items")).isNull(); - - /* - { - "firstName": "Alex", - "lastName": "Theedom", - "publications": [] - } - */ - - } -} diff --git a/jackson/src/test/java/com/baeldung/jackson/serialization/jsonpropertyorder/JsonPropertyOrderUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/serialization/jsonpropertyorder/JsonPropertyOrderUnitTest.java deleted file mode 100644 index 77ef85ed73..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/serialization/jsonpropertyorder/JsonPropertyOrderUnitTest.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.baeldung.jackson.serialization.jsonpropertyorder; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import static io.restassured.module.jsv.JsonSchemaValidator.matchesJsonSchemaInClasspath; -import static org.hamcrest.MatcherAssert.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class JsonPropertyOrderUnitTest { - - @Test - public void whenSerializingUsingJsonPropertyOrder_thenCorrect() throws JsonProcessingException { - - // arrange - Author author = new Author("Alex", "Theedom"); - - // act - String result = new ObjectMapper().writeValueAsString(author); - - // assert - assertThat(result, matchesJsonSchemaInClasspath("author-jsonpropertyorder-schema.json")); - - // NOTE: property order is not enforced by the JSON specification. - - /* - { - "items": [], - "firstName": "Alex", - "lastName": "Theedom", - "id": "fd277638-9b6e-49f7-81c1-bc52f165245b" - } - */ - - } -} diff --git a/jackson/src/test/java/com/baeldung/jackson/serialization/jsonrawvalue/JsonRawValueUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/serialization/jsonrawvalue/JsonRawValueUnitTest.java deleted file mode 100644 index f0f0913aee..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/serialization/jsonrawvalue/JsonRawValueUnitTest.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.baeldung.jackson.serialization.jsonrawvalue; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class JsonRawValueUnitTest { - - @Test - public void whenSerializingUsingJsonRawValue_thenCorrect() throws JsonProcessingException { - - // arrange - String customerConfig = "{\"colour\":\"red\",\"device\":\"mobile\",\"orientation\":\"landscape\"}"; - Customer customer = new Customer("Alex", "Theedom"); - customer.setConfiguration("{\"colour\":\"red\",\"device\":\"mobile\",\"orientation\":\"landscape\"}"); - - // act - String result = new ObjectMapper().writeValueAsString(customer); - - // assert - assertThat(result.contains(customerConfig)); - - /* - { - "firstName": "Alex", - "lastName": "Theedom", - "publications": [] - } - */ - - } -} diff --git a/jackson/src/test/java/com/baeldung/jackson/serialization/jsonrootname/JsonRootNameUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/serialization/jsonrootname/JsonRootNameUnitTest.java deleted file mode 100644 index cb54e63079..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/serialization/jsonrootname/JsonRootNameUnitTest.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.baeldung.jackson.serialization.jsonrootname; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; -import org.junit.Test; - -import static io.restassured.path.json.JsonPath.from; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class JsonRootNameUnitTest { - - @Test - public void whenSerializingUsingJsonRootName_thenCorrect() throws JsonProcessingException { - - // arrange - Author author = new Author("Alex", "Theedom"); - - // act - ObjectMapper mapper = new ObjectMapper(); - mapper.enable(SerializationFeature.WRAP_ROOT_VALUE); - String result = mapper.writeValueAsString(author); - - // assert - assertThat(from(result).getString("writer.firstName")).isEqualTo("Alex"); - assertThat(from(result).getString("author.firstName")).isNull(); - - /* - { - "writer": { - "id": "0f50dca6-3dd7-4801-a334-fd1614276389", - "firstName": "Alex", - "lastName": "Theedom", - "items": [] - } - } - */ - - } -} diff --git a/jackson/src/test/java/com/baeldung/jackson/serialization/jsonserialize/JsonSerializeUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/serialization/jsonserialize/JsonSerializeUnitTest.java deleted file mode 100644 index cca018e78d..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/serialization/jsonserialize/JsonSerializeUnitTest.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.baeldung.jackson.serialization.jsonserialize; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import java.text.ParseException; -import java.text.SimpleDateFormat; - -import static io.restassured.path.json.JsonPath.from; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class JsonSerializeUnitTest { - - @Test - public void whenSerializingUsingJsonSerialize_thenCorrect() throws JsonProcessingException, ParseException { - - // arrange - Author joshuaBloch = new Author("Joshua", "Bloch"); - Book book = new Book("Effective Java", joshuaBloch); - - SimpleDateFormat df = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss"); - String toParse = "25-12-2017 13:30:25"; - book.setPublished(df.parse(toParse)); - - // act - String result = new ObjectMapper().writeValueAsString(book); - - // assert - assertThat(from(result).getString("published")).isEqualTo(toParse); - - /* - { - "id": "957c43f2-fa2e-42f9-bf75-6e3d5bb6960a", - "title": "Effective Java", - "authors": [ - { - "id": "9bcd817d-0141-42e6-8f04-e5aaab0980b6", - "firstName": "Joshua", - "lastName": "Bloch", - "items": [] - } - ], - "price": 0, - "published": "25-12-2017 13:30:25", - "pages": null, - "isbn": null - } - */ - - } -} diff --git a/jackson/src/test/java/com/baeldung/jackson/serialization/jsonvalue/JsonValueUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/serialization/jsonvalue/JsonValueUnitTest.java deleted file mode 100644 index 465daf13f5..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/serialization/jsonvalue/JsonValueUnitTest.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.baeldung.jackson.serialization.jsonvalue; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class JsonValueUnitTest { - - @Test - public void whenSerializingUsingJsonValue_thenCorrect() throws JsonProcessingException { - - // act - String result = new ObjectMapper().writeValueAsString(Course.Level.ADVANCED); - - // assert - assertThat(result).isEqualTo("\"Advanced\""); - - } -} \ No newline at end of file diff --git a/jackson/src/test/java/com/baeldung/jackson/test/UnitTestSuite.java b/jackson/src/test/java/com/baeldung/jackson/test/UnitTestSuite.java index 6be2f29baa..e783c67f5b 100644 --- a/jackson/src/test/java/com/baeldung/jackson/test/UnitTestSuite.java +++ b/jackson/src/test/java/com/baeldung/jackson/test/UnitTestSuite.java @@ -12,8 +12,6 @@ import org.junit.runners.Suite; ,JacksonDeserializationUnitTest.class ,JacksonDeserializationUnitTest.class ,JacksonPrettyPrintUnitTest.class - ,JacksonSerializationIgnoreUnitTest.class - ,JacksonSerializationUnitTest.class ,SandboxUnitTest.class ,JacksonFieldUnitTest.class }) // @formatter:on diff --git a/java-collections-conversions/src/test/java/com/baeldung/convertcollectiontoarraylist/FooUnitTest.java b/java-collections-conversions/src/test/java/com/baeldung/convertcollectiontoarraylist/FooUnitTest.java index 5be4121bc7..1de600aebf 100644 --- a/java-collections-conversions/src/test/java/com/baeldung/convertcollectiontoarraylist/FooUnitTest.java +++ b/java-collections-conversions/src/test/java/com/baeldung/convertcollectiontoarraylist/FooUnitTest.java @@ -33,9 +33,6 @@ public class FooUnitTest { srcCollection.add(sam); srcCollection.add(alice); srcCollection.add(buffy); - - // make sure the collection isn't sorted accidentally - assertFalse("Oops: source collection is already sorted!", isSorted(srcCollection)); } /** diff --git a/java-collections-maps-2/README.md b/java-collections-maps-2/README.md new file mode 100644 index 0000000000..8bcafccfe8 --- /dev/null +++ b/java-collections-maps-2/README.md @@ -0,0 +1,2 @@ +## Relevant Articles: +- [Map of Primitives in Java](https://www.baeldung.com/java-map-primitives) diff --git a/java-collections-maps-2/pom.xml b/java-collections-maps-2/pom.xml new file mode 100644 index 0000000000..5f27eaa2d8 --- /dev/null +++ b/java-collections-maps-2/pom.xml @@ -0,0 +1,61 @@ + + + 4.0.0 + java-collections-maps-2 + 0.1.0-SNAPSHOT + java-collections-maps-2 + jar + + + com.baeldung + parent-java + 0.0.1-SNAPSHOT + ../parent-java + + + + + org.eclipse.collections + eclipse-collections + ${eclipse-collections.version} + + + net.sf.trove4j + trove4j + ${trove4j.version} + + + it.unimi.dsi + fastutil + ${fastutil.version} + + + colt + colt + ${colt.version} + + + org.apache.commons + commons-lang3 + ${commons-lang3.version} + + + org.assertj + assertj-core + ${assertj.version} + test + + + + + 8.2.0 + 3.0.2 + 8.1.0 + 1.2.0 + 3.8.1 + 3.11.1 + + + \ No newline at end of file diff --git a/java-collections-maps-2/src/main/java/com/baeldung/map/CopyHashMap.java b/java-collections-maps-2/src/main/java/com/baeldung/map/CopyHashMap.java new file mode 100644 index 0000000000..2ebc9413c8 --- /dev/null +++ b/java-collections-maps-2/src/main/java/com/baeldung/map/CopyHashMap.java @@ -0,0 +1,55 @@ +package com.baeldung.map; + +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.stream.Collectors; + +import org.apache.commons.lang3.SerializationUtils; + +public class CopyHashMap { + + public static HashMap copyUsingConstructor(HashMap originalMap) { + return new HashMap(originalMap); + } + + public static HashMap copyUsingClone(HashMap originalMap) { + return (HashMap) originalMap.clone(); + } + + public static HashMap copyUsingPut(HashMap originalMap) { + HashMap shallowCopy = new HashMap(); + Set> entries = originalMap.entrySet(); + for(Map.Entry mapEntry: entries) { + shallowCopy.put(mapEntry.getKey(), mapEntry.getValue()); + } + + return shallowCopy; + } + + public static HashMap copyUsingPutAll(HashMap originalMap) { + HashMap shallowCopy = new HashMap(); + shallowCopy.putAll(originalMap); + + return shallowCopy; + } + + public static HashMap copyUsingJava8Stream(HashMap originalMap) { + Set> entries = originalMap.entrySet(); + HashMap shallowCopy = (HashMap) entries + .stream() + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + + return shallowCopy; + } + + public static HashMap shallowCopy(HashMap originalMap) { + return (HashMap) originalMap.clone(); + } + + public static HashMap deepCopy(HashMap originalMap) { + return SerializationUtils.clone(originalMap); + } + +} diff --git a/java-collections-maps-2/src/main/java/com/baeldung/map/PrimitiveMaps.java b/java-collections-maps-2/src/main/java/com/baeldung/map/PrimitiveMaps.java new file mode 100644 index 0000000000..d835950c68 --- /dev/null +++ b/java-collections-maps-2/src/main/java/com/baeldung/map/PrimitiveMaps.java @@ -0,0 +1,69 @@ +package com.baeldung.map; + +import cern.colt.map.AbstractIntDoubleMap; +import cern.colt.map.OpenIntDoubleHashMap; +import gnu.trove.map.TDoubleIntMap; +import gnu.trove.map.hash.TDoubleIntHashMap; +import it.unimi.dsi.fastutil.ints.Int2BooleanMap; +import it.unimi.dsi.fastutil.ints.Int2BooleanOpenHashMap; +import it.unimi.dsi.fastutil.ints.Int2BooleanSortedMap; +import it.unimi.dsi.fastutil.ints.Int2BooleanSortedMaps; +import org.eclipse.collections.api.map.primitive.ImmutableIntIntMap; +import org.eclipse.collections.api.map.primitive.MutableIntIntMap; +import org.eclipse.collections.api.map.primitive.MutableObjectDoubleMap; +import org.eclipse.collections.impl.factory.primitive.IntIntMaps; +import org.eclipse.collections.impl.factory.primitive.ObjectDoubleMaps; + +public class PrimitiveMaps { + + public static void main(String[] args) { + + eclipseCollectionsMap(); + troveMap(); + coltMap(); + fastutilMap(); + } + + private static void fastutilMap() { + Int2BooleanMap int2BooleanMap = new Int2BooleanOpenHashMap(); + int2BooleanMap.put(1, true); + int2BooleanMap.put(7, false); + int2BooleanMap.put(4, true); + + boolean value = int2BooleanMap.get(1); + + Int2BooleanSortedMap int2BooleanSorted = Int2BooleanSortedMaps.EMPTY_MAP; + } + + private static void coltMap() { + AbstractIntDoubleMap map = new OpenIntDoubleHashMap(); + map.put(1, 4.5); + double value = map.get(1); + } + + private static void eclipseCollectionsMap() { + MutableIntIntMap mutableIntIntMap = IntIntMaps.mutable.empty(); + mutableIntIntMap.addToValue(1, 1); + + ImmutableIntIntMap immutableIntIntMap = IntIntMaps.immutable.empty(); + + MutableObjectDoubleMap dObject = ObjectDoubleMaps.mutable.empty(); + dObject.addToValue("price", 150.5); + dObject.addToValue("quality", 4.4); + dObject.addToValue("stability", 0.8); + } + + private static void troveMap() { + double[] doubles = new double[] {1.2, 4.5, 0.3}; + int[] ints = new int[] {1, 4, 0}; + + TDoubleIntMap doubleIntMap = new TDoubleIntHashMap(doubles, ints); + + doubleIntMap.put(1.2, 22); + doubleIntMap.put(4.5, 16); + + doubleIntMap.adjustValue(1.2, 1); + doubleIntMap.adjustValue(4.5, 4); + doubleIntMap.adjustValue(0.3, 7); + } +} diff --git a/java-collections-maps-2/src/test/java/com/baeldung/map/CopyHashMapUnitTest.java b/java-collections-maps-2/src/test/java/com/baeldung/map/CopyHashMapUnitTest.java new file mode 100644 index 0000000000..c400eea153 --- /dev/null +++ b/java-collections-maps-2/src/test/java/com/baeldung/map/CopyHashMapUnitTest.java @@ -0,0 +1,77 @@ +package com.baeldung.map; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.Test; + +import com.google.common.collect.ImmutableMap; + +public class CopyHashMapUnitTest { + + @Test + public void givenHashMap_whenShallowCopy_thenCopyisNotSameAsOriginal() { + + HashMap map = new HashMap<>(); + Employee emp1 = new Employee("John"); + Employee emp2 = new Employee("Norman"); + map.put("emp1",emp1); + map.put("emp2",emp2); + + HashMap shallowCopy = CopyHashMap.shallowCopy(map); + + assertThat(shallowCopy).isNotSameAs(map); + + } + + @Test + public void givenHashMap_whenShallowCopyModifyingOriginalObject_thenCopyShouldChange() { + + HashMap map = new HashMap<>(); + Employee emp1 = new Employee("John"); + Employee emp2 = new Employee("Norman"); + map.put("emp1",emp1); + map.put("emp2",emp2); + + HashMap shallowCopy = CopyHashMap.shallowCopy(map); + + emp1.setName("Johny"); + + assertThat(shallowCopy.get("emp1")).isEqualTo(map.get("emp1")); + + } + + @Test + public void givenHashMap_whenDeepCopyModifyingOriginalObject_thenCopyShouldNotChange() { + + HashMap map = new HashMap<>(); + Employee emp1 = new Employee("John"); + Employee emp2 = new Employee("Norman"); + map.put("emp1",emp1); + map.put("emp2",emp2); + HashMap deepCopy = CopyHashMap.deepCopy(map); + + emp1.setName("Johny"); + + assertThat(deepCopy.get("emp1")).isNotEqualTo(map.get("emp1")); + + } + + @Test + public void givenImmutableMap_whenCopyUsingGuava_thenCopyShouldNotChange() { + Employee emp1 = new Employee("John"); + Employee emp2 = new Employee("Norman"); + + Map map = ImmutableMap. builder() + .put("emp1",emp1) + .put("emp2",emp2) + .build(); + Map shallowCopy = ImmutableMap.copyOf(map); + + assertThat(shallowCopy).isSameAs(map); + + } + +} diff --git a/java-collections-maps-2/src/test/java/com/baeldung/map/Employee.java b/java-collections-maps-2/src/test/java/com/baeldung/map/Employee.java new file mode 100644 index 0000000000..7963fa811c --- /dev/null +++ b/java-collections-maps-2/src/test/java/com/baeldung/map/Employee.java @@ -0,0 +1,28 @@ +package com.baeldung.map; + +import java.io.Serializable; + +public class Employee implements Serializable{ + + private String name; + + public Employee(String name) { + super(); + this.name = name; + } + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public String toString() { + return this.name; + } + +} + + diff --git a/java-dates-2/.gitignore b/java-dates-2/.gitignore new file mode 100644 index 0000000000..6471aabbcf --- /dev/null +++ b/java-dates-2/.gitignore @@ -0,0 +1,29 @@ +*.class + +0.* + +#folders# +/target +/neoDb* +/data +/src/main/webapp/WEB-INF/classes +*/META-INF/* +.resourceCache + +# Packaged files # +*.jar +*.war +*.ear + +# Files generated by integration tests +*.txt +backup-pom.xml +/bin/ +/temp + +#IntelliJ specific +.idea/ +*.iml + +#jenv +.java-version \ No newline at end of file diff --git a/java-dates-2/README.md b/java-dates-2/README.md new file mode 100644 index 0000000000..a6b5c8e574 --- /dev/null +++ b/java-dates-2/README.md @@ -0,0 +1,2 @@ +## Relevant Articles: +- [Converting Between LocalDate and XMLGregorianCalendar](https://www.baeldung.com/java-localdate-to-xmlgregoriancalendar) diff --git a/java-dates-2/pom.xml b/java-dates-2/pom.xml new file mode 100644 index 0000000000..9307a794b9 --- /dev/null +++ b/java-dates-2/pom.xml @@ -0,0 +1,62 @@ + + 4.0.0 + com.baeldung + java-dates-2 + 0.1.0-SNAPSHOT + jar + java-dates-2 + + + com.baeldung + parent-java + 0.0.1-SNAPSHOT + ../parent-java + + + + + joda-time + joda-time + ${joda-time.version} + + + + + org.assertj + assertj-core + ${assertj.version} + test + + + + + java-dates-2 + + + src/main/resources + true + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + ${maven.compiler.source} + ${maven.compiler.target} + + + + + + + + 3.6.1 + 2.10 + 1.9 + 1.9 + + diff --git a/java-dates-2/src/test/java/com/baeldung/convert/ConvertDateTimeUnitTest.java b/java-dates-2/src/test/java/com/baeldung/convert/ConvertDateTimeUnitTest.java new file mode 100644 index 0000000000..cd31ccc799 --- /dev/null +++ b/java-dates-2/src/test/java/com/baeldung/convert/ConvertDateTimeUnitTest.java @@ -0,0 +1,59 @@ +package com.baeldung.convert; + +import org.joda.time.Instant; +import org.junit.Assert; +import org.junit.Test; + +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.Calendar; +import java.util.Date; + +public class ConvertDateTimeUnitTest { + + public final long millis = 1556175797428L; + + @Test + public void givenLocalDateTime_WhenToEpochMillis_ThenMillis() { + ZoneId id = ZoneId.systemDefault(); + + LocalDateTime localDateTime = + LocalDateTime.ofInstant(java.time.Instant.ofEpochMilli(millis), id); + + ZonedDateTime zdt = ZonedDateTime.of(localDateTime, id); + + Assert.assertEquals(millis, zdt.toInstant().toEpochMilli()); + } + + @Test + public void givenJava8Instant_WhenGToEpochMillis_ThenMillis() { + java.time.Instant instant = java.time.Instant.ofEpochMilli(millis); + Assert.assertEquals(millis, instant.toEpochMilli()); + } + + @Test + public void givenDate_WhenGetTime_ThenMillis() { + Date date = new Date(millis); + Assert.assertEquals(millis, date.getTime()); + } + + @Test + public void givenCalendar_WhenGetTimeInMillis_ThenMillis() { + Calendar calendar = Calendar.getInstance(); + calendar.setTime(new Date(millis)); + Assert.assertEquals(millis, calendar.getTimeInMillis()); + } + + @Test + public void givenJodaInstant_WhenGetMillis_ThenMillis() { + Instant jodaInstant = Instant.ofEpochMilli(millis); + Assert.assertEquals(millis, jodaInstant.getMillis()); + } + + @Test + public void givenJODADateTime_WhenGetMillis_ThenMillis() { + org.joda.time.DateTime jodaDateTime = new org.joda.time.DateTime(millis); + Assert.assertEquals(millis, jodaDateTime.getMillis()); + } +} diff --git a/java-dates-2/src/test/java/com/baeldung/xmlgregoriancalendar/XmlGregorianCalendarConverterUnitTest.java b/java-dates-2/src/test/java/com/baeldung/xmlgregoriancalendar/XmlGregorianCalendarConverterUnitTest.java new file mode 100644 index 0000000000..b221c04199 --- /dev/null +++ b/java-dates-2/src/test/java/com/baeldung/xmlgregoriancalendar/XmlGregorianCalendarConverterUnitTest.java @@ -0,0 +1,36 @@ +package com.baeldung.xmlgregoriancalendar; + +import org.junit.Test; + +import javax.xml.datatype.DatatypeConfigurationException; +import javax.xml.datatype.DatatypeConstants; +import javax.xml.datatype.DatatypeFactory; +import javax.xml.datatype.XMLGregorianCalendar; +import java.time.LocalDate; + +import static org.assertj.core.api.Assertions.assertThat; + +public class XmlGregorianCalendarConverterUnitTest { + + @Test + public void fromLocalDateToXMLGregorianCalendar() throws DatatypeConfigurationException { + LocalDate localDate = LocalDate.of(2017, 4, 25); + XMLGregorianCalendar xmlGregorianCalendar = DatatypeFactory.newInstance().newXMLGregorianCalendar(localDate.toString()); + + assertThat(xmlGregorianCalendar.getYear()).isEqualTo(localDate.getYear()); + assertThat(xmlGregorianCalendar.getMonth()).isEqualTo(localDate.getMonthValue()); + assertThat(xmlGregorianCalendar.getDay()).isEqualTo(localDate.getDayOfMonth()); + assertThat(xmlGregorianCalendar.getTimezone()).isEqualTo(DatatypeConstants.FIELD_UNDEFINED); + } + + @Test + public void fromXMLGregorianCalendarToLocalDate() throws DatatypeConfigurationException { + XMLGregorianCalendar xmlGregorianCalendar = DatatypeFactory.newInstance().newXMLGregorianCalendar("2017-04-25"); + LocalDate localDate = LocalDate.of(xmlGregorianCalendar.getYear(), xmlGregorianCalendar.getMonth(), xmlGregorianCalendar.getDay()); + + assertThat(localDate.getYear()).isEqualTo(xmlGregorianCalendar.getYear()); + assertThat(localDate.getMonthValue()).isEqualTo(xmlGregorianCalendar.getMonth()); + assertThat(localDate.getDayOfMonth()).isEqualTo(xmlGregorianCalendar.getDay()); + } + +} diff --git a/java-math/.gitignore b/java-math/.gitignore new file mode 100644 index 0000000000..30b2b7442c --- /dev/null +++ b/java-math/.gitignore @@ -0,0 +1,4 @@ +/target/ +.settings/ +.classpath +.project \ No newline at end of file diff --git a/java-math/README.md b/java-math/README.md new file mode 100644 index 0000000000..d821348204 --- /dev/null +++ b/java-math/README.md @@ -0,0 +1,10 @@ +## Relevant articles: + +- [Calculate Factorial in Java](https://www.baeldung.com/java-calculate-factorial) +- [Generate Combinations in Java](https://www.baeldung.com/java-combinations-algorithm) +- [Check If Two Rectangles Overlap In Java](https://www.baeldung.com/java-check-if-two-rectangles-overlap) +- [Calculate the Distance Between Two Points in Java](https://www.baeldung.com/java-distance-between-two-points) +- [Find the Intersection of Two Lines in Java](https://www.baeldung.com/java-intersection-of-two-lines) +- [Round Up to the Nearest Hundred](https://www.baeldung.com/java-round-up-nearest-hundred) +- [Calculate Percentage in Java](https://www.baeldung.com/java-calculate-percentage) +- [Convert Latitude and Longitude to a 2D Point in Java](https://www.baeldung.com/java-convert-latitude-longitude) \ No newline at end of file diff --git a/java-math/pom.xml b/java-math/pom.xml new file mode 100644 index 0000000000..159d053df3 --- /dev/null +++ b/java-math/pom.xml @@ -0,0 +1,68 @@ + + 4.0.0 + java-math + 0.0.1-SNAPSHOT + java-math + + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + + + + + org.apache.commons + commons-math3 + ${commons-math3.version} + + + com.google.guava + guava + ${guava.version} + + + commons-codec + commons-codec + ${commons-codec.version} + + + org.projectlombok + lombok + ${lombok.version} + provided + + + org.assertj + assertj-core + ${org.assertj.core.version} + test + + + com.github.dpaukov + combinatoricslib3 + 3.3.0 + + + + + + + + org.codehaus.mojo + exec-maven-plugin + ${exec-maven-plugin.version} + + + + + + + 3.6.1 + 3.9.0 + 1.11 + 27.0.1-jre + + + \ No newline at end of file diff --git a/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/combination/ApacheCommonsCombinationGenerator.java b/java-math/src/main/java/com/baeldung/algorithms/combination/ApacheCommonsCombinationGenerator.java similarity index 100% rename from algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/combination/ApacheCommonsCombinationGenerator.java rename to java-math/src/main/java/com/baeldung/algorithms/combination/ApacheCommonsCombinationGenerator.java diff --git a/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/combination/CombinatoricsLibCombinationGenerator.java b/java-math/src/main/java/com/baeldung/algorithms/combination/CombinatoricsLibCombinationGenerator.java similarity index 100% rename from algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/combination/CombinatoricsLibCombinationGenerator.java rename to java-math/src/main/java/com/baeldung/algorithms/combination/CombinatoricsLibCombinationGenerator.java diff --git a/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/combination/GuavaCombinationsGenerator.java b/java-math/src/main/java/com/baeldung/algorithms/combination/GuavaCombinationsGenerator.java similarity index 100% rename from algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/combination/GuavaCombinationsGenerator.java rename to java-math/src/main/java/com/baeldung/algorithms/combination/GuavaCombinationsGenerator.java diff --git a/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/combination/IterativeCombinationGenerator.java b/java-math/src/main/java/com/baeldung/algorithms/combination/IterativeCombinationGenerator.java similarity index 100% rename from algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/combination/IterativeCombinationGenerator.java rename to java-math/src/main/java/com/baeldung/algorithms/combination/IterativeCombinationGenerator.java diff --git a/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/combination/SelectionRecursiveCombinationGenerator.java b/java-math/src/main/java/com/baeldung/algorithms/combination/SelectionRecursiveCombinationGenerator.java similarity index 100% rename from algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/combination/SelectionRecursiveCombinationGenerator.java rename to java-math/src/main/java/com/baeldung/algorithms/combination/SelectionRecursiveCombinationGenerator.java diff --git a/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/combination/SetRecursiveCombinationGenerator.java b/java-math/src/main/java/com/baeldung/algorithms/combination/SetRecursiveCombinationGenerator.java similarity index 100% rename from algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/combination/SetRecursiveCombinationGenerator.java rename to java-math/src/main/java/com/baeldung/algorithms/combination/SetRecursiveCombinationGenerator.java diff --git a/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/distancebetweenpoints/DistanceBetweenPointsService.java b/java-math/src/main/java/com/baeldung/algorithms/distancebetweenpoints/DistanceBetweenPointsService.java similarity index 100% rename from algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/distancebetweenpoints/DistanceBetweenPointsService.java rename to java-math/src/main/java/com/baeldung/algorithms/distancebetweenpoints/DistanceBetweenPointsService.java diff --git a/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/factorial/Factorial.java b/java-math/src/main/java/com/baeldung/algorithms/factorial/Factorial.java similarity index 100% rename from algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/factorial/Factorial.java rename to java-math/src/main/java/com/baeldung/algorithms/factorial/Factorial.java diff --git a/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/linesintersection/LinesIntersectionService.java b/java-math/src/main/java/com/baeldung/algorithms/linesintersection/LinesIntersectionService.java similarity index 100% rename from algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/linesintersection/LinesIntersectionService.java rename to java-math/src/main/java/com/baeldung/algorithms/linesintersection/LinesIntersectionService.java diff --git a/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/mercator/EllipticalMercator.java b/java-math/src/main/java/com/baeldung/algorithms/mercator/EllipticalMercator.java similarity index 100% rename from algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/mercator/EllipticalMercator.java rename to java-math/src/main/java/com/baeldung/algorithms/mercator/EllipticalMercator.java diff --git a/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/mercator/Mercator.java b/java-math/src/main/java/com/baeldung/algorithms/mercator/Mercator.java similarity index 100% rename from algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/mercator/Mercator.java rename to java-math/src/main/java/com/baeldung/algorithms/mercator/Mercator.java diff --git a/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/mercator/SphericalMercator.java b/java-math/src/main/java/com/baeldung/algorithms/mercator/SphericalMercator.java similarity index 100% rename from algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/mercator/SphericalMercator.java rename to java-math/src/main/java/com/baeldung/algorithms/mercator/SphericalMercator.java diff --git a/java-numbers/src/main/java/com/baeldung/percentage/PercentageCalculator.java b/java-math/src/main/java/com/baeldung/algorithms/percentage/PercentageCalculator.java similarity index 93% rename from java-numbers/src/main/java/com/baeldung/percentage/PercentageCalculator.java rename to java-math/src/main/java/com/baeldung/algorithms/percentage/PercentageCalculator.java index e74de2cc67..f69b23146e 100644 --- a/java-numbers/src/main/java/com/baeldung/percentage/PercentageCalculator.java +++ b/java-math/src/main/java/com/baeldung/algorithms/percentage/PercentageCalculator.java @@ -1,4 +1,4 @@ -package com.baeldung.percentage; +package com.baeldung.algorithms.percentage; import java.util.Scanner; diff --git a/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/rectanglesoverlap/Point.java b/java-math/src/main/java/com/baeldung/algorithms/rectanglesoverlap/Point.java similarity index 100% rename from algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/rectanglesoverlap/Point.java rename to java-math/src/main/java/com/baeldung/algorithms/rectanglesoverlap/Point.java diff --git a/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/rectanglesoverlap/Rectangle.java b/java-math/src/main/java/com/baeldung/algorithms/rectanglesoverlap/Rectangle.java similarity index 100% rename from algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/rectanglesoverlap/Rectangle.java rename to java-math/src/main/java/com/baeldung/algorithms/rectanglesoverlap/Rectangle.java diff --git a/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/roundedup/RoundUpToHundred.java b/java-math/src/main/java/com/baeldung/algorithms/roundedup/RoundUpToHundred.java similarity index 100% rename from algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/roundedup/RoundUpToHundred.java rename to java-math/src/main/java/com/baeldung/algorithms/roundedup/RoundUpToHundred.java diff --git a/java-math/src/main/resources/logback.xml b/java-math/src/main/resources/logback.xml new file mode 100644 index 0000000000..7d900d8ea8 --- /dev/null +++ b/java-math/src/main/resources/logback.xml @@ -0,0 +1,13 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + \ No newline at end of file diff --git a/algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/combination/CombinationUnitTest.java b/java-math/src/test/java/com/baeldung/algorithms/combination/CombinationUnitTest.java similarity index 100% rename from algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/combination/CombinationUnitTest.java rename to java-math/src/test/java/com/baeldung/algorithms/combination/CombinationUnitTest.java diff --git a/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/distancebetweenpoints/DistanceBetweenPointsServiceUnitTest.java b/java-math/src/test/java/com/baeldung/algorithms/distancebetweenpoints/DistanceBetweenPointsServiceUnitTest.java similarity index 93% rename from algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/distancebetweenpoints/DistanceBetweenPointsServiceUnitTest.java rename to java-math/src/test/java/com/baeldung/algorithms/distancebetweenpoints/DistanceBetweenPointsServiceUnitTest.java index 785afdbb2b..784681a807 100644 --- a/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/distancebetweenpoints/DistanceBetweenPointsServiceUnitTest.java +++ b/java-math/src/test/java/com/baeldung/algorithms/distancebetweenpoints/DistanceBetweenPointsServiceUnitTest.java @@ -2,8 +2,6 @@ package com.baeldung.algorithms.distancebetweenpoints; import org.junit.Test; -import com.baeldung.algorithms.distancebetweenpoints.DistanceBetweenPointsService; - import static org.junit.Assert.assertEquals; public class DistanceBetweenPointsServiceUnitTest { diff --git a/algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/factorial/FactorialUnitTest.java b/java-math/src/test/java/com/baeldung/algorithms/factorial/FactorialUnitTest.java similarity index 100% rename from algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/factorial/FactorialUnitTest.java rename to java-math/src/test/java/com/baeldung/algorithms/factorial/FactorialUnitTest.java diff --git a/algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/linesintersection/LinesIntersectionServiceUnitTest.java b/java-math/src/test/java/com/baeldung/algorithms/linesintersection/LinesIntersectionServiceUnitTest.java similarity index 100% rename from algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/linesintersection/LinesIntersectionServiceUnitTest.java rename to java-math/src/test/java/com/baeldung/algorithms/linesintersection/LinesIntersectionServiceUnitTest.java diff --git a/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/mercator/EllipticalMercatorUnitTest.java b/java-math/src/test/java/com/baeldung/algorithms/mercator/EllipticalMercatorUnitTest.java similarity index 100% rename from algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/mercator/EllipticalMercatorUnitTest.java rename to java-math/src/test/java/com/baeldung/algorithms/mercator/EllipticalMercatorUnitTest.java diff --git a/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/mercator/SphericalMercatorUnitTest.java b/java-math/src/test/java/com/baeldung/algorithms/mercator/SphericalMercatorUnitTest.java similarity index 100% rename from algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/mercator/SphericalMercatorUnitTest.java rename to java-math/src/test/java/com/baeldung/algorithms/mercator/SphericalMercatorUnitTest.java diff --git a/java-numbers/src/test/java/com/baeldung/percentage/PercentageCalculatorUnitTest.java b/java-math/src/test/java/com/baeldung/algorithms/percentage/PercentageCalculatorUnitTest.java similarity index 95% rename from java-numbers/src/test/java/com/baeldung/percentage/PercentageCalculatorUnitTest.java rename to java-math/src/test/java/com/baeldung/algorithms/percentage/PercentageCalculatorUnitTest.java index 202d4f8112..e49acc0c4b 100644 --- a/java-numbers/src/test/java/com/baeldung/percentage/PercentageCalculatorUnitTest.java +++ b/java-math/src/test/java/com/baeldung/algorithms/percentage/PercentageCalculatorUnitTest.java @@ -1,4 +1,4 @@ -package com.baeldung.percentage; +package com.baeldung.algorithms.percentage; import org.junit.Assert; import org.junit.Test; diff --git a/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/rectanglesoverlap/RectangleUnitTest.java b/java-math/src/test/java/com/baeldung/algorithms/rectanglesoverlap/RectangleUnitTest.java similarity index 93% rename from algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/rectanglesoverlap/RectangleUnitTest.java rename to java-math/src/test/java/com/baeldung/algorithms/rectanglesoverlap/RectangleUnitTest.java index 6707b34477..e4bb614b48 100644 --- a/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/rectanglesoverlap/RectangleUnitTest.java +++ b/java-math/src/test/java/com/baeldung/algorithms/rectanglesoverlap/RectangleUnitTest.java @@ -4,9 +4,6 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertFalse; import org.junit.Test; -import com.baeldung.algorithms.rectanglesoverlap.Point; -import com.baeldung.algorithms.rectanglesoverlap.Rectangle; - public class RectangleUnitTest { @Test diff --git a/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/roundedup/RoundUpToHundredUnitTest.java b/java-math/src/test/java/com/baeldung/algorithms/roundedup/RoundUpToHundredUnitTest.java similarity index 100% rename from algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/roundedup/RoundUpToHundredUnitTest.java rename to java-math/src/test/java/com/baeldung/algorithms/roundedup/RoundUpToHundredUnitTest.java diff --git a/java-streams-2/README.md b/java-streams-2/README.md new file mode 100644 index 0000000000..83ef97686f --- /dev/null +++ b/java-streams-2/README.md @@ -0,0 +1,3 @@ +### Relevant Articles: +- [Guide to Stream.reduce()](https://www.baeldung.com/java-stream-reduce) + diff --git a/java-streams-2/pom.xml b/java-streams-2/pom.xml new file mode 100644 index 0000000000..5004249352 --- /dev/null +++ b/java-streams-2/pom.xml @@ -0,0 +1,50 @@ + + + 4.0.0 + com.baeldung.javastreams2 + javastreams2 + 1.0 + Stream Reduce + jar + + + com.baeldung + parent-java + 0.0.1-SNAPSHOT + ../parent-java + + + + + org.openjdk.jmh + jmh-core + ${jmh.version} + + + org.openjdk.jmh + jmh-generator-annprocess + ${jmh.version} + + + junit + junit + ${junit.version} + test + jar + + + org.assertj + assertj-core + ${assertj.version} + test + + + + + UTF-8 + 1.8 + 1.8 + 1.21 + 3.11.1 + + \ No newline at end of file diff --git a/java-streams-2/src/main/java/com/baeldung/reduce/application/Application.java b/java-streams-2/src/main/java/com/baeldung/reduce/application/Application.java new file mode 100644 index 0000000000..79c557524d --- /dev/null +++ b/java-streams-2/src/main/java/com/baeldung/reduce/application/Application.java @@ -0,0 +1,39 @@ +package com.baeldung.reduce.application; + +import com.baeldung.reduce.entities.User; +import com.baeldung.reduce.utilities.NumberUtils; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class Application { + + public static void main(String[] args) { + List numbers = Arrays.asList(1, 2, 3, 4, 5, 6); + int result1 = numbers.stream().reduce(0, (subtotal, element) -> subtotal + element); + System.out.println(result1); + + int result2 = numbers.stream().reduce(0, Integer::sum); + System.out.println(result2); + + List letters = Arrays.asList("a", "b", "c", "d", "e"); + String result3 = letters.stream().reduce("", (partialString, element) -> partialString + element); + System.out.println(result3); + + String result4 = letters.stream().reduce("", String::concat); + System.out.println(result4); + + String result5 = letters.stream().reduce("", (partialString, element) -> partialString.toUpperCase() + element.toUpperCase()); + System.out.println(result5); + + List users = Arrays.asList(new User("John", 30), new User("Julie", 35)); + int result6 = users.stream().reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge(), Integer::sum); + System.out.println(result6); + + String result7 = letters.parallelStream().reduce("", String::concat); + System.out.println(result7); + + int result8 = users.parallelStream().reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge(), Integer::sum); + System.out.println(result8); + } +} diff --git a/java-streams-2/src/main/java/com/baeldung/reduce/benchmarks/JMHStreamReduceBenchMark.java b/java-streams-2/src/main/java/com/baeldung/reduce/benchmarks/JMHStreamReduceBenchMark.java new file mode 100644 index 0000000000..af4a9276a9 --- /dev/null +++ b/java-streams-2/src/main/java/com/baeldung/reduce/benchmarks/JMHStreamReduceBenchMark.java @@ -0,0 +1,52 @@ +package com.baeldung.reduce.benchmarks; + +import com.baeldung.reduce.entities.User; +import java.util.ArrayList; +import java.util.List; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.RunnerException; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +@State(Scope.Thread) +@BenchmarkMode(Mode.AverageTime) +public class JMHStreamReduceBenchMark { + + private final List userList = createUsers(); + + public static void main(String[] args) throws RunnerException { + + Options options = new OptionsBuilder() + .include(JMHStreamReduceBenchMark.class.getSimpleName()).threads(1) + .forks(1).shouldFailOnError(true).shouldDoGC(true) + .jvmArgs("-server").build(); + new Runner(options).run(); + } + + private List createUsers() { + List users = new ArrayList<>(); + for (int i = 0; i <= 1000000; i++) { + users.add(new User("John" + i, i)); + } + return users; + } + + @Benchmark + public Integer executeReduceOnParallelizedStream() { + return this.userList + .parallelStream() + .reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge(), Integer::sum); + } + + @Benchmark + public Integer executeReduceOnSequentialStream() { + return this.userList + .stream() + .reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge(), Integer::sum); + } +} diff --git a/java-streams-2/src/main/java/com/baeldung/reduce/entities/User.java b/java-streams-2/src/main/java/com/baeldung/reduce/entities/User.java new file mode 100644 index 0000000000..a17c6a02b6 --- /dev/null +++ b/java-streams-2/src/main/java/com/baeldung/reduce/entities/User.java @@ -0,0 +1,25 @@ +package com.baeldung.reduce.entities; + +public class User { + + private final String name; + private final int age; + + public User(String name, int age) { + this.name = name; + this.age = age; + } + + public String getName() { + return name; + } + + public int getAge() { + return age; + } + + @Override + public String toString() { + return "User{" + "name=" + name + ", age=" + age + '}'; + } +} diff --git a/java-streams-2/src/main/java/com/baeldung/reduce/utilities/NumberUtils.java b/java-streams-2/src/main/java/com/baeldung/reduce/utilities/NumberUtils.java new file mode 100644 index 0000000000..a7a4b8df29 --- /dev/null +++ b/java-streams-2/src/main/java/com/baeldung/reduce/utilities/NumberUtils.java @@ -0,0 +1,52 @@ +package com.baeldung.reduce.utilities; + +import java.util.List; +import java.util.function.BiFunction; +import java.util.logging.Level; +import java.util.logging.Logger; + +public abstract class NumberUtils { + + private static final Logger LOGGER = Logger.getLogger(NumberUtils.class.getName()); + + public static int divideListElements(List values, Integer divider) { + return values.stream() + .reduce(0, (a, b) -> { + try { + return a / divider + b / divider; + } catch (ArithmeticException e) { + LOGGER.log(Level.INFO, "Arithmetic Exception: Division by Zero"); + } + return 0; + }); + } + + public static int divideListElementsWithExtractedTryCatchBlock(List values, int divider) { + return values.stream().reduce(0, (a, b) -> divide(a, divider) + divide(b, divider)); + } + + public static int divideListElementsWithApplyFunctionMethod(List values, int divider) { + BiFunction division = (a, b) -> a / b; + return values.stream().reduce(0, (a, b) -> applyFunction(division, a, divider) + applyFunction(division, b, divider)); + } + + private static int divide(int value, int factor) { + int result = 0; + try { + result = value / factor; + } catch (ArithmeticException e) { + LOGGER.log(Level.INFO, "Arithmetic Exception: Division by Zero"); + } + return result; + } + + private static int applyFunction(BiFunction function, int a, int b) { + try { + return function.apply(a, b); + } + catch(Exception e) { + LOGGER.log(Level.INFO, "Exception thrown!"); + } + return 0; + } +} diff --git a/java-streams-2/src/test/java/com/baeldung/reduce/tests/StreamReduceUnitTest.java b/java-streams-2/src/test/java/com/baeldung/reduce/tests/StreamReduceUnitTest.java new file mode 100644 index 0000000000..564d614017 --- /dev/null +++ b/java-streams-2/src/test/java/com/baeldung/reduce/tests/StreamReduceUnitTest.java @@ -0,0 +1,79 @@ +package com.baeldung.reduce.tests; + +import com.baeldung.reduce.entities.User; +import com.baeldung.reduce.utilities.NumberUtils; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import static org.assertj.core.api.Assertions.assertThat; +import org.junit.Test; + +public class StreamReduceUnitTest { + + @Test + public void givenIntegerList_whenReduceWithSumAccumulatorLambda_thenCorrect() { + List numbers = Arrays.asList(1, 2, 3, 4, 5, 6); + int result = numbers.stream().reduce(0, (subtotal, element) -> subtotal + element); + assertThat(result).isEqualTo(21); + } + + @Test + public void givenIntegerList_whenReduceWithSumAccumulatorMethodReference_thenCorrect() { + List numbers = Arrays.asList(1, 2, 3, 4, 5, 6); + int result = numbers.stream().reduce(0, Integer::sum); + assertThat(result).isEqualTo(21); + } + + @Test + public void givenStringList_whenReduceWithConcatenatorAccumulatorLambda_thenCorrect() { + List letters = Arrays.asList("a", "b", "c", "d", "e"); + String result = letters.stream().reduce("", (partialString, element) -> partialString + element); + assertThat(result).isEqualTo("abcde"); + } + + @Test + public void givenStringList_whenReduceWithConcatenatorAccumulatorMethodReference_thenCorrect() { + List letters = Arrays.asList("a", "b", "c", "d", "e"); + String result = letters.stream().reduce("", String::concat); + assertThat(result).isEqualTo("abcde"); + } + + @Test + public void givenStringList_whenReduceWithUppercaseConcatenatorAccumulator_thenCorrect() { + List letters = Arrays.asList("a", "b", "c", "d", "e"); + String result = letters.stream().reduce("", (partialString, element) -> partialString.toUpperCase() + element.toUpperCase()); + assertThat(result).isEqualTo("ABCDE"); + } + + @Test + public void givenUserList_whenReduceWithAgeAccumulatorAndSumCombiner_thenCorrect() { + List users = Arrays.asList(new User("John", 30), new User("Julie", 35)); + int result = users.stream().reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge(), Integer::sum); + assertThat(result).isEqualTo(65); + } + + @Test + public void givenStringList_whenReduceWithParallelStream_thenCorrect() { + List letters = Arrays.asList("a", "b", "c", "d", "e"); + String result = letters.parallelStream().reduce("", String::concat); + assertThat(result).isEqualTo("abcde"); + } + + @Test + public void givenNumberUtilsClass_whenCalledDivideListElements_thenCorrect() { + List numbers = Arrays.asList(1, 2, 3, 4, 5, 6); + assertThat(NumberUtils.divideListElements(numbers, 1)).isEqualTo(21); + } + + @Test + public void givenNumberUtilsClass_whenCalledDivideListElementsWithExtractedTryCatchBlock_thenCorrect() { + List numbers = Arrays.asList(1, 2, 3, 4, 5, 6); + assertThat(NumberUtils.divideListElementsWithExtractedTryCatchBlock(numbers, 1)).isEqualTo(21); + } + + @Test + public void givenStream_whneCalleddivideListElementsWithApplyFunctionMethod_thenCorrect() { + List numbers = Arrays.asList(1, 2, 3, 4, 5, 6); + assertThat(NumberUtils.divideListElementsWithApplyFunctionMethod(numbers, 1)).isEqualTo(21); + } +} diff --git a/java-streams/README.md b/java-streams/README.md index b931c0d7d9..0c9588c47e 100644 --- a/java-streams/README.md +++ b/java-streams/README.md @@ -8,7 +8,7 @@ - [Java 8 and Infinite Streams](http://www.baeldung.com/java-inifinite-streams) - [Java 8 Stream findFirst() vs. findAny()](http://www.baeldung.com/java-stream-findfirst-vs-findany) - [How to Get the Last Element of a Stream in Java?](http://www.baeldung.com/java-stream-last-element) -- [”Stream has already been operated upon or closed” Exception in Java](http://www.baeldung.com/java-stream-operated-upon-or-closed-exception) +- [“Stream has already been operated upon or closed” Exception in Java](http://www.baeldung.com/java-stream-operated-upon-or-closed-exception) - [Iterable to Stream in Java](http://www.baeldung.com/java-iterable-to-stream) - [How to Iterate Over a Stream With Indices](http://www.baeldung.com/java-stream-indices) - [Primitive Type Streams in Java 8](http://www.baeldung.com/java-8-primitive-streams) @@ -17,3 +17,4 @@ - [Java Stream Filter with Lambda Expression](https://www.baeldung.com/java-stream-filter-lambda) - [Counting Matches on a Stream Filter](https://www.baeldung.com/java-stream-filter-count) - [Java 8 Streams peek() API](https://www.baeldung.com/java-streams-peek-api) +- [Working With Maps Using Streams](https://www.baeldung.com/java-maps-streams) diff --git a/java-strings-2/pom.xml b/java-strings-2/pom.xml new file mode 100755 index 0000000000..c314cd8cad --- /dev/null +++ b/java-strings-2/pom.xml @@ -0,0 +1,150 @@ + + 4.0.0 + java-strings-2 + 0.1.0-SNAPSHOT + jar + java-strings-2 + + + com.baeldung + parent-java + 0.0.1-SNAPSHOT + ../parent-java + + + + + commons-io + commons-io + ${commons-io.version} + + + log4j + log4j + ${log4j.version} + + + commons-codec + commons-codec + ${commons-codec.version} + + + + org.assertj + assertj-core + ${assertj.version} + test + + + org.openjdk.jmh + jmh-core + ${jmh-core.version} + + + org.openjdk.jmh + jmh-generator-annprocess + ${jmh-core.version} + + + com.ibm.icu + icu4j + ${icu4j.version} + + + com.google.guava + guava + ${guava.version} + + + com.vdurmont + emoji-java + ${emoji-java.version} + + + org.apache.commons + commons-lang3 + ${commons-lang3.version} + + + junit + junit + ${junit.version} + test + + + org.junit.jupiter + junit-jupiter-api + ${junit-jupiter-api.version} + test + + + + org.hamcrest + hamcrest-library + ${hamcrest-library.version} + test + + + + + org.passay + passay + ${passay.version} + + + org.apache.commons + commons-text + ${commons-text.version} + + + + org.ahocorasick + ahocorasick + ${ahocorasick.version} + + + + + + java-strings-2 + + + src/main/resources + true + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + ${java.version} + ${java.version} + -parameters + + + + + + + + 3.8.1 + 1.10 + + 3.6.1 + 1.19 + 61.1 + 27.0.1-jre + 4.0.0 + 5.3.1 + 1.3 + 1.3.1 + 1.4 + 0.4.0 + + + \ No newline at end of file diff --git a/java-strings-2/src/main/java/com/baeldung/string/search/performance/SubstringSearchPerformanceComparison.java b/java-strings-2/src/main/java/com/baeldung/string/search/performance/SubstringSearchPerformanceComparison.java new file mode 100644 index 0000000000..bf33c47a7e --- /dev/null +++ b/java-strings-2/src/main/java/com/baeldung/string/search/performance/SubstringSearchPerformanceComparison.java @@ -0,0 +1,58 @@ +package com.baeldung.string.search.performance; + +import java.util.concurrent.TimeUnit; +import java.util.regex.Pattern; + +import org.apache.commons.lang3.StringUtils; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; + +/** + * Based on https://github.com/tedyoung/indexof-contains-benchmark + */ +@Fork(5) +@State(Scope.Benchmark) +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +public class SubstringSearchPerformanceComparison { + + private String message; + + private Pattern pattern; + + public static void main(String[] args) throws Exception { + org.openjdk.jmh.Main.main(args); + } + + @Setup + public void setup() { + message = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum"; + pattern = Pattern.compile("(? + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + \ No newline at end of file diff --git a/java-strings-2/src/test/java/com/baeldung/string/search/SubstringSearch.java b/java-strings-2/src/test/java/com/baeldung/string/search/SubstringSearch.java new file mode 100644 index 0000000000..4a5adb45ef --- /dev/null +++ b/java-strings-2/src/test/java/com/baeldung/string/search/SubstringSearch.java @@ -0,0 +1,70 @@ +package com.baeldung.string.search; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.commons.lang3.StringUtils; +import org.junit.Assert; +import org.junit.Test; + +/** + * BAEL-2832: Different ways to check if a Substring could be found in a String. + */ +public class SubstringSearch { + + @Test + public void searchSubstringWithIndexOf() { + Assert.assertEquals(9, "Bohemian Rhapsodyan".indexOf("Rhap")); + + // indexOf will return -1, because it's case sensitive + Assert.assertEquals(-1, "Bohemian Rhapsodyan".indexOf("rhap")); + + // indexOf will return 9, because it's all lowercase + Assert.assertEquals(9, "Bohemian Rhapsodyan".toLowerCase() + .indexOf("rhap")); + + // it will return 6, because it's the first occurrence. Sorry Queen for being blasphemic + Assert.assertEquals(6, "Bohemian Rhapsodyan".indexOf("an")); + } + + @Test + public void searchSubstringWithContains() { + Assert.assertTrue("Hey Ho, let's go".contains("Hey")); + + // contains will return false, because it's case sensitive + Assert.assertFalse("Hey Ho, let's go".contains("hey")); + + // contains will return true, because it's all lowercase + Assert.assertTrue("Hey Ho, let's go".toLowerCase().contains("hey")); + + // contains will return false, because 'jey' can't be found + Assert.assertFalse("Hey Ho, let's go".contains("jey")); + } + + @Test + public void searchSubstringWithStringUtils() { + Assert.assertTrue(StringUtils.containsIgnoreCase("Runaway train", "train")); + + // it will also be true, because ignores case ;) + Assert.assertTrue(StringUtils.containsIgnoreCase("Runaway train", "Train")); + } + + @Test + public void searchUsingPattern() { + + // We create the Pattern first + Pattern pattern = Pattern.compile("(? lf) + +*.bat text eol=crlf +*.coffee text +*.css text +*.cql text +*.df text +*.ejs text +*.html text +*.java text +*.js text +*.json text +*.less text +*.properties text +*.sass text +*.scss text +*.sh text eol=lf +*.sql text +*.txt text +*.ts text +*.xml text +*.yaml text +*.yml text + +# Documents +*.doc diff=astextplain +*.DOC diff=astextplain +*.docx diff=astextplain +*.DOCX diff=astextplain +*.dot diff=astextplain +*.DOT diff=astextplain +*.pdf diff=astextplain +*.PDF diff=astextplain +*.rtf diff=astextplain +*.RTF diff=astextplain +*.markdown text +*.md text +*.adoc text +*.textile text +*.mustache text +*.csv text +*.tab text +*.tsv text +*.txt text +AUTHORS text +CHANGELOG text +CHANGES text +CONTRIBUTING text +COPYING text +copyright text +*COPYRIGHT* text +INSTALL text +license text +LICENSE text +NEWS text +readme text +*README* text +TODO text + +# Graphics +*.png binary +*.jpg binary +*.jpeg binary +*.gif binary +*.tif binary +*.tiff binary +*.ico binary +# SVG treated as an asset (binary) by default. If you want to treat it as text, +# comment-out the following line and uncomment the line after. +*.svg binary +#*.svg text +*.eps binary + +# These files are binary and should be left untouched +# (binary is a macro for -text -diff) +*.class binary +*.jar binary +*.war binary + +## LINTERS +.csslintrc text +.eslintrc text +.jscsrc text +.jshintrc text +.jshintignore text +.stylelintrc text + +## CONFIGS +*.conf text +*.config text +.editorconfig text +.gitattributes text +.gitconfig text +.gitignore text +.htaccess text +*.npmignore text + +## HEROKU +Procfile text +.slugignore text + +## AUDIO +*.kar binary +*.m4a binary +*.mid binary +*.midi binary +*.mp3 binary +*.ogg binary +*.ra binary + +## VIDEO +*.3gpp binary +*.3gp binary +*.as binary +*.asf binary +*.asx binary +*.fla binary +*.flv binary +*.m4v binary +*.mng binary +*.mov binary +*.mp4 binary +*.mpeg binary +*.mpg binary +*.swc binary +*.swf binary +*.webm binary + +## ARCHIVES +*.7z binary +*.gz binary +*.rar binary +*.tar binary +*.zip binary + +## FONTS +*.ttf binary +*.eot binary +*.otf binary +*.woff binary +*.woff2 binary diff --git a/jhipster-5/bookstore-monolith/.gitignore b/jhipster-5/bookstore-monolith/.gitignore new file mode 100644 index 0000000000..f1f6845d33 --- /dev/null +++ b/jhipster-5/bookstore-monolith/.gitignore @@ -0,0 +1,145 @@ +###################### +# Project Specific +###################### +/src/main/webapp/content/css/main.css +/target/www/** +/src/test/javascript/coverage/ + +###################### +# Node +###################### +/node/ +node_tmp/ +node_modules/ +npm-debug.log.* +/.awcache/* +/.cache-loader/* + +###################### +# SASS +###################### +.sass-cache/ + +###################### +# Eclipse +###################### +*.pydevproject +.project +.metadata +tmp/ +tmp/**/* +*.tmp +*.bak +*.swp +*~.nib +local.properties +.classpath +.settings/ +.loadpath +.factorypath +/src/main/resources/rebel.xml + +# External tool builders +.externalToolBuilders/** + +# Locally stored "Eclipse launch configurations" +*.launch + +# CDT-specific +.cproject + +# PDT-specific +.buildpath + +###################### +# Intellij +###################### +.idea/ +*.iml +*.iws +*.ipr +*.ids +*.orig +classes/ +out/ + +###################### +# Visual Studio Code +###################### +.vscode/ + +###################### +# Maven +###################### +/log/ +/target/ + +###################### +# Gradle +###################### +.gradle/ +/build/ + +###################### +# Package Files +###################### +*.jar +*.war +*.ear +*.db + +###################### +# Windows +###################### +# Windows image file caches +Thumbs.db + +# Folder config file +Desktop.ini + +###################### +# Mac OSX +###################### +.DS_Store +.svn + +# Thumbnails +._* + +# Files that might appear on external disk +.Spotlight-V100 +.Trashes + +###################### +# Directories +###################### +/bin/ +/deploy/ + +###################### +# Logs +###################### +*.log* + +###################### +# Others +###################### +*.class +*.*~ +*~ +.merge_file* + +###################### +# Gradle Wrapper +###################### +!gradle/wrapper/gradle-wrapper.jar + +###################### +# Maven Wrapper +###################### +!.mvn/wrapper/maven-wrapper.jar + +###################### +# ESLint +###################### +.eslintcache diff --git a/jhipster-5/bookstore-monolith/.huskyrc b/jhipster-5/bookstore-monolith/.huskyrc new file mode 100644 index 0000000000..9e18d87674 --- /dev/null +++ b/jhipster-5/bookstore-monolith/.huskyrc @@ -0,0 +1,5 @@ +{ + "hooks": { + "pre-commit": "lint-staged" + } +} diff --git a/jhipster-5/bookstore-monolith/.jhipster/Book.json b/jhipster-5/bookstore-monolith/.jhipster/Book.json new file mode 100644 index 0000000000..4c5bd1fa52 --- /dev/null +++ b/jhipster-5/bookstore-monolith/.jhipster/Book.json @@ -0,0 +1,54 @@ +{ + "fluentMethods": true, + "clientRootFolder": "", + "relationships": [], + "fields": [ + { + "fieldName": "title", + "fieldType": "String", + "fieldValidateRules": [ + "required" + ] + }, + { + "fieldName": "author", + "fieldType": "String", + "fieldValidateRules": [ + "required" + ] + }, + { + "fieldName": "published", + "fieldType": "LocalDate", + "fieldValidateRules": [ + "required" + ] + }, + { + "fieldName": "quantity", + "fieldType": "Integer", + "fieldValidateRules": [ + "required", + "min" + ], + "fieldValidateRulesMin": 0 + }, + { + "fieldName": "price", + "fieldType": "Double", + "fieldValidateRules": [ + "required", + "min" + ], + "fieldValidateRulesMin": 0 + } + ], + "changelogDate": "20190319124041", + "dto": "mapstruct", + "searchEngine": false, + "service": "serviceImpl", + "entityTableName": "book", + "databaseType": "sql", + "jpaMetamodelFiltering": false, + "pagination": "no" +} diff --git a/jhipster-5/bookstore-monolith/.mvn/wrapper/MavenWrapperDownloader.java b/jhipster-5/bookstore-monolith/.mvn/wrapper/MavenWrapperDownloader.java new file mode 100644 index 0000000000..8fe1fab5a2 --- /dev/null +++ b/jhipster-5/bookstore-monolith/.mvn/wrapper/MavenWrapperDownloader.java @@ -0,0 +1,110 @@ +/* +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you 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 + + http://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. +*/ + +import java.net.*; +import java.io.*; +import java.nio.channels.*; +import java.util.Properties; + +public class MavenWrapperDownloader { + + /** + * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. + */ + private static final String DEFAULT_DOWNLOAD_URL = + "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"; + + /** + * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to + * use instead of the default one. + */ + private static final String MAVEN_WRAPPER_PROPERTIES_PATH = + ".mvn/wrapper/maven-wrapper.properties"; + + /** + * Path where the maven-wrapper.jar will be saved to. + */ + private static final String MAVEN_WRAPPER_JAR_PATH = + ".mvn/wrapper/maven-wrapper.jar"; + + /** + * Name of the property which should be used to override the default download url for the wrapper. + */ + private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; + + public static void main(String args[]) { + System.out.println("- Downloader started"); + File baseDirectory = new File(args[0]); + System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); + + // If the maven-wrapper.properties exists, read it and check if it contains a custom + // wrapperUrl parameter. + File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); + String url = DEFAULT_DOWNLOAD_URL; + if (mavenWrapperPropertyFile.exists()) { + FileInputStream mavenWrapperPropertyFileInputStream = null; + try { + mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); + Properties mavenWrapperProperties = new Properties(); + mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); + url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); + } catch (IOException e) { + System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); + } finally { + try { + if (mavenWrapperPropertyFileInputStream != null) { + mavenWrapperPropertyFileInputStream.close(); + } + } catch (IOException e) { + // Ignore ... + } + } + } + System.out.println("- Downloading from: : " + url); + + File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); + if (!outputFile.getParentFile().exists()) { + if (!outputFile.getParentFile().mkdirs()) { + System.out.println( + "- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'"); + } + } + System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); + try { + downloadFileFromURL(url, outputFile); + System.out.println("Done"); + System.exit(0); + } catch (Throwable e) { + System.out.println("- Error downloading"); + e.printStackTrace(); + System.exit(1); + } + } + + private static void downloadFileFromURL(String urlString, File destination) throws Exception { + URL website = new URL(urlString); + ReadableByteChannel rbc; + rbc = Channels.newChannel(website.openStream()); + FileOutputStream fos = new FileOutputStream(destination); + fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); + fos.close(); + rbc.close(); + } + +} diff --git a/jhipster-5/bookstore-monolith/.mvn/wrapper/maven-wrapper.jar b/jhipster-5/bookstore-monolith/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000000..01e6799737 Binary files /dev/null and b/jhipster-5/bookstore-monolith/.mvn/wrapper/maven-wrapper.jar differ diff --git a/jhipster-5/bookstore-monolith/.mvn/wrapper/maven-wrapper.properties b/jhipster-5/bookstore-monolith/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000000..cd0d451ccd --- /dev/null +++ b/jhipster-5/bookstore-monolith/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1 @@ +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip diff --git a/jhipster-5/bookstore-monolith/.prettierignore b/jhipster-5/bookstore-monolith/.prettierignore new file mode 100644 index 0000000000..151fcf7916 --- /dev/null +++ b/jhipster-5/bookstore-monolith/.prettierignore @@ -0,0 +1,3 @@ +node_modules +target +package-lock.json diff --git a/jhipster-5/bookstore-monolith/.prettierrc b/jhipster-5/bookstore-monolith/.prettierrc new file mode 100644 index 0000000000..6fd4aa1267 --- /dev/null +++ b/jhipster-5/bookstore-monolith/.prettierrc @@ -0,0 +1,12 @@ +# Prettier configuration + +printWidth: 140 +singleQuote: true +tabWidth: 4 +useTabs: false + +# js and ts rules: +arrowParens: avoid + +# jsx and tsx rules: +jsxBracketSameLine: false diff --git a/jhipster-5/bookstore-monolith/.yo-rc.json b/jhipster-5/bookstore-monolith/.yo-rc.json new file mode 100644 index 0000000000..d852aeeddc --- /dev/null +++ b/jhipster-5/bookstore-monolith/.yo-rc.json @@ -0,0 +1,34 @@ +{ + "generator-jhipster": { + "promptValues": { + "packageName": "com.baeldung.jhipster5" + }, + "jhipsterVersion": "5.8.2", + "applicationType": "monolith", + "baseName": "Bookstore", + "packageName": "com.baeldung.jhipster5", + "packageFolder": "com/baeldung/jhipster5", + "serverPort": "8080", + "authenticationType": "jwt", + "cacheProvider": "no", + "websocket": false, + "databaseType": "sql", + "devDatabaseType": "h2Memory", + "prodDatabaseType": "mysql", + "searchEngine": false, + "messageBroker": false, + "serviceDiscoveryType": false, + "buildTool": "maven", + "enableSwaggerCodegen": false, + "jwtSecretKey": "NDJmOTVlZjI2NzhlZDRjNmVkNTM1NDE2NjkyNDljZDJiNzBlMjI5YmZjMjY3MzdjZmZlMjI3NjE4OTRkNzc5MWYzNDNlYWMzYmJjOWRmMjc5ZWQyZTZmOWZkOTMxZWZhNWE1MTVmM2U2NjFmYjhlNDc2Y2Q3NzliMGY0YzFkNmI=", + "clientFramework": "angularX", + "useSass": true, + "clientPackageManager": "npm", + "testFrameworks": [], + "jhiPrefix": "jhi", + "entitySuffix": "", + "dtoSuffix": "DTO", + "otherModules": [], + "enableTranslation": false + } +} diff --git a/jhipster-5/bookstore-monolith/README.md b/jhipster-5/bookstore-monolith/README.md new file mode 100644 index 0000000000..1387b82163 --- /dev/null +++ b/jhipster-5/bookstore-monolith/README.md @@ -0,0 +1,179 @@ +# Bookstore + +This application was generated using JHipster 5.8.2, you can find documentation and help at [https://www.jhipster.tech/documentation-archive/v5.8.2](https://www.jhipster.tech/documentation-archive/v5.8.2). + +## Development + +Before you can build this project, you must install and configure the following dependencies on your machine: + +1. [Node.js][]: We use Node to run a development web server and build the project. + Depending on your system, you can install Node either from source or as a pre-packaged bundle. + +After installing Node, you should be able to run the following command to install development tools. +You will only need to run this command when dependencies change in [package.json](package.json). + + npm install + +We use npm scripts and [Webpack][] as our build system. + +Run the following commands in two separate terminals to create a blissful development experience where your browser +auto-refreshes when files change on your hard drive. + + ./mvnw + npm start + +Npm is also used to manage CSS and JavaScript dependencies used in this application. You can upgrade dependencies by +specifying a newer version in [package.json](package.json). You can also run `npm update` and `npm install` to manage dependencies. +Add the `help` flag on any command to see how you can use it. For example, `npm help update`. + +The `npm run` command will list all of the scripts available to run for this project. + +### Service workers + +Service workers are commented by default, to enable them please uncomment the following code. + +- The service worker registering script in index.html + +```html + +``` + +Note: workbox creates the respective service worker and dynamically generate the `service-worker.js` + +### Managing dependencies + +For example, to add [Leaflet][] library as a runtime dependency of your application, you would run following command: + + npm install --save --save-exact leaflet + +To benefit from TypeScript type definitions from [DefinitelyTyped][] repository in development, you would run following command: + + npm install --save-dev --save-exact @types/leaflet + +Then you would import the JS and CSS files specified in library's installation instructions so that [Webpack][] knows about them: +Edit [src/main/webapp/app/vendor.ts](src/main/webapp/app/vendor.ts) file: + +``` +import 'leaflet/dist/leaflet.js'; +``` + +Edit [src/main/webapp/content/css/vendor.css](src/main/webapp/content/css/vendor.css) file: + +``` +@import '~leaflet/dist/leaflet.css'; +``` + +Note: there are still few other things remaining to do for Leaflet that we won't detail here. + +For further instructions on how to develop with JHipster, have a look at [Using JHipster in development][]. + +### Using angular-cli + +You can also use [Angular CLI][] to generate some custom client code. + +For example, the following command: + + ng generate component my-component + +will generate few files: + + create src/main/webapp/app/my-component/my-component.component.html + create src/main/webapp/app/my-component/my-component.component.ts + update src/main/webapp/app/app.module.ts + +## Building for production + +To optimize the Bookstore application for production, run: + + ./mvnw -Pprod clean package + +This will concatenate and minify the client CSS and JavaScript files. It will also modify `index.html` so it references these new files. +To ensure everything worked, run: + + java -jar target/*.war + +Then navigate to [http://localhost:8080](http://localhost:8080) in your browser. + +Refer to [Using JHipster in production][] for more details. + +## Testing + +To launch your application's tests, run: + + ./mvnw clean test + +### Client tests + +Unit tests are run by [Jest][] and written with [Jasmine][]. They're located in [src/test/javascript/](src/test/javascript/) and can be run with: + + npm test + +For more information, refer to the [Running tests page][]. + +### Code quality + +Sonar is used to analyse code quality. You can start a local Sonar server (accessible on http://localhost:9001) with: + +``` +docker-compose -f src/main/docker/sonar.yml up -d +``` + +Then, run a Sonar analysis: + +``` +./mvnw -Pprod clean test sonar:sonar +``` + +For more information, refer to the [Code quality page][]. + +## Using Docker to simplify development (optional) + +You can use Docker to improve your JHipster development experience. A number of docker-compose configuration are available in the [src/main/docker](src/main/docker) folder to launch required third party services. + +For example, to start a mysql database in a docker container, run: + + docker-compose -f src/main/docker/mysql.yml up -d + +To stop it and remove the container, run: + + docker-compose -f src/main/docker/mysql.yml down + +You can also fully dockerize your application and all the services that it depends on. +To achieve this, first build a docker image of your app by running: + + ./mvnw package -Pprod verify jib:dockerBuild + +Then run: + + docker-compose -f src/main/docker/app.yml up -d + +For more information refer to [Using Docker and Docker-Compose][], this page also contains information on the docker-compose sub-generator (`jhipster docker-compose`), which is able to generate docker configurations for one or several JHipster applications. + +## Continuous Integration (optional) + +To configure CI for your project, run the ci-cd sub-generator (`jhipster ci-cd`), this will let you generate configuration files for a number of Continuous Integration systems. Consult the [Setting up Continuous Integration][] page for more information. + +[jhipster homepage and latest documentation]: https://www.jhipster.tech +[jhipster 5.8.2 archive]: https://www.jhipster.tech/documentation-archive/v5.8.2 +[using jhipster in development]: https://www.jhipster.tech/documentation-archive/v5.8.2/development/ +[using docker and docker-compose]: https://www.jhipster.tech/documentation-archive/v5.8.2/docker-compose +[using jhipster in production]: https://www.jhipster.tech/documentation-archive/v5.8.2/production/ +[running tests page]: https://www.jhipster.tech/documentation-archive/v5.8.2/running-tests/ +[code quality page]: https://www.jhipster.tech/documentation-archive/v5.8.2/code-quality/ +[setting up continuous integration]: https://www.jhipster.tech/documentation-archive/v5.8.2/setting-up-ci/ +[node.js]: https://nodejs.org/ +[yarn]: https://yarnpkg.org/ +[webpack]: https://webpack.github.io/ +[angular cli]: https://cli.angular.io/ +[browsersync]: http://www.browsersync.io/ +[jest]: https://facebook.github.io/jest/ +[jasmine]: http://jasmine.github.io/2.0/introduction.html +[protractor]: https://angular.github.io/protractor/ +[leaflet]: http://leafletjs.com/ +[definitelytyped]: http://definitelytyped.org/ diff --git a/jhipster-5/bookstore-monolith/angular.json b/jhipster-5/bookstore-monolith/angular.json new file mode 100644 index 0000000000..61791db9fb --- /dev/null +++ b/jhipster-5/bookstore-monolith/angular.json @@ -0,0 +1,39 @@ +{ + "$schema": "./node_modules/@angular/cli/lib/config/schema.json", + "version": 1, + "newProjectRoot": "projects", + "projects": { + "bookstore": { + "root": "", + "sourceRoot": "src/main/webapp", + "projectType": "application", + "architect": {} + } + }, + "defaultProject": "bookstore", + "cli": { + "packageManager": "npm" + }, + "schematics": { + "@schematics/angular:component": { + "inlineStyle": true, + "inlineTemplate": false, + "spec": false, + "prefix": "jhi", + "styleExt": "scss" + }, + "@schematics/angular:directive": { + "spec": false, + "prefix": "jhi" + }, + "@schematics/angular:guard": { + "spec": false + }, + "@schematics/angular:pipe": { + "spec": false + }, + "@schematics/angular:service": { + "spec": false + } + } +} diff --git a/jhipster-5/bookstore-monolith/mvnw b/jhipster-5/bookstore-monolith/mvnw new file mode 100755 index 0000000000..5551fde8e7 --- /dev/null +++ b/jhipster-5/bookstore-monolith/mvnw @@ -0,0 +1,286 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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 +# +# http://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. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven2 Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + 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 + + 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/jhipster-5/bookstore-monolith/mvnw.cmd b/jhipster-5/bookstore-monolith/mvnw.cmd new file mode 100644 index 0000000000..e5cfb0ae9e --- /dev/null +++ b/jhipster-5/bookstore-monolith/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/jhipster-5/bookstore-monolith/package-lock.json b/jhipster-5/bookstore-monolith/package-lock.json new file mode 100644 index 0000000000..6e2a8dc526 --- /dev/null +++ b/jhipster-5/bookstore-monolith/package-lock.json @@ -0,0 +1,18244 @@ +{ + "name": "bookstore", + "version": "0.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@angular-devkit/architect": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.13.1.tgz", + "integrity": "sha512-QDmIbqde75ZZSEFbw6Q6kQWq4cY6C7D67yujXw6XTyubDNAs1tyXJyxTIB8vjSlEKwRizTTDd/B0ZXVcke3Mvw==", + "dev": true, + "requires": { + "@angular-devkit/core": "7.3.1", + "rxjs": "6.3.3" + }, + "dependencies": { + "rxjs": { + "version": "6.3.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.3.3.tgz", + "integrity": "sha512-JTWmoY9tWCs7zvIk/CvRjhjGaOd+OVBM987mxFo+OW66cGpdKjZcpmc74ES1sB//7Kl/PAe8+wEakuhG4pcgOw==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + } + } + }, + "@angular-devkit/core": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-7.3.1.tgz", + "integrity": "sha512-56XDWWfIzOAkEk69lBLgmCYybPUA4yjunhmMlCk7vVdb7gbQUyzNjFD04Uj0GjlejatAQ5F76tRwygD9C+3RXQ==", + "dev": true, + "requires": { + "ajv": "6.7.0", + "chokidar": "2.0.4", + "fast-json-stable-stringify": "2.0.0", + "rxjs": "6.3.3", + "source-map": "0.7.3" + }, + "dependencies": { + "rxjs": { + "version": "6.3.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.3.3.tgz", + "integrity": "sha512-JTWmoY9tWCs7zvIk/CvRjhjGaOd+OVBM987mxFo+OW66cGpdKjZcpmc74ES1sB//7Kl/PAe8+wEakuhG4pcgOw==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + } + } + }, + "@angular-devkit/schematics": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-7.3.1.tgz", + "integrity": "sha512-cd7usiasfSgw75INz72/VssrLr9tiVRYfo1TEdvr9ww0GuQbuQpB33xbV8W135eAV8+wzQ3Ce8ohaDHibvj6Yg==", + "dev": true, + "requires": { + "@angular-devkit/core": "7.3.1", + "rxjs": "6.3.3" + }, + "dependencies": { + "rxjs": { + "version": "6.3.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.3.3.tgz", + "integrity": "sha512-JTWmoY9tWCs7zvIk/CvRjhjGaOd+OVBM987mxFo+OW66cGpdKjZcpmc74ES1sB//7Kl/PAe8+wEakuhG4pcgOw==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + } + } + }, + "@angular/cli": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-7.3.1.tgz", + "integrity": "sha512-8EvXYRhTqTaTk5PKv7VZxIWJiyG51R9RC9gtpRFx4bbnurqBHdEUxGMmaRsGT8QDbfvVsWnuakE0eeW1CrfZAQ==", + "dev": true, + "requires": { + "@angular-devkit/architect": "0.13.1", + "@angular-devkit/core": "7.3.1", + "@angular-devkit/schematics": "7.3.1", + "@schematics/angular": "7.3.1", + "@schematics/update": "0.13.1", + "@yarnpkg/lockfile": "1.1.0", + "ini": "1.3.5", + "inquirer": "6.2.1", + "npm-package-arg": "6.1.0", + "opn": "5.4.0", + "pacote": "9.4.0", + "semver": "5.6.0", + "symbol-observable": "1.2.0" + }, + "dependencies": { + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true + }, + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "external-editor": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.0.3.tgz", + "integrity": "sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, + "inquirer": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.2.1.tgz", + "integrity": "sha512-088kl3DRT2dLU5riVMKKr1DlImd6X7smDhpXUCkJDCKvTEJeRiXh0G132HG9u5a+6Ylw9plFRY7RuTnwohYSpg==", + "dev": true, + "requires": { + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.0", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.0", + "figures": "^2.0.0", + "lodash": "^4.17.10", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rxjs": "^6.1.0", + "string-width": "^2.1.0", + "strip-ansi": "^5.0.0", + "through": "^2.3.6" + } + }, + "opn": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/opn/-/opn-5.4.0.tgz", + "integrity": "sha512-YF9MNdVy/0qvJvDtunAOzFw9iasOQHpVthTCvGzxt61Il64AYSGdK+rYwld7NAfk9qJ7dt+hymBNSc9LNYS+Sw==", + "dev": true, + "requires": { + "is-wsl": "^1.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@angular/common": { + "version": "7.2.4", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-7.2.4.tgz", + "integrity": "sha512-3/i8RtnLTx/90gJHk5maE8zwsSiHgHvLItaa0qVfNlWiU0eCId/PL6TgDkut5vN9SQYL0oxhxFaVd35HmwsmuQ==", + "requires": { + "tslib": "^1.9.0" + } + }, + "@angular/compiler": { + "version": "7.2.4", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-7.2.4.tgz", + "integrity": "sha512-+zyMzPCL45ePEV9nrnYJvhAVgp2Y19bDaq0f0YdZAqAjgDqHzXGGR6wX8GueyJWmUYWx5vwK6Apla4HwDrYA1w==", + "requires": { + "tslib": "^1.9.0" + } + }, + "@angular/compiler-cli": { + "version": "7.2.4", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-7.2.4.tgz", + "integrity": "sha512-UhLosSeuwFIfaGqGcYOh9WSOuzEpeuhIRAOt81MeqOQEqkoreUjfxrQq8XWNkdqsPZHtiptF5ZwXlMBxlj9jJg==", + "dev": true, + "requires": { + "canonical-path": "1.0.0", + "chokidar": "^1.4.2", + "convert-source-map": "^1.5.1", + "dependency-graph": "^0.7.2", + "magic-string": "^0.25.0", + "minimist": "^1.2.0", + "reflect-metadata": "^0.1.2", + "shelljs": "^0.8.1", + "source-map": "^0.6.1", + "tslib": "^1.9.0", + "yargs": "9.0.1" + }, + "dependencies": { + "anymatch": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", + "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", + "dev": true, + "requires": { + "micromatch": "^2.1.5", + "normalize-path": "^2.0.0" + } + }, + "arr-diff": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", + "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", + "dev": true, + "requires": { + "arr-flatten": "^1.0.1" + } + }, + "array-unique": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", + "dev": true + }, + "braces": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", + "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", + "dev": true, + "requires": { + "expand-range": "^1.8.1", + "preserve": "^0.2.0", + "repeat-element": "^1.1.2" + } + }, + "chokidar": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", + "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=", + "dev": true, + "requires": { + "anymatch": "^1.3.0", + "async-each": "^1.0.0", + "fsevents": "^1.0.0", + "glob-parent": "^2.0.0", + "inherits": "^2.0.1", + "is-binary-path": "^1.0.0", + "is-glob": "^2.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.0.0" + } + }, + "expand-brackets": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", + "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", + "dev": true, + "requires": { + "is-posix-bracket": "^0.1.0" + } + }, + "extglob": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", + "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", + "dev": true, + "requires": { + "is-extglob": "^1.0.0" + } + }, + "glob-parent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "dev": true, + "requires": { + "is-glob": "^2.0.0" + } + }, + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "dev": true + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "dev": true, + "requires": { + "is-extglob": "^1.0.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + }, + "micromatch": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", + "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", + "dev": true, + "requires": { + "arr-diff": "^2.0.0", + "array-unique": "^0.2.1", + "braces": "^1.8.2", + "expand-brackets": "^0.1.4", + "extglob": "^0.3.1", + "filename-regex": "^2.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.1", + "kind-of": "^3.0.2", + "normalize-path": "^2.0.1", + "object.omit": "^2.0.0", + "parse-glob": "^3.0.4", + "regex-cache": "^0.4.2" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "@angular/core": { + "version": "7.2.4", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-7.2.4.tgz", + "integrity": "sha512-kfAxhIxl89PmB7y81FR/RAv0yWRFcEYxEnTwV+o8jKGfemAXtQ0g/Vh+lJR0SD/TBgFilMxotN1mhwH4A8GShw==", + "requires": { + "tslib": "^1.9.0" + } + }, + "@angular/forms": { + "version": "7.2.4", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-7.2.4.tgz", + "integrity": "sha512-DAtOrdlTRsgvmZrsvczCAkY8dhTwZb5DXBmPuSXh0UR9lvEiCgNHGbwEiIiIkAHpw1wSeXZrq0qyy/oJRvf18g==", + "requires": { + "tslib": "^1.9.0" + } + }, + "@angular/platform-browser": { + "version": "7.2.4", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-7.2.4.tgz", + "integrity": "sha512-Klt8aKR5SP9bqfMfpSY5vQOY7AQEs8JGuZOk5Bfc2dUtYT2IEIvK2IqO8v2rcFRVO13HOPUxl328efyHqLgI7g==", + "requires": { + "tslib": "^1.9.0" + } + }, + "@angular/platform-browser-dynamic": { + "version": "7.2.4", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-7.2.4.tgz", + "integrity": "sha512-J/xWlmaYOPUoCHZ5TiIRiyYa4uRMtCz3aGdBfY8k/NWtNo8SCYaS3aut7Sk4RS5rK8aAVi+aYFlY5YOrlW+Hbg==", + "requires": { + "tslib": "^1.9.0" + } + }, + "@angular/router": { + "version": "7.2.4", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-7.2.4.tgz", + "integrity": "sha512-T8Uqf2H1SV1MQI38WwYJ4aa+4NNnvlp2Tp/rkfg6tKcp/cLkKqE6OOfiy9lmW+i/624v8tMgYoBMOUNBjAG23g==", + "requires": { + "tslib": "^1.9.0" + } + }, + "@babel/code-frame": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", + "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", + "dev": true, + "requires": { + "@babel/highlight": "^7.0.0" + } + }, + "@babel/core": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.3.4.tgz", + "integrity": "sha512-jRsuseXBo9pN197KnDwhhaaBzyZr2oIcLHHTt2oDdQrej5Qp57dCCJafWx5ivU8/alEYDpssYqv1MUqcxwQlrA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/generator": "^7.3.4", + "@babel/helpers": "^7.2.0", + "@babel/parser": "^7.3.4", + "@babel/template": "^7.2.2", + "@babel/traverse": "^7.3.4", + "@babel/types": "^7.3.4", + "convert-source-map": "^1.1.0", + "debug": "^4.1.0", + "json5": "^2.1.0", + "lodash": "^4.17.11", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "json5": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz", + "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/generator": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.3.4.tgz", + "integrity": "sha512-8EXhHRFqlVVWXPezBW5keTiQi/rJMQTg/Y9uVCEZ0CAF3PKtCCaVRnp64Ii1ujhkoDhhF1fVsImoN4yJ2uz4Wg==", + "dev": true, + "requires": { + "@babel/types": "^7.3.4", + "jsesc": "^2.5.1", + "lodash": "^4.17.11", + "source-map": "^0.5.0", + "trim-right": "^1.0.1" + }, + "dependencies": { + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/helper-function-name": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz", + "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.0.0", + "@babel/template": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz", + "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz", + "integrity": "sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA==", + "dev": true + }, + "@babel/helper-split-export-declaration": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0.tgz", + "integrity": "sha512-MXkOJqva62dfC0w85mEf/LucPPS/1+04nmmRMPEBUB++hiiThQ2zPtX/mEWQ3mtzCEjIJvPY8nuwxXtQeQwUag==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helpers": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.3.1.tgz", + "integrity": "sha512-Q82R3jKsVpUV99mgX50gOPCWwco9Ec5Iln/8Vyu4osNIOQgSrd9RFrQeUvmvddFNoLwMyOUWU+5ckioEKpDoGA==", + "dev": true, + "requires": { + "@babel/template": "^7.1.2", + "@babel/traverse": "^7.1.5", + "@babel/types": "^7.3.0" + } + }, + "@babel/highlight": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", + "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@babel/parser": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.3.4.tgz", + "integrity": "sha512-tXZCqWtlOOP4wgCp6RjRvLmfuhnqTLy9VHwRochJBCP2nDm27JnnuFEnXFASVyQNHk36jD1tAammsCEEqgscIQ==", + "dev": true + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz", + "integrity": "sha512-t0JKGgqk2We+9may3t0xDdmneaXmyxq0xieYcKHxIsrJO64n1OiMWNUtc5gQK1PA0NpdCRrtZp4z+IUaKugrSA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/runtime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.0.0.tgz", + "integrity": "sha512-7hGhzlcmg01CvH1EHdSPVXYX1aJ8KCEyz6I9xYIi/asDtzBPMyMhVibhM/K6g/5qnKBwjZtp10bNZIEFTRW1MA==", + "dev": true, + "requires": { + "regenerator-runtime": "^0.12.0" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz", + "integrity": "sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==", + "dev": true + } + } + }, + "@babel/template": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.2.2.tgz", + "integrity": "sha512-zRL0IMM02AUDwghf5LMSSDEz7sBCO2YnNmpg3uWTZj/v1rcG2BmQUvaGU8GhU8BvfMh1k2KIAYZ7Ji9KXPUg7g==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.2.2", + "@babel/types": "^7.2.2" + } + }, + "@babel/traverse": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.3.4.tgz", + "integrity": "sha512-TvTHKp6471OYEcE/91uWmhR6PrrYywQntCHSaZ8CM8Vmp+pjAusal4nGB2WCCQd0rvI7nOMKn9GnbcvTUz3/ZQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/generator": "^7.3.4", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.0.0", + "@babel/parser": "^7.3.4", + "@babel/types": "^7.3.4", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.11" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + } + } + }, + "@babel/types": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", + "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.11", + "to-fast-properties": "^2.0.0" + } + }, + "@cnakazawa/watch": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.3.tgz", + "integrity": "sha512-r5160ogAvGyHsal38Kux7YYtodEKOj89RGb28ht1jh3SJb08VwRwAKKJL0bGb04Zd/3r9FL3BFIc3bBidYffCA==", + "dev": true, + "requires": { + "exec-sh": "^0.3.2", + "minimist": "^1.2.0" + } + }, + "@fortawesome/angular-fontawesome": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@fortawesome/angular-fontawesome/-/angular-fontawesome-0.3.0.tgz", + "integrity": "sha512-wXvyPI7GidoNiqeMz2re9iemUMFH4zBmuv94CfXlaanQ8+kMP/fYs/k69PLVN1KsebQY4kRA9GHmc1U1ndBkJg==", + "requires": { + "tslib": "^1.9.0" + } + }, + "@fortawesome/fontawesome-common-types": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.15.tgz", + "integrity": "sha512-ATBRyKJw1d2ko+0DWN9+BXau0EK3I/Q6pPzPv3LhJD7r052YFAkAdfb1Bd7ZqhBsJrdse/S7jKxWUOZ61qBD4g==" + }, + "@fortawesome/fontawesome-svg-core": { + "version": "1.2.14", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.14.tgz", + "integrity": "sha512-T1qCqkwm9PuvK53J64D1ovfrOTa1kG+SrHNj5cFst/rrskhCnbxpRdbqFIdc/thmXC0ebBX8nOUyja2/mrxe4g==", + "requires": { + "@fortawesome/fontawesome-common-types": "^0.2.14" + } + }, + "@fortawesome/free-solid-svg-icons": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.7.1.tgz", + "integrity": "sha512-5V/Q+JoPzuiIHW2JwmZGvE9bHguvNJKa7611DPo51uIvYv9LweX/SnDF+HC23X2W5T3myHhnGi+EZJTmidAmyg==", + "requires": { + "@fortawesome/fontawesome-common-types": "^0.2.14" + } + }, + "@iamstarkov/listr-update-renderer": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@iamstarkov/listr-update-renderer/-/listr-update-renderer-0.4.1.tgz", + "integrity": "sha512-IJyxQWsYDEkf8C8QthBn5N8tIUR9V9je6j3sMIpAkonaadjbvxmRC6RAhpa3RKxndhNnU2M6iNbtJwd7usQYIA==", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "cli-truncate": "^0.2.1", + "elegant-spinner": "^1.0.1", + "figures": "^1.7.0", + "indent-string": "^3.0.0", + "log-symbols": "^1.0.2", + "log-update": "^2.3.0", + "strip-ansi": "^3.0.1" + }, + "dependencies": { + "figures": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5", + "object-assign": "^4.1.0" + } + }, + "log-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", + "integrity": "sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg=", + "dev": true, + "requires": { + "chalk": "^1.0.0" + } + } + } + }, + "@jest/console": { + "version": "24.3.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.3.0.tgz", + "integrity": "sha512-NaCty/OOei6rSDcbPdMiCbYCI0KGFGPgGO6B09lwWt5QTxnkuhKYET9El5u5z1GAcSxkQmSMtM63e24YabCWqA==", + "dev": true, + "requires": { + "@jest/source-map": "^24.3.0", + "@types/node": "*", + "chalk": "^2.0.1", + "slash": "^2.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@jest/core": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-24.5.0.tgz", + "integrity": "sha512-RDZArRzAs51YS7dXG1pbXbWGxK53rvUu8mCDYsgqqqQ6uSOaTjcVyBl2Jce0exT2rSLk38ca7az7t2f3b0/oYQ==", + "dev": true, + "requires": { + "@jest/console": "^24.3.0", + "@jest/reporters": "^24.5.0", + "@jest/test-result": "^24.5.0", + "@jest/transform": "^24.5.0", + "@jest/types": "^24.5.0", + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "graceful-fs": "^4.1.15", + "jest-changed-files": "^24.5.0", + "jest-config": "^24.5.0", + "jest-haste-map": "^24.5.0", + "jest-message-util": "^24.5.0", + "jest-regex-util": "^24.3.0", + "jest-resolve-dependencies": "^24.5.0", + "jest-runner": "^24.5.0", + "jest-runtime": "^24.5.0", + "jest-snapshot": "^24.5.0", + "jest-util": "^24.5.0", + "jest-validate": "^24.5.0", + "jest-watcher": "^24.5.0", + "micromatch": "^3.1.10", + "p-each-series": "^1.0.0", + "pirates": "^4.0.1", + "realpath-native": "^1.1.0", + "rimraf": "^2.5.4", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true + }, + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@jest/environment": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-24.5.0.tgz", + "integrity": "sha512-tzUHR9SHjMXwM8QmfHb/EJNbF0fjbH4ieefJBvtwO8YErLTrecc1ROj0uo2VnIT6SlpEGZnvdCK6VgKYBo8LsA==", + "dev": true, + "requires": { + "@jest/fake-timers": "^24.5.0", + "@jest/transform": "^24.5.0", + "@jest/types": "^24.5.0", + "@types/node": "*", + "jest-mock": "^24.5.0" + } + }, + "@jest/fake-timers": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-24.5.0.tgz", + "integrity": "sha512-i59KVt3QBz9d+4Qr4QxsKgsIg+NjfuCjSOWj3RQhjF5JNy+eVJDhANQ4WzulzNCHd72srMAykwtRn5NYDGVraw==", + "dev": true, + "requires": { + "@jest/types": "^24.5.0", + "@types/node": "*", + "jest-message-util": "^24.5.0", + "jest-mock": "^24.5.0" + } + }, + "@jest/reporters": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-24.5.0.tgz", + "integrity": "sha512-vfpceiaKtGgnuC3ss5czWOihKOUSyjJA4M4udm6nH8xgqsuQYcyDCi4nMMcBKsHXWgz9/V5G7iisnZGfOh1w6Q==", + "dev": true, + "requires": { + "@jest/environment": "^24.5.0", + "@jest/test-result": "^24.5.0", + "@jest/transform": "^24.5.0", + "@jest/types": "^24.5.0", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "glob": "^7.1.2", + "istanbul-api": "^2.1.1", + "istanbul-lib-coverage": "^2.0.2", + "istanbul-lib-instrument": "^3.0.1", + "istanbul-lib-source-maps": "^3.0.1", + "jest-haste-map": "^24.5.0", + "jest-resolve": "^24.5.0", + "jest-runtime": "^24.5.0", + "jest-util": "^24.5.0", + "jest-worker": "^24.4.0", + "node-notifier": "^5.2.1", + "slash": "^2.0.0", + "source-map": "^0.6.0", + "string-length": "^2.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@jest/source-map": { + "version": "24.3.0", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-24.3.0.tgz", + "integrity": "sha512-zALZt1t2ou8le/crCeeiRYzvdnTzaIlpOWaet45lNSqNJUnXbppUUFR4ZUAlzgDmKee4Q5P/tKXypI1RiHwgag==", + "dev": true, + "requires": { + "callsites": "^3.0.0", + "graceful-fs": "^4.1.15", + "source-map": "^0.6.0" + }, + "dependencies": { + "callsites": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.0.0.tgz", + "integrity": "sha512-tWnkwu9YEq2uzlBDI4RcLn8jrFvF9AOi8PxDNU3hZZjJcjkcRAq3vCI+vZcg1SuxISDYe86k9VZFwAxDiJGoAw==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "@jest/test-result": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-24.5.0.tgz", + "integrity": "sha512-u66j2vBfa8Bli1+o3rCaVnVYa9O8CAFZeqiqLVhnarXtreSXG33YQ6vNYBogT7+nYiFNOohTU21BKiHlgmxD5A==", + "dev": true, + "requires": { + "@jest/console": "^24.3.0", + "@jest/types": "^24.5.0", + "@types/istanbul-lib-coverage": "^1.1.0" + } + }, + "@jest/transform": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-24.5.0.tgz", + "integrity": "sha512-XSsDz1gdR/QMmB8UCKlweAReQsZrD/DK7FuDlNo/pE8EcKMrfi2kqLRk8h8Gy/PDzgqJj64jNEzOce9pR8oj1w==", + "dev": true, + "requires": { + "@babel/core": "^7.1.0", + "@jest/types": "^24.5.0", + "babel-plugin-istanbul": "^5.1.0", + "chalk": "^2.0.1", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.1.15", + "jest-haste-map": "^24.5.0", + "jest-regex-util": "^24.3.0", + "jest-util": "^24.5.0", + "micromatch": "^3.1.10", + "realpath-native": "^1.1.0", + "slash": "^2.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "2.4.1" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "write-file-atomic": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.1.tgz", + "integrity": "sha512-TGHFeZEZMnv+gBFRfjAcxL5bPHrsGKtnb4qsFAws7/vlh+QfwAaySIw4AXP9ZskTTh5GWu3FLuJhsWVdiJPGvg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + } + } + }, + "@jest/types": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.5.0.tgz", + "integrity": "sha512-kN7RFzNMf2R8UDadPOl6ReyI+MT8xfqRuAnuVL+i4gwjv/zubdDK+EDeLHYwq1j0CSSR2W/MmgaRlMZJzXdmVA==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^1.1.0", + "@types/yargs": "^12.0.9" + } + }, + "@mrmlnc/readdir-enhanced": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", + "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", + "dev": true, + "requires": { + "call-me-maybe": "^1.0.1", + "glob-to-regexp": "^0.3.0" + } + }, + "@ng-bootstrap/ng-bootstrap": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@ng-bootstrap/ng-bootstrap/-/ng-bootstrap-4.0.2.tgz", + "integrity": "sha512-SBsN8ORvj/WXpZGSyR2+CRkg6GCtax5+fsLKt9ImHKUVWwePVqRxiGlnxXqwNPHQ46vOdd7nDN9cwE7dfbGaAQ==", + "requires": { + "tslib": "^1.9.0" + } + }, + "@ngtools/webpack": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-7.3.1.tgz", + "integrity": "sha512-EGQRjgDf5XP+Fm1MdZNRFiPd9e1vhl11BhjkwqkAsewic4eoz6fqXfj/Osz1hQy8xU+2dPPf/byQ/+nY3E02Zg==", + "dev": true, + "requires": { + "@angular-devkit/core": "7.3.1", + "enhanced-resolve": "4.1.0", + "rxjs": "6.3.3", + "tree-kill": "1.2.1", + "webpack-sources": "1.3.0" + }, + "dependencies": { + "rxjs": { + "version": "6.3.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.3.3.tgz", + "integrity": "sha512-JTWmoY9tWCs7zvIk/CvRjhjGaOd+OVBM987mxFo+OW66cGpdKjZcpmc74ES1sB//7Kl/PAe8+wEakuhG4pcgOw==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + } + } + }, + "@ngx-translate/core": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/@ngx-translate/core/-/core-11.0.1.tgz", + "integrity": "sha512-nBCa1ZD9fAUY/3eskP3Lql2fNg8OMrYIej1/5GRsfcutx9tG/5fZLCv9m6UCw1aS+u4uK/vXjv1ctG/FdMvaWg==", + "requires": { + "tslib": "^1.9.0" + } + }, + "@ngx-translate/http-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@ngx-translate/http-loader/-/http-loader-4.0.0.tgz", + "integrity": "sha512-x8LumqydWD7eX9yQTAVeoCM9gFUIGVTUjZqbxdAUavAA3qVnk9wCQux7iHLPXpydl8vyQmLoPQR+fFU+DUDOMA==", + "requires": { + "tslib": "^1.9.0" + } + }, + "@nodelib/fs.stat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", + "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", + "dev": true + }, + "@samverschueren/stream-to-observable": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.0.tgz", + "integrity": "sha512-MI4Xx6LHs4Webyvi6EbspgyAb4D2Q2VtnCQ1blOJcoLS6mVa8lNN2rkIy1CVxfTUpoyIbCTkXES1rLXztFD1lg==", + "dev": true, + "requires": { + "any-observable": "^0.3.0" + } + }, + "@schematics/angular": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-7.3.1.tgz", + "integrity": "sha512-0Ne8APPlTAjKg5CSZqluwCuW/5yPjr3ALCWzqwPxN0suE745usThtasBmqrjw0RMIt8nRqRgtg54Z7lCPO9ZFg==", + "dev": true, + "requires": { + "@angular-devkit/core": "7.3.1", + "@angular-devkit/schematics": "7.3.1", + "typescript": "3.2.4" + } + }, + "@schematics/update": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/@schematics/update/-/update-0.13.1.tgz", + "integrity": "sha512-EHOqolT/d/jRGuVTCUESLpk8JNpuaPlsVHfeK7Kdp/t0wSEnmtOelZX4+leS25lGXDaDUF3138ntjrZR4n6bGw==", + "dev": true, + "requires": { + "@angular-devkit/core": "7.3.1", + "@angular-devkit/schematics": "7.3.1", + "@yarnpkg/lockfile": "1.1.0", + "ini": "1.3.5", + "pacote": "9.4.0", + "rxjs": "6.3.3", + "semver": "5.6.0", + "semver-intersect": "1.4.0" + }, + "dependencies": { + "rxjs": { + "version": "6.3.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.3.3.tgz", + "integrity": "sha512-JTWmoY9tWCs7zvIk/CvRjhjGaOd+OVBM987mxFo+OW66cGpdKjZcpmc74ES1sB//7Kl/PAe8+wEakuhG4pcgOw==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + } + } + }, + "@types/babel__core": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.0.tgz", + "integrity": "sha512-wJTeJRt7BToFx3USrCDs2BhEi4ijBInTQjOIukj6a/5tEkwpFMVZ+1ppgmE+Q/FQyc5P/VWUbx7I9NELrKruHA==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "@types/babel__generator": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.0.2.tgz", + "integrity": "sha512-NHcOfab3Zw4q5sEE2COkpfXjoE7o+PmqD9DQW4koUT3roNxwziUdXGnRndMat/LJNUtePwn1TlP4do3uoe3KZQ==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@types/babel__template": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.0.2.tgz", + "integrity": "sha512-/K6zCpeW7Imzgab2bLkLEbz0+1JlFSrUMdw7KoIIu+IUdu51GWaBZpd3y1VXGVXzynvGa4DaIaxNZHiON3GXUg==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@types/babel__traverse": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.6.tgz", + "integrity": "sha512-XYVgHF2sQ0YblLRMLNPB3CkFMewzFmlDsH/TneZFHUXDlABQgh88uOxuez7ZcXxayLFrqLwtDH1t+FmlFwNZxw==", + "dev": true, + "requires": { + "@babel/types": "^7.3.0" + } + }, + "@types/istanbul-lib-coverage": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-1.1.0.tgz", + "integrity": "sha512-ohkhb9LehJy+PA40rDtGAji61NCgdtKLAlFoYp4cnuuQEswwdK3vz9SOIkkyc3wrk8dzjphQApNs56yyXLStaQ==", + "dev": true + }, + "@types/jest": { + "version": "24.0.0", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-24.0.0.tgz", + "integrity": "sha512-kOafJnUTnMd7/OfEO/x3I47EHswNjn+dbz9qk3mtonr1RvKT+1FGVxnxAx08I9K8Tl7j9hpoJRE7OCf+t10fng==", + "dev": true + }, + "@types/node": { + "version": "10.12.24", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.24.tgz", + "integrity": "sha512-GWWbvt+z9G5otRBW8rssOFgRY87J9N/qbhqfjMZ+gUuL6zoL+Hm6gP/8qQBG4jjimqdaNLCehcVapZ/Fs2WjCQ==", + "dev": true + }, + "@types/q": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.2.tgz", + "integrity": "sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw==", + "dev": true + }, + "@types/stack-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz", + "integrity": "sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==", + "dev": true + }, + "@types/yargs": { + "version": "12.0.10", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-12.0.10.tgz", + "integrity": "sha512-WsVzTPshvCSbHThUduGGxbmnwcpkgSctHGHTqzWyFg4lYAuV5qXlyFPOsP3OWqCINfmg/8VXP+zJaa4OxEsBQQ==", + "dev": true + }, + "@webassemblyjs/ast": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.7.11.tgz", + "integrity": "sha512-ZEzy4vjvTzScC+SH8RBssQUawpaInUdMTYwYYLh54/s8TuT0gBLuyUnppKsVyZEi876VmmStKsUs28UxPgdvrA==", + "dev": true, + "requires": { + "@webassemblyjs/helper-module-context": "1.7.11", + "@webassemblyjs/helper-wasm-bytecode": "1.7.11", + "@webassemblyjs/wast-parser": "1.7.11" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.7.11.tgz", + "integrity": "sha512-zY8dSNyYcgzNRNT666/zOoAyImshm3ycKdoLsyDw/Bwo6+/uktb7p4xyApuef1dwEBo/U/SYQzbGBvV+nru2Xg==", + "dev": true + }, + "@webassemblyjs/helper-api-error": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.7.11.tgz", + "integrity": "sha512-7r1qXLmiglC+wPNkGuXCvkmalyEstKVwcueZRP2GNC2PAvxbLYwLLPr14rcdJaE4UtHxQKfFkuDFuv91ipqvXg==", + "dev": true + }, + "@webassemblyjs/helper-buffer": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.7.11.tgz", + "integrity": "sha512-MynuervdylPPh3ix+mKZloTcL06P8tenNH3sx6s0qE8SLR6DdwnfgA7Hc9NSYeob2jrW5Vql6GVlsQzKQCa13w==", + "dev": true + }, + "@webassemblyjs/helper-code-frame": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.7.11.tgz", + "integrity": "sha512-T8ESC9KMXFTXA5urJcyor5cn6qWeZ4/zLPyWeEXZ03hj/x9weSokGNkVCdnhSabKGYWxElSdgJ+sFa9G/RdHNw==", + "dev": true, + "requires": { + "@webassemblyjs/wast-printer": "1.7.11" + } + }, + "@webassemblyjs/helper-fsm": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.7.11.tgz", + "integrity": "sha512-nsAQWNP1+8Z6tkzdYlXT0kxfa2Z1tRTARd8wYnc/e3Zv3VydVVnaeePgqUzFrpkGUyhUUxOl5ML7f1NuT+gC0A==", + "dev": true + }, + "@webassemblyjs/helper-module-context": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.7.11.tgz", + "integrity": "sha512-JxfD5DX8Ygq4PvXDucq0M+sbUFA7BJAv/GGl9ITovqE+idGX+J3QSzJYz+LwQmL7fC3Rs+utvWoJxDb6pmC0qg==", + "dev": true + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.7.11.tgz", + "integrity": "sha512-cMXeVS9rhoXsI9LLL4tJxBgVD/KMOKXuFqYb5oCJ/opScWpkCMEz9EJtkonaNcnLv2R3K5jIeS4TRj/drde1JQ==", + "dev": true + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.7.11.tgz", + "integrity": "sha512-8ZRY5iZbZdtNFE5UFunB8mmBEAbSI3guwbrsCl4fWdfRiAcvqQpeqd5KHhSWLL5wuxo53zcaGZDBU64qgn4I4Q==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.7.11", + "@webassemblyjs/helper-buffer": "1.7.11", + "@webassemblyjs/helper-wasm-bytecode": "1.7.11", + "@webassemblyjs/wasm-gen": "1.7.11" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.7.11.tgz", + "integrity": "sha512-Mmqx/cS68K1tSrvRLtaV/Lp3NZWzXtOHUW2IvDvl2sihAwJh4ACE0eL6A8FvMyDG9abes3saB6dMimLOs+HMoQ==", + "dev": true, + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.7.11.tgz", + "integrity": "sha512-vuGmgZjjp3zjcerQg+JA+tGOncOnJLWVkt8Aze5eWQLwTQGNgVLcyOTqgSCxWTR4J42ijHbBxnuRaL1Rv7XMdw==", + "dev": true, + "requires": { + "@xtuc/long": "4.2.1" + } + }, + "@webassemblyjs/utf8": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.7.11.tgz", + "integrity": "sha512-C6GFkc7aErQIAH+BMrIdVSmW+6HSe20wg57HEC1uqJP8E/xpMjXqQUxkQw07MhNDSDcGpxI9G5JSNOQCqJk4sA==", + "dev": true + }, + "@webassemblyjs/wasm-edit": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.7.11.tgz", + "integrity": "sha512-FUd97guNGsCZQgeTPKdgxJhBXkUbMTY6hFPf2Y4OedXd48H97J+sOY2Ltaq6WGVpIH8o/TGOVNiVz/SbpEMJGg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.7.11", + "@webassemblyjs/helper-buffer": "1.7.11", + "@webassemblyjs/helper-wasm-bytecode": "1.7.11", + "@webassemblyjs/helper-wasm-section": "1.7.11", + "@webassemblyjs/wasm-gen": "1.7.11", + "@webassemblyjs/wasm-opt": "1.7.11", + "@webassemblyjs/wasm-parser": "1.7.11", + "@webassemblyjs/wast-printer": "1.7.11" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.7.11.tgz", + "integrity": "sha512-U/KDYp7fgAZX5KPfq4NOupK/BmhDc5Kjy2GIqstMhvvdJRcER/kUsMThpWeRP8BMn4LXaKhSTggIJPOeYHwISA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.7.11", + "@webassemblyjs/helper-wasm-bytecode": "1.7.11", + "@webassemblyjs/ieee754": "1.7.11", + "@webassemblyjs/leb128": "1.7.11", + "@webassemblyjs/utf8": "1.7.11" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.7.11.tgz", + "integrity": "sha512-XynkOwQyiRidh0GLua7SkeHvAPXQV/RxsUeERILmAInZegApOUAIJfRuPYe2F7RcjOC9tW3Cb9juPvAC/sCqvg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.7.11", + "@webassemblyjs/helper-buffer": "1.7.11", + "@webassemblyjs/wasm-gen": "1.7.11", + "@webassemblyjs/wasm-parser": "1.7.11" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.7.11.tgz", + "integrity": "sha512-6lmXRTrrZjYD8Ng8xRyvyXQJYUQKYSXhJqXOBLw24rdiXsHAOlvw5PhesjdcaMadU/pyPQOJ5dHreMjBxwnQKg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.7.11", + "@webassemblyjs/helper-api-error": "1.7.11", + "@webassemblyjs/helper-wasm-bytecode": "1.7.11", + "@webassemblyjs/ieee754": "1.7.11", + "@webassemblyjs/leb128": "1.7.11", + "@webassemblyjs/utf8": "1.7.11" + } + }, + "@webassemblyjs/wast-parser": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.7.11.tgz", + "integrity": "sha512-lEyVCg2np15tS+dm7+JJTNhNWq9yTZvi3qEhAIIOaofcYlUp0UR5/tVqOwa/gXYr3gjwSZqw+/lS9dscyLelbQ==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.7.11", + "@webassemblyjs/floating-point-hex-parser": "1.7.11", + "@webassemblyjs/helper-api-error": "1.7.11", + "@webassemblyjs/helper-code-frame": "1.7.11", + "@webassemblyjs/helper-fsm": "1.7.11", + "@xtuc/long": "4.2.1" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.7.11.tgz", + "integrity": "sha512-m5vkAsuJ32QpkdkDOUPGSltrg8Cuk3KBx4YrmAGQwCZPRdUHXxG4phIOuuycLemHFr74sWL9Wthqss4fzdzSwg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.7.11", + "@webassemblyjs/wast-parser": "1.7.11", + "@xtuc/long": "4.2.1" + } + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "@xtuc/long": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.1.tgz", + "integrity": "sha512-FZdkNBDqBRHKQ2MEbSC17xnPFOhZxeJ2YGSfr2BKf3sujG49Qe3bB+rGCwQfIaA7WHnGeGkSijX4FuBCdrzW/g==", + "dev": true + }, + "@yarnpkg/lockfile": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", + "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", + "dev": true + }, + "JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "dev": true, + "requires": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + } + }, + "abab": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.0.tgz", + "integrity": "sha512-sY5AXXVZv4Y1VACTtR11UJCPHHudgY5i26Qj5TypE6DKlIApbwb5uqhXcJ5UUGbvZNRh7EeIoW+LrJumBsKp7w==", + "dev": true + }, + "accepts": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", + "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", + "dev": true, + "requires": { + "mime-types": "~2.1.18", + "negotiator": "0.6.1" + } + }, + "acorn": { + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", + "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", + "dev": true + }, + "acorn-dynamic-import": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-4.0.0.tgz", + "integrity": "sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw==", + "dev": true + }, + "acorn-globals": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.0.tgz", + "integrity": "sha512-hMtHj3s5RnuhvHPowpBYvJVj3rAar82JiDQHvGs1zO0l10ocX/xEdBShNHTJaboucJUsScghp74pH3s7EnHHQw==", + "dev": true, + "requires": { + "acorn": "^6.0.1", + "acorn-walk": "^6.0.1" + }, + "dependencies": { + "acorn": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.1.1.tgz", + "integrity": "sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA==", + "dev": true + } + } + }, + "acorn-walk": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.1.1.tgz", + "integrity": "sha512-OtUw6JUTgxA2QoqqmrmQ7F2NYqiBPi/L2jqHyFtllhOUvXYQXf0Z1CYUinIfyT4bTCGmrA7gX9FvHA81uzCoVw==", + "dev": true + }, + "after": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", + "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=", + "dev": true + }, + "agent-base": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz", + "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==", + "dev": true, + "requires": { + "es6-promisify": "^5.0.0" + } + }, + "agentkeepalive": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-3.5.2.tgz", + "integrity": "sha512-e0L/HNe6qkQ7H19kTlRRqUibEAwDK5AFk6y3PtMsuut2VAH6+Q4xZml1tNDJD7kSAyqmbG/K08K5WEJYtUrSlQ==", + "dev": true, + "requires": { + "humanize-ms": "^1.2.1" + } + }, + "ajv": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.7.0.tgz", + "integrity": "sha512-RZXPviBTtfmtka9n9sy1N5M5b82CbxWIR6HIis4s3WQTXDJamc/0gpCWNGz6EWdWp4DOfjzJfhz/AS9zVPjjWg==", + "dev": true, + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-errors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", + "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", + "dev": true + }, + "ajv-keywords": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.0.tgz", + "integrity": "sha512-aUjdRFISbuFOl0EIZc+9e4FfZp0bDZgAdOOf30bJmw8VM9v84SHyVyxDfbWxpGYbdZD/9XoKxfHVNmxPkhwyGw==", + "dev": true + }, + "alphanum-sort": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz", + "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=", + "dev": true + }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", + "dev": true + }, + "angular-router-loader": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/angular-router-loader/-/angular-router-loader-0.8.5.tgz", + "integrity": "sha512-8wggCTKGgzB1o8co3Wvj+p9pKN7T7q3C477lEz3NLjvPVzUti8rv9i45Di+4aO/k+HvzGh3s8QdNlXU2Bl4avQ==", + "dev": true, + "requires": { + "loader-utils": "^1.0.2" + } + }, + "angular2-template-loader": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/angular2-template-loader/-/angular2-template-loader-0.6.2.tgz", + "integrity": "sha1-wNROkP/w+sleiyPwQ6zaf9HFHXw=", + "dev": true, + "requires": { + "loader-utils": "^0.2.15" + }, + "dependencies": { + "big.js": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", + "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==", + "dev": true + }, + "json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "dev": true + }, + "loader-utils": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz", + "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=", + "dev": true, + "requires": { + "big.js": "^3.1.3", + "emojis-list": "^2.0.0", + "json5": "^0.5.0", + "object-assign": "^4.0.1" + } + } + } + }, + "ansi": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/ansi/-/ansi-0.3.1.tgz", + "integrity": "sha1-DELU+xcWDVqa8eSEus4cZpIsGyE=", + "dev": true + }, + "ansi-colors": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", + "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==", + "dev": true + }, + "ansi-cyan": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-cyan/-/ansi-cyan-0.1.1.tgz", + "integrity": "sha1-U4rlKK+JgvKK4w2G8vF0VtJgmHM=", + "dev": true, + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-escapes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", + "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=" + }, + "ansi-html": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz", + "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=", + "dev": true + }, + "ansi-red": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-red/-/ansi-red-0.1.1.tgz", + "integrity": "sha1-jGOPnRCAgAo1PJwoyKgcpHBdlGw=", + "dev": true, + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "ansi-wrap": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", + "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=", + "dev": true + }, + "any-observable": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/any-observable/-/any-observable-0.3.0.tgz", + "integrity": "sha512-/FQM1EDkTsf63Ub2C6O7GuYFDsSXUwsaZDurV0np41ocwq0jthUAYCmhBX9f+KwlaCgIuWyr/4WlUQUBfKfZog==", + "dev": true + }, + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + } + }, + "app-root-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-2.1.0.tgz", + "integrity": "sha1-mL9lmTJ+zqGZMJhm6BQDaP0uZGo=", + "dev": true + }, + "append-transform": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-1.0.0.tgz", + "integrity": "sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw==", + "dev": true, + "requires": { + "default-require-extensions": "^2.0.0" + } + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "dev": true + }, + "are-we-there-yet": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "dev": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + }, + "dependencies": { + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + } + } + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true + }, + "array-differ": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz", + "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=", + "dev": true + }, + "array-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", + "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=", + "dev": true + }, + "array-find-index": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", + "dev": true + }, + "array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", + "dev": true + }, + "array-slice": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz", + "integrity": "sha1-3Tz7gO15c6dRF82sabC5nshhhvU=", + "dev": true + }, + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "requires": { + "array-uniq": "^1.0.1" + } + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "arraybuffer.slice": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", + "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==", + "dev": true + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", + "dev": true + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "dev": true, + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "asn1.js": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", + "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "assert": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz", + "integrity": "sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=", + "dev": true, + "requires": { + "util": "0.10.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", + "dev": true + }, + "util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "dev": true, + "requires": { + "inherits": "2.0.1" + } + } + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true + }, + "ast-types": { + "version": "0.9.6", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.9.6.tgz", + "integrity": "sha1-ECyenpAF0+fjgpvwxPok7oYu6bk=", + "dev": true + }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true + }, + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true + }, + "async-each": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.2.tgz", + "integrity": "sha512-6xrbvN0MOBKSJDdonmSSz2OwFSgxRaVtBDes26mj9KIGtDo+g9xosFRSC+i1gQh2oAN/tQ62AI/pGZGQjVOiRg==", + "dev": true + }, + "async-each-series": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/async-each-series/-/async-each-series-0.1.1.tgz", + "integrity": "sha1-dhfBkXQB/Yykooqtzj266Yr+tDI=", + "dev": true + }, + "async-limiter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", + "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true + }, + "autoprefixer": { + "version": "9.4.7", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.4.7.tgz", + "integrity": "sha512-qS5wW6aXHkm53Y4z73tFGsUhmZu4aMPV9iHXYlF0c/wxjknXNHuj/1cIQb+6YH692DbJGGWcckAXX+VxKvahMA==", + "dev": true, + "requires": { + "browserslist": "^4.4.1", + "caniuse-lite": "^1.0.30000932", + "normalize-range": "^0.1.2", + "num2fraction": "^1.2.2", + "postcss": "^7.0.14", + "postcss-value-parser": "^3.3.1" + } + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true + }, + "aws4": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", + "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", + "dev": true + }, + "axios": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.17.1.tgz", + "integrity": "sha1-LY4+XQvb1zJ/kbyBT1xXZg+Bgk0=", + "dev": true, + "requires": { + "follow-redirects": "^1.2.5", + "is-buffer": "^1.1.5" + } + }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" + } + }, + "babel-extract-comments": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/babel-extract-comments/-/babel-extract-comments-1.0.0.tgz", + "integrity": "sha512-qWWzi4TlddohA91bFwgt6zO/J0X+io7Qp184Fw0m2JYRSTZnJbFR8+07KmzudHCZgOiKRCrjhylwv9Xd8gfhVQ==", + "dev": true, + "requires": { + "babylon": "^6.18.0" + } + }, + "babel-jest": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-24.5.0.tgz", + "integrity": "sha512-0fKCXyRwxFTJL0UXDJiT2xYxO9Lu2vBd9n+cC+eDjESzcVG3s2DRGAxbzJX21fceB1WYoBjAh8pQ83dKcl003g==", + "dev": true, + "requires": { + "@jest/transform": "^24.5.0", + "@jest/types": "^24.5.0", + "@types/babel__core": "^7.1.0", + "babel-plugin-istanbul": "^5.1.0", + "babel-preset-jest": "^24.3.0", + "chalk": "^2.4.2", + "slash": "^2.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "babel-plugin-istanbul": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-5.1.1.tgz", + "integrity": "sha512-RNNVv2lsHAXJQsEJ5jonQwrJVWK8AcZpG1oxhnjCUaAjL7xahYLANhPUZbzEQHjKy1NMYUwn+0NPKQc8iSY4xQ==", + "dev": true, + "requires": { + "find-up": "^3.0.0", + "istanbul-lib-instrument": "^3.0.0", + "test-exclude": "^5.0.0" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", + "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.1.0.tgz", + "integrity": "sha512-H2RyIJ7+A3rjkwKC2l5GGtU4H1vkxKCAGsWasNVd0Set+6i4znxbWy6/j16YDPJDWxhsgZiKAstMEP8wCdSpjA==", + "dev": true + } + } + }, + "babel-plugin-jest-hoist": { + "version": "24.3.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-24.3.0.tgz", + "integrity": "sha512-nWh4N1mVH55Tzhx2isvUN5ebM5CDUvIpXPZYMRazQughie/EqGnbR+czzoQlhUmJG9pPJmYDRhvocotb2THl1w==", + "dev": true, + "requires": { + "@types/babel__traverse": "^7.0.6" + } + }, + "babel-plugin-syntax-object-rest-spread": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz", + "integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=", + "dev": true + }, + "babel-plugin-transform-object-rest-spread": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz", + "integrity": "sha1-DzZpLVD+9rfi1LOsFHgTepY7ewY=", + "dev": true, + "requires": { + "babel-plugin-syntax-object-rest-spread": "^6.8.0", + "babel-runtime": "^6.26.0" + } + }, + "babel-polyfill": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.23.0.tgz", + "integrity": "sha1-g2TKYt+Or7gwSZ9pkXdGbDsDSZ0=", + "requires": { + "babel-runtime": "^6.22.0", + "core-js": "^2.4.0", + "regenerator-runtime": "^0.10.0" + } + }, + "babel-preset-jest": { + "version": "24.3.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-24.3.0.tgz", + "integrity": "sha512-VGTV2QYBa/Kn3WCOKdfS31j9qomaXSgJqi65B6o05/1GsJyj9LVhSljM9ro4S+IBGj/ENhNBuH9bpqzztKAQSw==", + "dev": true, + "requires": { + "@babel/plugin-syntax-object-rest-spread": "^7.0.0", + "babel-plugin-jest-hoist": "^24.3.0" + } + }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "requires": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" + } + } + }, + "babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", + "dev": true + }, + "backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "base62": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/base62/-/base62-1.2.8.tgz", + "integrity": "sha512-V6YHUbjLxN1ymqNLb1DPHoU1CpfdL7d2YTIp5W3U4hhoG4hhxNmsFDs66M9EXxBiSEke5Bt5dwdfMwwZF70iLA==", + "dev": true + }, + "base64-arraybuffer": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", + "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=", + "dev": true + }, + "base64-js": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", + "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==", + "dev": true + }, + "base64id": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz", + "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=", + "dev": true + }, + "batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dev": true, + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "better-assert": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", + "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", + "dev": true, + "requires": { + "callsite": "1.0.0" + } + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true + }, + "binary-extensions": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.0.tgz", + "integrity": "sha512-EgmjVLMn22z7eGGv3kcnHwSnJXmFHjISTY9E/S5lIcTD3Oxw05QTcBLNkJFzcb3cNueUdF/IN4U+d78V0zO8Hw==", + "dev": true + }, + "binaryextensions": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-2.1.2.tgz", + "integrity": "sha512-xVNN69YGDghOqCCtA6FI7avYrr02mTJjOgB0/f1VPD3pJC8QEvjTKWc4epDx8AqxxA75NI0QpVM2gPJXUbE4Tg==", + "dev": true + }, + "blob": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", + "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==", + "dev": true + }, + "bluebird": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.3.tgz", + "integrity": "sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw==", + "dev": true + }, + "bn.js": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", + "dev": true + }, + "body-parser": { + "version": "1.18.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", + "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", + "dev": true, + "requires": { + "bytes": "3.0.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "~1.6.3", + "iconv-lite": "0.4.23", + "on-finished": "~2.3.0", + "qs": "6.5.2", + "raw-body": "2.3.3", + "type-is": "~1.6.16" + }, + "dependencies": { + "iconv-lite": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", + "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true + } + } + }, + "bonjour": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", + "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", + "dev": true, + "requires": { + "array-flatten": "^2.1.0", + "deep-equal": "^1.0.1", + "dns-equal": "^1.0.0", + "dns-txt": "^2.0.2", + "multicast-dns": "^6.0.1", + "multicast-dns-service-types": "^1.1.0" + } + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", + "dev": true + }, + "bootstrap": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.2.1.tgz", + "integrity": "sha512-tt/7vIv3Gm2mnd/WeDx36nfGGHleil0Wg8IeB7eMrVkY0fZ5iTaBisSh8oNANc2IBsCc6vCgCNTIM/IEN0+50Q==" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", + "dev": true + }, + "browser-process-hrtime": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-0.1.3.tgz", + "integrity": "sha512-bRFnI4NnjO6cnyLmOV/7PVoDEMJChlcfN0z4s1YMBY989/SvlfMI1lgCnkFUs53e9gQF+w7qu7XdllSTiSl8Aw==", + "dev": true + }, + "browser-resolve": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz", + "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==", + "dev": true, + "requires": { + "resolve": "1.1.7" + }, + "dependencies": { + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", + "dev": true + } + } + }, + "browser-sync": { + "version": "2.26.3", + "resolved": "https://registry.npmjs.org/browser-sync/-/browser-sync-2.26.3.tgz", + "integrity": "sha512-VLzpjCA4uXqfzkwqWtMM6hvPm2PNHp2RcmzBXcbi6C9WpkUhhFb8SVAr4CFrCsFxDg+oY6HalOjn8F+egyvhag==", + "dev": true, + "requires": { + "browser-sync-client": "^2.26.2", + "browser-sync-ui": "^2.26.2", + "bs-recipes": "1.3.4", + "bs-snippet-injector": "^2.0.1", + "chokidar": "^2.0.4", + "connect": "3.6.6", + "connect-history-api-fallback": "^1", + "dev-ip": "^1.0.1", + "easy-extender": "^2.3.4", + "eazy-logger": "^3", + "etag": "^1.8.1", + "fresh": "^0.5.2", + "fs-extra": "3.0.1", + "http-proxy": "1.15.2", + "immutable": "^3", + "localtunnel": "1.9.1", + "micromatch": "2.3.11", + "opn": "5.3.0", + "portscanner": "2.1.1", + "qs": "6.2.3", + "raw-body": "^2.3.2", + "resp-modifier": "6.0.2", + "rx": "4.1.0", + "send": "0.16.2", + "serve-index": "1.9.1", + "serve-static": "1.13.2", + "server-destroy": "1.0.1", + "socket.io": "2.1.1", + "ua-parser-js": "0.7.17", + "yargs": "6.4.0" + }, + "dependencies": { + "arr-diff": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", + "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", + "dev": true, + "requires": { + "arr-flatten": "^1.0.1" + } + }, + "array-unique": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", + "dev": true + }, + "braces": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", + "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", + "dev": true, + "requires": { + "expand-range": "^1.8.1", + "preserve": "^0.2.0", + "repeat-element": "^1.1.2" + } + }, + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "dev": true + }, + "expand-brackets": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", + "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", + "dev": true, + "requires": { + "is-posix-bracket": "^0.1.0" + } + }, + "extglob": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", + "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", + "dev": true, + "requires": { + "is-extglob": "^1.0.0" + } + }, + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "requires": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "dev": true, + "requires": { + "is-extglob": "^1.0.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + }, + "load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + } + }, + "micromatch": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", + "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", + "dev": true, + "requires": { + "arr-diff": "^2.0.0", + "array-unique": "^0.2.1", + "braces": "^1.8.2", + "expand-brackets": "^0.1.4", + "extglob": "^0.3.1", + "filename-regex": "^2.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.1", + "kind-of": "^3.0.2", + "normalize-path": "^2.0.1", + "object.omit": "^2.0.0", + "parse-glob": "^3.0.4", + "regex-cache": "^0.4.2" + } + }, + "opn": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/opn/-/opn-5.3.0.tgz", + "integrity": "sha512-bYJHo/LOmoTd+pfiYhfZDnf9zekVJrY+cnS2a5F2x+w5ppvTqObojTP7WiFG+kVZs9Inw+qQ/lw7TroWwhdd2g==", + "dev": true, + "requires": { + "is-wsl": "^1.1.0" + } + }, + "os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "dev": true, + "requires": { + "lcid": "^1.0.0" + } + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "requires": { + "pinkie-promise": "^2.0.0" + } + }, + "path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "dev": true, + "requires": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "dev": true, + "requires": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true, + "requires": { + "is-utf8": "^0.2.0" + } + }, + "which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=", + "dev": true + }, + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", + "dev": true + }, + "yargs": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-6.4.0.tgz", + "integrity": "sha1-gW4ahm1VmMzzTlWW3c4i2S2kkNQ=", + "dev": true, + "requires": { + "camelcase": "^3.0.0", + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "os-locale": "^1.4.0", + "read-pkg-up": "^1.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^1.0.2", + "which-module": "^1.0.0", + "window-size": "^0.2.0", + "y18n": "^3.2.1", + "yargs-parser": "^4.1.0" + } + }, + "yargs-parser": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-4.2.1.tgz", + "integrity": "sha1-KczqwNxPA8bIe0qfIX3RjJ90hxw=", + "dev": true, + "requires": { + "camelcase": "^3.0.0" + } + } + } + }, + "browser-sync-client": { + "version": "2.26.2", + "resolved": "https://registry.npmjs.org/browser-sync-client/-/browser-sync-client-2.26.2.tgz", + "integrity": "sha512-FEuVJD41fI24HJ30XOT2RyF5WcnEtdJhhTqeyDlnMk/8Ox9MZw109rvk9pdfRWye4soZLe+xcAo9tHSMxvgAdw==", + "dev": true, + "requires": { + "etag": "1.8.1", + "fresh": "0.5.2", + "mitt": "^1.1.3", + "rxjs": "^5.5.6" + }, + "dependencies": { + "rxjs": { + "version": "5.5.12", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.12.tgz", + "integrity": "sha512-xx2itnL5sBbqeeiVgNPVuQQ1nC8Jp2WfNJhXWHmElW9YmrpS9UVnNzhP3EH3HFqexO5Tlp8GhYY+WEcqcVMvGw==", + "dev": true, + "requires": { + "symbol-observable": "1.0.1" + } + }, + "symbol-observable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.1.tgz", + "integrity": "sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ=", + "dev": true + } + } + }, + "browser-sync-ui": { + "version": "2.26.2", + "resolved": "https://registry.npmjs.org/browser-sync-ui/-/browser-sync-ui-2.26.2.tgz", + "integrity": "sha512-LF7GMWo8ELOE0eAlxuRCfnGQT1ZxKP9flCfGgZdXFc6BwmoqaJHlYe7MmVvykKkXjolRXTz8ztXAKGVqNwJ3EQ==", + "dev": true, + "requires": { + "async-each-series": "0.1.1", + "connect-history-api-fallback": "^1", + "immutable": "^3", + "server-destroy": "1.0.1", + "socket.io-client": "^2.0.4", + "stream-throttle": "^0.1.3" + } + }, + "browser-sync-webpack-plugin": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/browser-sync-webpack-plugin/-/browser-sync-webpack-plugin-2.2.2.tgz", + "integrity": "sha512-x92kl8LdBi4dp6YVXYqrSoDkOCOLCeBOrYSY0h9Sk1VcCDSoZC1Vc62eae6TfC2ljN4/L+aYlkzE46kirHzbgA==", + "dev": true, + "requires": { + "lodash": "^4" + } + }, + "browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dev": true, + "requires": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "dev": true, + "requires": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "browserify-rsa": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", + "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "randombytes": "^2.0.1" + } + }, + "browserify-sign": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", + "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", + "dev": true, + "requires": { + "bn.js": "^4.1.1", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.2", + "elliptic": "^6.0.0", + "inherits": "^2.0.1", + "parse-asn1": "^5.0.0" + } + }, + "browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "dev": true, + "requires": { + "pako": "~1.0.5" + } + }, + "browserslist": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.5.1.tgz", + "integrity": "sha512-/pPw5IAUyqaQXGuD5vS8tcbudyPZ241jk1W5pQBsGDfcjNQt7p8qxZhgMNuygDShte1PibLFexecWUPgmVLfrg==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30000949", + "electron-to-chromium": "^1.3.116", + "node-releases": "^1.1.11" + } + }, + "bs-recipes": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/bs-recipes/-/bs-recipes-1.3.4.tgz", + "integrity": "sha1-DS1NSKcYyMBEdp/cT4lZLci2lYU=", + "dev": true + }, + "bs-snippet-injector": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/bs-snippet-injector/-/bs-snippet-injector-2.0.1.tgz", + "integrity": "sha1-YbU5PxH1JVntEgaTEANDtu2wTdU=", + "dev": true + }, + "bser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.0.0.tgz", + "integrity": "sha1-mseNPtXZFYBP2HrLFYvHlxR6Fxk=", + "dev": true, + "requires": { + "node-int64": "^0.4.0" + } + }, + "buffer": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", + "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", + "dev": true, + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "buffer-alloc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", + "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", + "dev": true, + "requires": { + "buffer-alloc-unsafe": "^1.1.0", + "buffer-fill": "^1.0.0" + } + }, + "buffer-alloc-unsafe": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", + "dev": true + }, + "buffer-fill": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", + "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=", + "dev": true + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "buffer-indexof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz", + "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==", + "dev": true + }, + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", + "dev": true + }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true + }, + "builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", + "dev": true + }, + "builtins": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz", + "integrity": "sha1-y5T662HIaWRR2zZTThQi+U8K7og=", + "dev": true + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", + "dev": true + }, + "cacache": { + "version": "11.3.2", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.2.tgz", + "integrity": "sha512-E0zP4EPGDOaT2chM08Als91eYnf8Z+eH1awwwVsngUmgppfM5jjJ8l3z5vO5p5w/I3LsiXawb1sW0VY65pQABg==", + "dev": true, + "requires": { + "bluebird": "^3.5.3", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.3", + "graceful-fs": "^4.1.15", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.2", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", + "y18n": "^4.0.0" + } + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, + "cache-loader": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/cache-loader/-/cache-loader-2.0.1.tgz", + "integrity": "sha512-V99T3FOynmGx26Zom+JrVBytLBsmUCzVG2/4NnUKgvXN4bEV42R1ERl1IyiH/cvFIDA1Ytq2lPZ9tXDSahcQpQ==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0", + "mkdirp": "^0.5.1", + "neo-async": "^2.6.0", + "normalize-path": "^3.0.0", + "schema-utils": "^1.0.0" + }, + "dependencies": { + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + } + } + }, + "call-me-maybe": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", + "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=", + "dev": true + }, + "caller-callsite": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", + "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", + "dev": true, + "requires": { + "callsites": "^2.0.0" + } + }, + "caller-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", + "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", + "dev": true, + "requires": { + "caller-callsite": "^2.0.0" + } + }, + "callsite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", + "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=", + "dev": true + }, + "callsites": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", + "dev": true + }, + "camel-case": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", + "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=", + "dev": true, + "requires": { + "no-case": "^2.2.0", + "upper-case": "^1.1.1" + } + }, + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + }, + "camelcase-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-4.2.0.tgz", + "integrity": "sha1-oqpfsa9oh1glnDLBQUJteJI7m3c=", + "dev": true, + "requires": { + "camelcase": "^4.1.0", + "map-obj": "^2.0.0", + "quick-lru": "^1.0.0" + } + }, + "caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, + "caniuse-lite": { + "version": "1.0.30000950", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000950.tgz", + "integrity": "sha512-Cs+4U9T0okW2ftBsCIHuEYXXkki7mjXmjCh4c6PzYShk04qDEr76/iC7KwhLoWoY65wcra1XOsRD+S7BptEb5A==", + "dev": true + }, + "canonical-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/canonical-path/-/canonical-path-1.0.0.tgz", + "integrity": "sha512-feylzsbDxi1gPZ1IjystzIQZagYYLvfKrSuygUCgf7z6x790VEzze5QEkdSV1U58RA7Hi0+v6fv4K54atOzATg==", + "dev": true + }, + "capture-exit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz", + "integrity": "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==", + "dev": true, + "requires": { + "rsvp": "^4.8.4" + } + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "chardet": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", + "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=" + }, + "chevrotain": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-4.2.0.tgz", + "integrity": "sha512-uiwhNpkudwrk3rHxKKfrvsWNe4SBDjnswbF2FDqDfrqsfYr4gY0Yl1k2m9yPKR0fqfbiIP67EbgOv4e+JP+GGg==", + "dev": true, + "requires": { + "regexp-to-ast": "0.3.5" + } + }, + "chokidar": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.4.tgz", + "integrity": "sha512-z9n7yt9rOvIJrMhvDtDictKrkFHeihkNl6uWMmZlmL6tJtX9Cs+87oK+teBx+JIgzvbX3yZHT3eF8vpbDxHJXQ==", + "dev": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.0", + "braces": "^2.3.0", + "fsevents": "^1.2.2", + "glob-parent": "^3.1.0", + "inherits": "^2.0.1", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "lodash.debounce": "^4.0.8", + "normalize-path": "^2.1.1", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.0.0", + "upath": "^1.0.5" + } + }, + "chownr": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz", + "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==", + "dev": true + }, + "chrome-trace-event": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.0.tgz", + "integrity": "sha512-xDbVgyfDTT2piup/h8dK/y4QZfJRSa73bw1WZ8b4XM1o7fsFubUVGYcE+1ANtOzJJELGpYoG2961z0Z6OAld9A==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "clean-css": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.1.tgz", + "integrity": "sha512-4ZxI6dy4lrY6FHzfiy1aEOXgu4LIsW2MhwG0VBKdcoGoH/XLFgaHSdLTGr4O8Be6A8r3MOphEiI8Gc1n0ecf3g==", + "dev": true, + "requires": { + "source-map": "~0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "requires": { + "restore-cursor": "^2.0.0" + } + }, + "cli-table": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.1.tgz", + "integrity": "sha1-9TsFJmqLGguTSz0IIebi3FkUriM=", + "dev": true, + "requires": { + "colors": "1.0.3" + }, + "dependencies": { + "colors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", + "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", + "dev": true + } + } + }, + "cli-truncate": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-0.2.1.tgz", + "integrity": "sha1-nxXPuwcFAFNpIWxiasfQWrkN1XQ=", + "dev": true, + "requires": { + "slice-ansi": "0.0.4", + "string-width": "^1.0.1" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + } + } + }, + "cli-width": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=" + }, + "cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + } + } + }, + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "dev": true + }, + "clone-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz", + "integrity": "sha1-4+JbIHrE5wGvch4staFnksrD3Fg=", + "dev": true + }, + "clone-deep": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-2.0.2.tgz", + "integrity": "sha512-SZegPTKjCgpQH63E+eN6mVEEPdQBOUzjyJm5Pora4lrwWRFS8I0QAxV/KD6vV/i0WuijHZWQC1fMsPEdxfdVCQ==", + "dev": true, + "requires": { + "for-own": "^1.0.0", + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.0", + "shallow-clone": "^1.0.0" + }, + "dependencies": { + "for-own": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", + "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", + "dev": true, + "requires": { + "for-in": "^1.0.1" + } + } + } + }, + "clone-stats": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", + "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=", + "dev": true + }, + "cloneable-readable": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.2.tgz", + "integrity": "sha512-Bq6+4t+lbM8vhTs/Bef5c5AdEMtapp/iFb6+s4/Hh9MVTt8OLKH7ZOOZSCT+Ys7hsHvqv0GuMPJ1lnQJVHvxpg==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "process-nextick-args": "^2.0.0", + "readable-stream": "^2.3.5" + } + }, + "closest-file-data": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/closest-file-data/-/closest-file-data-0.1.4.tgz", + "integrity": "sha1-l1+HwTLymdJKA3W59jyj+4j3Kzo=", + "dev": true + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, + "coa": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz", + "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==", + "dev": true, + "requires": { + "@types/q": "^1.5.1", + "chalk": "^2.4.1", + "q": "^1.1.2" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true + }, + "codelyzer": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/codelyzer/-/codelyzer-4.5.0.tgz", + "integrity": "sha512-oO6vCkjqsVrEsmh58oNlnJkRXuA30hF8cdNAQV9DytEalDwyOFRvHMnlKFzmOStNerOmPGZU9GAHnBo4tGvtiQ==", + "dev": true, + "requires": { + "app-root-path": "^2.1.0", + "css-selector-tokenizer": "^0.7.0", + "cssauron": "^1.4.0", + "semver-dsl": "^1.0.1", + "source-map": "^0.5.7", + "sprintf-js": "^1.1.1" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "color": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz", + "integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==", + "dev": true, + "requires": { + "color-convert": "^1.9.1", + "color-string": "^1.5.2" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "color-string": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.3.tgz", + "integrity": "sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==", + "dev": true, + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "colornames": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/colornames/-/colornames-1.1.1.tgz", + "integrity": "sha1-+IiQMGhcfE/54qVZ9Qd+t2qBb5Y=", + "dev": true + }, + "colors": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.3.3.tgz", + "integrity": "sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg==", + "dev": true + }, + "colorspace": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.1.tgz", + "integrity": "sha512-pI3btWyiuz7Ken0BWh9Elzsmv2bM9AhA7psXib4anUXy/orfZ/E0MbQwhSOG/9L8hLlalqrU0UhOuqxW1YjmVw==", + "dev": true, + "requires": { + "color": "3.0.x", + "text-hex": "1.0.x" + } + }, + "combined-stream": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", + "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz", + "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==", + "dev": true + }, + "common-tags": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.0.tgz", + "integrity": "sha512-6P6g0uetGpW/sdyUy/iQQCbFF0kWVMSIVSyYz7Zgjcgh8mgw8PQzDNZeyZ5DQ2gM7LBoZPHmnjz8rUthkBG5tw==", + "dev": true + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "commoner": { + "version": "0.10.8", + "resolved": "https://registry.npmjs.org/commoner/-/commoner-0.10.8.tgz", + "integrity": "sha1-NPw2cs0kOT6LtH5wyqApOBH08sU=", + "dev": true, + "requires": { + "commander": "^2.5.0", + "detective": "^4.3.1", + "glob": "^5.0.15", + "graceful-fs": "^4.1.2", + "iconv-lite": "^0.4.5", + "mkdirp": "^0.5.0", + "private": "^0.1.6", + "q": "^1.1.2", + "recast": "^0.11.17" + }, + "dependencies": { + "glob": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", + "dev": true, + "requires": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, + "compare-versions": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.4.0.tgz", + "integrity": "sha512-tK69D7oNXXqUW3ZNo/z7NXTEz22TCF0pTE+YF9cxvaAM9XnkLo1fV621xCLrRR6aevJlKxExkss0vWqUCUpqdg==", + "dev": true + }, + "component-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", + "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=", + "dev": true + }, + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true + }, + "component-inherit": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", + "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=", + "dev": true + }, + "compressible": { + "version": "2.0.16", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.16.tgz", + "integrity": "sha512-JQfEOdnI7dASwCuSPWIeVYwc/zMsu/+tRhoUvEfXz2gxOA2DNjmG5vhtFdBlhWPPGo+RdT9S3tgc/uH5qgDiiA==", + "dev": true, + "requires": { + "mime-db": ">= 1.38.0 < 2" + } + }, + "compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dev": true, + "requires": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "conf": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/conf/-/conf-2.0.0.tgz", + "integrity": "sha512-iCLzBsGFi8S73EANsEJZz0JnJ/e5VZef/kSaxydYZLAvw0rFNAUx5R7K5leC/CXXR2mZfXWhUvcZOO/dM2D5xg==", + "dev": true, + "requires": { + "dot-prop": "^4.1.0", + "env-paths": "^1.0.0", + "make-dir": "^1.0.0", + "pkg-up": "^2.0.0", + "write-file-atomic": "^2.3.0" + } + }, + "connect": { + "version": "3.6.6", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.6.6.tgz", + "integrity": "sha1-Ce/2xVr3I24TcTWnJXSFi2eG9SQ=", + "dev": true, + "requires": { + "debug": "2.6.9", + "finalhandler": "1.1.0", + "parseurl": "~1.3.2", + "utils-merge": "1.0.1" + } + }, + "connect-history-api-fallback": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", + "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", + "dev": true + }, + "console-browserify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", + "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", + "dev": true, + "requires": { + "date-now": "^0.1.4" + } + }, + "constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", + "dev": true + }, + "content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=", + "dev": true + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "dev": true + }, + "convert-source-map": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", + "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=", + "dev": true + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", + "dev": true + }, + "copy-concurrently": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", + "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", + "dev": true, + "requires": { + "aproba": "^1.1.1", + "fs-write-stream-atomic": "^1.0.8", + "iferr": "^0.1.5", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.0" + } + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true + }, + "copy-webpack-plugin": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-4.6.0.tgz", + "integrity": "sha512-Y+SQCF+0NoWQryez2zXn5J5knmr9z/9qSQt7fbL78u83rxmigOy8X5+BFn8CFSuX+nKT8gpYwJX68ekqtQt6ZA==", + "dev": true, + "requires": { + "cacache": "^10.0.4", + "find-cache-dir": "^1.0.0", + "globby": "^7.1.1", + "is-glob": "^4.0.0", + "loader-utils": "^1.1.0", + "minimatch": "^3.0.4", + "p-limit": "^1.0.0", + "serialize-javascript": "^1.4.0" + }, + "dependencies": { + "cacache": { + "version": "10.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-10.0.4.tgz", + "integrity": "sha512-Dph0MzuH+rTQzGPNT9fAnrPmMmjKfST6trxJeK7NQuHRaVw24VzPRWTmg9MpcwOVQZO0E1FBICUlFeNaKPIfHA==", + "dev": true, + "requires": { + "bluebird": "^3.5.1", + "chownr": "^1.0.1", + "glob": "^7.1.2", + "graceful-fs": "^4.1.11", + "lru-cache": "^4.1.1", + "mississippi": "^2.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.2", + "ssri": "^5.2.4", + "unique-filename": "^1.1.0", + "y18n": "^4.0.0" + } + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "mississippi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-2.0.0.tgz", + "integrity": "sha512-zHo8v+otD1J10j/tC+VNoGK9keCuByhKovAvdn74dmxJl9+mWHnx6EMsDN4lgRoMI/eYo2nchAxniIbUPb5onw==", + "dev": true, + "requires": { + "concat-stream": "^1.5.0", + "duplexify": "^3.4.2", + "end-of-stream": "^1.1.0", + "flush-write-stream": "^1.0.0", + "from2": "^2.1.0", + "parallel-transform": "^1.1.0", + "pump": "^2.0.1", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" + } + }, + "pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "ssri": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-5.3.0.tgz", + "integrity": "sha512-XRSIPqLij52MtgoQavH/x/dU1qVKtWUAAZeOHsR9c2Ddi4XerFy3mc1alf+dLJKl9EUIm/Ht+EowFkTUOA6GAQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.1" + } + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + } + } + }, + "core-js": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.4.tgz", + "integrity": "sha512-05qQ5hXShcqGkPZpXEFLIpxayZscVD2kuMBZewxiIPPEagukO4mqgPA9CWhUvFBJfy3ODdK2p9xyHh7FTU9/7A==" + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "cosmiconfig": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.1.0.tgz", + "integrity": "sha512-kCNPvthka8gvLtzAxQXvWo4FxqRB+ftRZyPZNuab5ngvM9Y7yw7hbEysglptLgpkGX9nAOKTBVkHUAe8xtYR6Q==", + "dev": true, + "requires": { + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.9.0", + "lodash.get": "^4.4.2", + "parse-json": "^4.0.0" + }, + "dependencies": { + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + } + } + }, + "create-ecdh": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", + "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "elliptic": "^6.0.0" + } + }, + "create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, + "requires": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "dependencies": { + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + } + } + }, + "crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "dev": true, + "requires": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + } + }, + "css-color-names": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", + "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=", + "dev": true + }, + "css-declaration-sorter": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz", + "integrity": "sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA==", + "dev": true, + "requires": { + "postcss": "^7.0.1", + "timsort": "^0.3.0" + } + }, + "css-loader": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-2.1.0.tgz", + "integrity": "sha512-MoOu+CStsGrSt5K2OeZ89q3Snf+IkxRfAIt9aAKg4piioTrhtP1iEFPu+OVn3Ohz24FO6L+rw9UJxBILiSBw5Q==", + "dev": true, + "requires": { + "icss-utils": "^4.0.0", + "loader-utils": "^1.2.1", + "lodash": "^4.17.11", + "postcss": "^7.0.6", + "postcss-modules-extract-imports": "^2.0.0", + "postcss-modules-local-by-default": "^2.0.3", + "postcss-modules-scope": "^2.0.0", + "postcss-modules-values": "^2.0.0", + "postcss-value-parser": "^3.3.0", + "schema-utils": "^1.0.0" + } + }, + "css-select": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", + "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", + "dev": true, + "requires": { + "boolbase": "~1.0.0", + "css-what": "2.1", + "domutils": "1.5.1", + "nth-check": "~1.0.1" + } + }, + "css-select-base-adapter": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", + "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==", + "dev": true + }, + "css-selector-tokenizer": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.1.tgz", + "integrity": "sha512-xYL0AMZJ4gFzJQsHUKa5jiWWi2vH77WVNg7JYRyewwj6oPh4yb/y6Y9ZCw9dsj/9UauMhtuxR+ogQd//EdEVNA==", + "dev": true, + "requires": { + "cssesc": "^0.1.0", + "fastparse": "^1.1.1", + "regexpu-core": "^1.0.0" + } + }, + "css-tree": { + "version": "1.0.0-alpha.28", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.28.tgz", + "integrity": "sha512-joNNW1gCp3qFFzj4St6zk+Wh/NBv0vM5YbEreZk0SD4S23S+1xBKb6cLDg2uj4P4k/GUMlIm6cKIDqIG+vdt0w==", + "dev": true, + "requires": { + "mdn-data": "~1.1.0", + "source-map": "^0.5.3" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "css-unit-converter": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.1.tgz", + "integrity": "sha1-2bkoGtz9jO2TW9urqDeGiX9k6ZY=", + "dev": true + }, + "css-url-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/css-url-regex/-/css-url-regex-1.1.0.tgz", + "integrity": "sha1-g4NCMMyfdMRX3lnuvRVD/uuDt+w=", + "dev": true + }, + "css-what": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz", + "integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==", + "dev": true + }, + "cssauron": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/cssauron/-/cssauron-1.4.0.tgz", + "integrity": "sha1-pmAt/34EqDBtwNuaVR6S6LVmKtg=", + "dev": true, + "requires": { + "through": "X.X.X" + } + }, + "cssesc": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-0.1.0.tgz", + "integrity": "sha1-yBSQPkViM3GgR3tAEJqq++6t27Q=", + "dev": true + }, + "cssnano": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-4.1.10.tgz", + "integrity": "sha512-5wny+F6H4/8RgNlaqab4ktc3e0/blKutmq8yNlBFXA//nSFFAqAngjNVRzUvCgYROULmZZUoosL/KSoZo5aUaQ==", + "dev": true, + "requires": { + "cosmiconfig": "^5.0.0", + "cssnano-preset-default": "^4.0.7", + "is-resolvable": "^1.0.0", + "postcss": "^7.0.0" + } + }, + "cssnano-preset-default": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-4.0.7.tgz", + "integrity": "sha512-x0YHHx2h6p0fCl1zY9L9roD7rnlltugGu7zXSKQx6k2rYw0Hi3IqxcoAGF7u9Q5w1nt7vK0ulxV8Lo+EvllGsA==", + "dev": true, + "requires": { + "css-declaration-sorter": "^4.0.1", + "cssnano-util-raw-cache": "^4.0.1", + "postcss": "^7.0.0", + "postcss-calc": "^7.0.1", + "postcss-colormin": "^4.0.3", + "postcss-convert-values": "^4.0.1", + "postcss-discard-comments": "^4.0.2", + "postcss-discard-duplicates": "^4.0.2", + "postcss-discard-empty": "^4.0.1", + "postcss-discard-overridden": "^4.0.1", + "postcss-merge-longhand": "^4.0.11", + "postcss-merge-rules": "^4.0.3", + "postcss-minify-font-values": "^4.0.2", + "postcss-minify-gradients": "^4.0.2", + "postcss-minify-params": "^4.0.2", + "postcss-minify-selectors": "^4.0.2", + "postcss-normalize-charset": "^4.0.1", + "postcss-normalize-display-values": "^4.0.2", + "postcss-normalize-positions": "^4.0.2", + "postcss-normalize-repeat-style": "^4.0.2", + "postcss-normalize-string": "^4.0.2", + "postcss-normalize-timing-functions": "^4.0.2", + "postcss-normalize-unicode": "^4.0.1", + "postcss-normalize-url": "^4.0.1", + "postcss-normalize-whitespace": "^4.0.2", + "postcss-ordered-values": "^4.1.2", + "postcss-reduce-initial": "^4.0.3", + "postcss-reduce-transforms": "^4.0.2", + "postcss-svgo": "^4.0.2", + "postcss-unique-selectors": "^4.0.1" + } + }, + "cssnano-util-get-arguments": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz", + "integrity": "sha1-7ToIKZ8h11dBsg87gfGU7UnMFQ8=", + "dev": true + }, + "cssnano-util-get-match": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz", + "integrity": "sha1-wOTKB/U4a7F+xeUiULT1lhNlFW0=", + "dev": true + }, + "cssnano-util-raw-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.1.tgz", + "integrity": "sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + } + }, + "cssnano-util-same-parent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.1.tgz", + "integrity": "sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q==", + "dev": true + }, + "csso": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/csso/-/csso-3.5.1.tgz", + "integrity": "sha512-vrqULLffYU1Q2tLdJvaCYbONStnfkfimRxXNaGjxMldI0C7JPBC4rB1RyjhfdZ4m1frm8pM9uRPKH3d2knZ8gg==", + "dev": true, + "requires": { + "css-tree": "1.0.0-alpha.29" + }, + "dependencies": { + "css-tree": { + "version": "1.0.0-alpha.29", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.29.tgz", + "integrity": "sha512-sRNb1XydwkW9IOci6iB2xmy8IGCj6r/fr+JWitvJ2JxQRPzN3T4AGGVWCMlVmVwM1gtgALJRmGIlWv5ppnGGkg==", + "dev": true, + "requires": { + "mdn-data": "~1.1.0", + "source-map": "^0.5.3" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "cssom": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.6.tgz", + "integrity": "sha512-DtUeseGk9/GBW0hl0vVPpU22iHL6YB5BUX7ml1hB+GMpo0NX5G4voX3kdWiMSEguFtcW3Vh3djqNF4aIe6ne0A==", + "dev": true + }, + "cssstyle": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.2.1.tgz", + "integrity": "sha512-7DYm8qe+gPx/h77QlCyFmX80+fGaE/6A/Ekl0zaszYOubvySO2saYFdQ78P29D0UsULxFKCetDGNaNRUdSF+2A==", + "dev": true, + "requires": { + "cssom": "0.3.x" + } + }, + "currently-unhandled": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", + "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", + "dev": true, + "requires": { + "array-find-index": "^1.0.1" + } + }, + "cyclist": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-0.2.2.tgz", + "integrity": "sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=", + "dev": true + }, + "d3": { + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/d3/-/d3-3.5.17.tgz", + "integrity": "sha1-vEZ0gAQ3iyGjYMn8fPUjF5B2L7g=", + "dev": true + }, + "dargs": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/dargs/-/dargs-6.0.0.tgz", + "integrity": "sha512-6lJauzNaI7MiM8EHQWmGj+s3rP5/i1nYs8GAvKrLAx/9dpc9xS/4seFb1ioR39A+kcfu4v3jnEa/EE5qWYnitQ==", + "dev": true + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "data-urls": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz", + "integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==", + "dev": true, + "requires": { + "abab": "^2.0.0", + "whatwg-mimetype": "^2.2.0", + "whatwg-url": "^7.0.0" + }, + "dependencies": { + "whatwg-url": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.0.0.tgz", + "integrity": "sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ==", + "dev": true, + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + } + } + }, + "date-fns": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz", + "integrity": "sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==", + "dev": true + }, + "date-now": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", + "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=", + "dev": true + }, + "dateformat": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", + "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "decamelize-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz", + "integrity": "sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=", + "dev": true, + "requires": { + "decamelize": "^1.1.0", + "map-obj": "^1.0.0" + }, + "dependencies": { + "map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "dev": true + } + } + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true + }, + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, + "dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", + "dev": true + }, + "deep-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", + "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=", + "dev": true + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "default-gateway": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-2.7.2.tgz", + "integrity": "sha512-lAc4i9QJR0YHSDFdzeBQKfZ1SRDG3hsJNEkrpcZa8QhBfidLAilT60BDEIVUUGqosFp425KOgB3uYqcnQrWafQ==", + "dev": true, + "requires": { + "execa": "^0.10.0", + "ip-regex": "^2.1.0" + }, + "dependencies": { + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "execa": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.10.0.tgz", + "integrity": "sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true + } + } + }, + "default-require-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-2.0.0.tgz", + "integrity": "sha1-9fj7sYp9bVCyH2QfZJ67Uiz+JPc=", + "dev": true, + "requires": { + "strip-bom": "^3.0.0" + } + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "defined": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", + "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=", + "dev": true + }, + "del": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/del/-/del-3.0.0.tgz", + "integrity": "sha1-U+z2mf/LyzljdpGrE7rxYIGXZuU=", + "dev": true, + "requires": { + "globby": "^6.1.0", + "is-path-cwd": "^1.0.0", + "is-path-in-cwd": "^1.0.0", + "p-map": "^1.1.1", + "pify": "^3.0.0", + "rimraf": "^2.2.8" + }, + "dependencies": { + "globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", + "dev": true + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true + }, + "dependency-graph": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.7.2.tgz", + "integrity": "sha512-KqtH4/EZdtdfWX0p6MGP9jljvxSY6msy/pRUD4jgNwVpv3v1QmNLlsB3LDSSUg79BRVSn7jI1QPRtArGABovAQ==", + "dev": true + }, + "des.js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz", + "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", + "dev": true + }, + "detect-conflict": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/detect-conflict/-/detect-conflict-1.0.1.tgz", + "integrity": "sha1-CIZXpmqWHAUBnbfEIwiDsca0F24=", + "dev": true + }, + "detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", + "dev": true + }, + "detect-newline": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", + "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=", + "dev": true + }, + "detect-node": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz", + "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==", + "dev": true + }, + "detective": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/detective/-/detective-4.7.1.tgz", + "integrity": "sha512-H6PmeeUcZloWtdt4DAkFyzFL94arpHr3NOwwmVILFiy+9Qd4JTxxXrzfyGk/lmct2qVGBwTSwSXagqu2BxmWig==", + "dev": true, + "requires": { + "acorn": "^5.2.1", + "defined": "^1.0.0" + } + }, + "dev-ip": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dev-ip/-/dev-ip-1.0.1.tgz", + "integrity": "sha1-p2o+0YVb56ASu4rBbLgPPADcKPA=", + "dev": true + }, + "diagnostics": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/diagnostics/-/diagnostics-1.1.1.tgz", + "integrity": "sha512-8wn1PmdunLJ9Tqbx+Fx/ZEuHfJf4NKSN2ZBj7SJC/OWRWha843+WsTjqMe1B5E3p28jqBlp+mJ2fPVxPyNgYKQ==", + "dev": true, + "requires": { + "colorspace": "1.1.x", + "enabled": "1.0.x", + "kuler": "1.0.x" + } + }, + "didyoumean": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.1.tgz", + "integrity": "sha1-6S7f2tplN9SE1zwBcv0eugxJdv8=", + "dev": true + }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true + }, + "diff-sequences": { + "version": "24.3.0", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-24.3.0.tgz", + "integrity": "sha512-xLqpez+Zj9GKSnPWS0WZw1igGocZ+uua8+y+5dDNTT934N3QuY1sp2LkHzwiaYQGz60hMq0pjAshdeXm5VUOEw==", + "dev": true + }, + "diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + } + }, + "dir-glob": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz", + "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==", + "dev": true, + "requires": { + "path-type": "^3.0.0" + }, + "dependencies": { + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=", + "dev": true + }, + "dns-packet": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.1.tgz", + "integrity": "sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg==", + "dev": true, + "requires": { + "ip": "^1.1.0", + "safe-buffer": "^5.0.1" + } + }, + "dns-txt": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", + "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", + "dev": true, + "requires": { + "buffer-indexof": "^1.0.0" + } + }, + "dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "dev": true, + "requires": { + "utila": "~0.4" + } + }, + "dom-serializer": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz", + "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==", + "dev": true, + "requires": { + "domelementtype": "^1.3.0", + "entities": "^1.1.1" + } + }, + "domain-browser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", + "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", + "dev": true + }, + "domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", + "dev": true + }, + "domexception": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz", + "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==", + "dev": true, + "requires": { + "webidl-conversions": "^4.0.2" + } + }, + "domhandler": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", + "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", + "dev": true, + "requires": { + "domelementtype": "1" + } + }, + "domutils": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", + "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", + "dev": true, + "requires": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "dot-prop": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", + "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", + "dev": true, + "requires": { + "is-obj": "^1.0.0" + } + }, + "drange": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/drange/-/drange-1.1.1.tgz", + "integrity": "sha512-pYxfDYpued//QpnLIm4Avk7rsNtAtQkUES2cwAYSvD/wd2pKD71gN2Ebj3e7klzXwjocvE8c5vx/1fxwpqmSxA==", + "dev": true + }, + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", + "dev": true + }, + "duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "dev": true, + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "easy-extender": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/easy-extender/-/easy-extender-2.3.4.tgz", + "integrity": "sha512-8cAwm6md1YTiPpOvDULYJL4ZS6WfM5/cTeVVh4JsvyYZAoqlRVUpHL9Gr5Fy7HA6xcSZicUia3DeAgO3Us8E+Q==", + "dev": true, + "requires": { + "lodash": "^4.17.10" + } + }, + "eazy-logger": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/eazy-logger/-/eazy-logger-3.0.2.tgz", + "integrity": "sha1-oyWqXlPROiIliJsqxBE7K5Y29Pw=", + "dev": true, + "requires": { + "tfunk": "^3.0.1" + } + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dev": true, + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "editions": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/editions/-/editions-2.1.3.tgz", + "integrity": "sha512-xDZyVm0A4nLgMNWVVLJvcwMjI80ShiH/27RyLiCnW1L273TcJIA25C4pwJ33AWV01OX6UriP35Xu+lH4S7HWQw==", + "dev": true, + "requires": { + "errlop": "^1.1.1", + "semver": "^5.6.0" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", + "dev": true + }, + "ejs": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.6.1.tgz", + "integrity": "sha512-0xy4A/twfrRCnkhfk8ErDi5DqdAsAqeGxht4xkCUrsvhhbQNs7E+4jV0CN7+NKIY0aHE72+XvqtBIXzD31ZbXQ==", + "dev": true + }, + "electron-to-chromium": { + "version": "1.3.116", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.116.tgz", + "integrity": "sha512-NKwKAXzur5vFCZYBHpdWjTMO8QptNLNP80nItkSIgUOapPAo9Uia+RvkCaZJtO7fhQaVElSvBPWEc2ku6cKsPA==", + "dev": true + }, + "elegant-spinner": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/elegant-spinner/-/elegant-spinner-1.0.1.tgz", + "integrity": "sha1-2wQ1IcldfjA/2PNFvtwzSc+wcp4=", + "dev": true + }, + "elliptic": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.1.tgz", + "integrity": "sha512-BsXLz5sqX8OHcsh7CqBMztyXARmGQ3LWPtGjJi6DiJHq5C/qvi9P3OqgswKSDftbu8+IoI/QDTAm2fFnQ9SZSQ==", + "dev": true, + "requires": { + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.0" + } + }, + "emojis-list": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", + "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", + "dev": true + }, + "enabled": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-1.0.2.tgz", + "integrity": "sha1-ll9lE9LC0cX0ZStkouM5ZGf8L5M=", + "dev": true, + "requires": { + "env-variable": "0.0.x" + } + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "dev": true + }, + "encoding": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", + "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", + "requires": { + "iconv-lite": "~0.4.13" + } + }, + "end-of-stream": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", + "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "engine.io": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.2.1.tgz", + "integrity": "sha512-+VlKzHzMhaU+GsCIg4AoXF1UdDFjHHwMmMKqMJNDNLlUlejz58FCy4LBqB2YVJskHGYl06BatYWKP2TVdVXE5w==", + "dev": true, + "requires": { + "accepts": "~1.3.4", + "base64id": "1.0.0", + "cookie": "0.3.1", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.0", + "ws": "~3.3.1" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + } + } + }, + "engine.io-client": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.3.2.tgz", + "integrity": "sha512-y0CPINnhMvPuwtqXfsGuWE8BB66+B6wTtCofQDRecMQPYX3MYUZXFNKDhdrSe3EVjgOu4V3rxdeqN/Tr91IgbQ==", + "dev": true, + "requires": { + "component-emitter": "1.2.1", + "component-inherit": "0.0.3", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.1", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "ws": "~6.1.0", + "xmlhttprequest-ssl": "~1.5.4", + "yeast": "0.1.2" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "engine.io-parser": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.3.tgz", + "integrity": "sha512-6HXPre2O4Houl7c4g7Ic/XzPnHBvaEmN90vtRO9uLmwtRqQmTOw0QMevL1TOfL2Cpu1VzsaTmMotQgMdkzGkVA==", + "dev": true, + "requires": { + "after": "0.8.2", + "arraybuffer.slice": "~0.0.7", + "base64-arraybuffer": "0.1.5", + "blob": "0.0.5", + "has-binary2": "~1.0.2" + } + }, + "enhanced-resolve": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz", + "integrity": "sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.4.0", + "tapable": "^1.0.0" + } + }, + "entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", + "dev": true + }, + "env-paths": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-1.0.0.tgz", + "integrity": "sha1-QWgTO0K7BcOKNbGuQ5fIKYqzaeA=", + "dev": true + }, + "env-variable": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/env-variable/-/env-variable-0.0.5.tgz", + "integrity": "sha512-zoB603vQReOFvTg5xMl9I1P2PnHsHQQKTEowsKKD7nseUfJq6UWzK+4YtlWUO1nhiQUxe6XMkk+JleSZD1NZFA==", + "dev": true + }, + "envify": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/envify/-/envify-3.4.1.tgz", + "integrity": "sha1-1xIjKejfFoi6dxsSUBkXyc5cvOg=", + "dev": true, + "requires": { + "jstransform": "^11.0.3", + "through": "~2.3.4" + } + }, + "err-code": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-1.1.2.tgz", + "integrity": "sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA=", + "dev": true + }, + "errlop": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/errlop/-/errlop-1.1.1.tgz", + "integrity": "sha512-WX7QjiPHhsny7/PQvrhS5VMizXXKoKCS3udaBp8gjlARdbn+XmK300eKBAAN0hGyRaTCtRpOaxK+xFVPUJ3zkw==", + "dev": true, + "requires": { + "editions": "^2.1.2" + } + }, + "errno": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", + "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", + "dev": true, + "requires": { + "prr": "~1.0.1" + } + }, + "error": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/error/-/error-7.0.2.tgz", + "integrity": "sha1-pfdf/02ZJhJt2sDqXcOOaJFTywI=", + "dev": true, + "requires": { + "string-template": "~0.2.1", + "xtend": "~4.0.0" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "error-stack-parser": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.0.2.tgz", + "integrity": "sha512-E1fPutRDdIj/hohG0UpT5mayXNCxXP9d+snxFsPU9X0XgccOumKraa3juDMwTUyi7+Bu5+mCGagjg4IYeNbOdw==", + "dev": true, + "requires": { + "stackframe": "^1.0.4" + } + }, + "es-abstract": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", + "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.0", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-keys": "^1.0.12" + } + }, + "es-to-primitive": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", + "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es6-promise": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.6.tgz", + "integrity": "sha512-aRVgGdnmW2OiySVPUC9e6m+plolMAJKjZnQlCwNSuK5yQ0JN61DZSO1X1Ufd1foqWRAlig0rhduTCHe7sVtK5Q==", + "dev": true + }, + "es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "dev": true, + "requires": { + "es6-promise": "^4.0.3" + } + }, + "es6-templates": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/es6-templates/-/es6-templates-0.2.3.tgz", + "integrity": "sha1-XLmsn7He1usSOTQrgdeSu7QHjuQ=", + "dev": true, + "requires": { + "recast": "~0.11.12", + "through": "~2.3.6" + } + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "escodegen": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.11.1.tgz", + "integrity": "sha512-JwiqFD9KdGVVpeuRa68yU3zZnBEOcPs0nKW7wZzXky8Z7tffdYUHbe11bPCV5jYlK6DVdKLWLm0f5I/QlL0Kmw==", + "dev": true, + "requires": { + "esprima": "^3.1.3", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + }, + "dependencies": { + "esprima": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true + } + } + }, + "eslint-scope": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", + "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "dev": true, + "requires": { + "estraverse": "^4.1.0" + } + }, + "estraverse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "dev": true + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "dev": true + }, + "eventemitter3": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-1.2.0.tgz", + "integrity": "sha1-HIaZHYFq0eUEdQ5zh0Ik7PO+xQg=", + "dev": true + }, + "events": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.0.0.tgz", + "integrity": "sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA==", + "dev": true + }, + "eventsource": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.0.7.tgz", + "integrity": "sha512-4Ln17+vVT0k8aWq+t/bF5arcS3EpT9gYtW66EPacdj/mAFevznsnyoHLPy2BA8gbIQeIHoPsvwmfBftfcG//BQ==", + "dev": true, + "requires": { + "original": "^1.0.0" + } + }, + "evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "requires": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "exec-sh": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.2.tgz", + "integrity": "sha512-9sLAvzhI5nc8TpuQUh4ahMdCrWT00wPWz7j47/emR5+2qEfoZP5zzUXvx+vdx+H6ohhnsYC31iX04QLYJK8zTg==", + "dev": true + }, + "execa": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", + "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", + "dev": true, + "requires": { + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "dependencies": { + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true + } + } + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true + }, + "exit-hook": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz", + "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=", + "dev": true + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "expand-range": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", + "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", + "dev": true, + "requires": { + "fill-range": "^2.1.0" + }, + "dependencies": { + "fill-range": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", + "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", + "dev": true, + "requires": { + "is-number": "^2.1.0", + "isobject": "^2.0.0", + "randomatic": "^3.0.0", + "repeat-element": "^1.1.2", + "repeat-string": "^1.5.2" + } + }, + "is-number": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", + "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", + "dev": true, + "requires": { + "homedir-polyfill": "^1.0.1" + } + }, + "expect": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-24.5.0.tgz", + "integrity": "sha512-p2Gmc0CLxOgkyA93ySWmHFYHUPFIHG6XZ06l7WArWAsrqYVaVEkOU5NtT5i68KUyGKbkQgDCkiT65bWmdoL6Bw==", + "dev": true, + "requires": { + "@jest/types": "^24.5.0", + "ansi-styles": "^3.2.0", + "jest-get-type": "^24.3.0", + "jest-matcher-utils": "^24.5.0", + "jest-message-util": "^24.5.0", + "jest-regex-util": "^24.3.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + } + } + }, + "express": { + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/express/-/express-4.16.4.tgz", + "integrity": "sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==", + "dev": true, + "requires": { + "accepts": "~1.3.5", + "array-flatten": "1.1.1", + "body-parser": "1.18.3", + "content-disposition": "0.5.2", + "content-type": "~1.0.4", + "cookie": "0.3.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.1.1", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.4", + "qs": "6.5.2", + "range-parser": "~1.2.0", + "safe-buffer": "5.1.2", + "send": "0.16.2", + "serve-static": "1.13.2", + "setprototypeof": "1.1.0", + "statuses": "~1.4.0", + "type-is": "~1.6.16", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", + "dev": true + }, + "finalhandler": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", + "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.4.0", + "unpipe": "~1.0.0" + } + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true + }, + "statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", + "dev": true + } + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "external-editor": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", + "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", + "requires": { + "chardet": "^0.4.0", + "iconv-lite": "^0.4.17", + "tmp": "^0.0.33" + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true + }, + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", + "dev": true + }, + "fast-glob": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.6.tgz", + "integrity": "sha512-0BvMaZc1k9F+MeWWMe8pL6YltFzZYcJsYU7D4JyDA6PAczaXvxqQQ/z+mDF7/4Mw01DeUc+i3CTKajnkANkV4w==", + "dev": true, + "requires": { + "@mrmlnc/readdir-enhanced": "^2.2.1", + "@nodelib/fs.stat": "^1.1.2", + "glob-parent": "^3.1.0", + "is-glob": "^4.0.0", + "merge2": "^1.2.3", + "micromatch": "^3.1.10" + } + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "fast-safe-stringify": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.6.tgz", + "integrity": "sha512-q8BZ89jjc+mz08rSxROs8VsrBBcn1SIw1kq9NjolL509tkABRk9io01RAjSaEv1Xb2uFLt8VtRiZbGp5H8iDtg==", + "dev": true + }, + "fastparse": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz", + "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==", + "dev": true + }, + "faye-websocket": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", + "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=", + "dev": true, + "requires": { + "websocket-driver": ">=0.5.1" + } + }, + "fb-watchman": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.0.tgz", + "integrity": "sha1-VOmr99+i8mzZsWNsWIwa/AXeXVg=", + "dev": true, + "requires": { + "bser": "^2.0.0" + } + }, + "fbjs": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.6.1.tgz", + "integrity": "sha1-lja3cF9bqWhNRLcveDISVK/IYPc=", + "dev": true, + "requires": { + "core-js": "^1.0.0", + "loose-envify": "^1.0.0", + "promise": "^7.0.3", + "ua-parser-js": "^0.7.9", + "whatwg-fetch": "^0.9.0" + }, + "dependencies": { + "core-js": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", + "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=", + "dev": true + } + } + }, + "fecha": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-2.3.3.tgz", + "integrity": "sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg==", + "dev": true + }, + "figgy-pudding": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.1.tgz", + "integrity": "sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==", + "dev": true + }, + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-loader": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-3.0.1.tgz", + "integrity": "sha512-4sNIOXgtH/9WZq4NvlfU3Opn5ynUsqBwSLyM+I7UOwdGigTBYfVVQEwe/msZNX/j4pCJTIM14Fsw66Svo1oVrw==", + "dev": true, + "requires": { + "loader-utils": "^1.0.2", + "schema-utils": "^1.0.0" + } + }, + "filename-regex": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", + "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", + "dev": true + }, + "fileset": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/fileset/-/fileset-2.0.3.tgz", + "integrity": "sha1-jnVIqW08wjJ+5eZ0FocjozO7oqA=", + "dev": true, + "requires": { + "glob": "^7.0.3", + "minimatch": "^3.0.3" + } + }, + "filesize": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-3.6.1.tgz", + "integrity": "sha512-7KjR1vv6qnicaPMi1iiTcI85CyYwRO/PSFCu6SvqL8jN2Wjt/NIYQTFtFs7fSDCYOstUkEWIQGFUg5YZQfjlcg==", + "dev": true + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "finalhandler": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz", + "integrity": "sha1-zgtoVbRYU+eRsvzGgARtiCU91/U=", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.1", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.3.1", + "unpipe": "~1.0.0" + } + }, + "find-cache-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-1.0.0.tgz", + "integrity": "sha1-kojj6ePMN0hxfTnq3hfPcfww7m8=", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^1.0.0", + "pkg-dir": "^2.0.0" + } + }, + "find-parent-dir": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/find-parent-dir/-/find-parent-dir-0.3.0.tgz", + "integrity": "sha1-M8RLQpqysvBkYpnF+fcY83b/jVQ=", + "dev": true + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "findup-sync": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", + "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=", + "dev": true, + "requires": { + "detect-file": "^1.0.0", + "is-glob": "^3.1.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "first-chunk-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-2.0.0.tgz", + "integrity": "sha1-G97NuOCDwGZLkZRVgVd6Q6nzHXA=", + "dev": true, + "requires": { + "readable-stream": "^2.0.2" + } + }, + "flush-write-stream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", + "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" + } + }, + "fn-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fn-name/-/fn-name-2.0.1.tgz", + "integrity": "sha1-UhTXU3pNBqSjAcDMJi/rhBiAAuc=", + "dev": true + }, + "follow-redirects": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.7.0.tgz", + "integrity": "sha512-m/pZQy4Gj287eNy94nivy5wchN3Kp+Q5WgUPNy5lJSZ3sgkVKSYV/ZChMAQVIgx1SqfZ2zBZtPA2YlXIWxxJOQ==", + "dev": true, + "requires": { + "debug": "^3.2.6" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + } + } + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "for-own": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", + "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", + "dev": true, + "requires": { + "for-in": "^1.0.1" + } + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "fork-ts-checker-webpack-plugin": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-0.5.2.tgz", + "integrity": "sha512-a5IG+xXyKnpruI0CP/anyRLAoxWtp3lzdG6flxicANnoSzz64b12dJ7ASAVRrI2OaWwZR2JyBaMHFQqInhWhIw==", + "dev": true, + "requires": { + "babel-code-frame": "^6.22.0", + "chalk": "^2.4.1", + "chokidar": "^2.0.4", + "micromatch": "^3.1.10", + "minimatch": "^3.0.4", + "tapable": "^1.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", + "dev": true + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "requires": { + "map-cache": "^0.2.2" + } + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "dev": true + }, + "friendly-errors-webpack-plugin": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/friendly-errors-webpack-plugin/-/friendly-errors-webpack-plugin-1.7.0.tgz", + "integrity": "sha512-K27M3VK30wVoOarP651zDmb93R9zF28usW4ocaK3mfQeIEI5BPht/EzZs5E8QLLwbLRJQMwscAjDxYPb1FuNiw==", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "error-stack-parser": "^2.0.0", + "string-width": "^2.0.0" + } + }, + "from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "fs-extra": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-3.0.1.tgz", + "integrity": "sha1-N5TzeMWLNC6n27sjCVEJxLO2IpE=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^3.0.0", + "universalify": "^0.1.0" + } + }, + "fs-minipass": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz", + "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==", + "dev": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "fs-write-stream-atomic": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", + "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "iferr": "^0.1.5", + "imurmurhash": "^0.1.4", + "readable-stream": "1 || 2" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.7.tgz", + "integrity": "sha512-Pxm6sI2MeBD7RdD12RYsqaP0nMiwx8eZBXCa6z2L+mRHm2DYrOYwihmhjpkdjUHwQhslWQjRpEgNq4XvBmaAuw==", + "dev": true, + "optional": true, + "requires": { + "nan": "^2.9.2", + "node-pre-gyp": "^0.10.0" + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "aproba": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "chownr": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "debug": { + "version": "2.6.9", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ms": "2.0.0" + } + }, + "deep-extend": { + "version": "0.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "detect-libc": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "fs-minipass": { + "version": "1.2.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "glob": { + "version": "7.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "iconv-lite": { + "version": "0.4.24", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore-walk": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "ini": { + "version": "1.3.5", + "bundled": true, + "dev": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "dev": true, + "optional": true + }, + "minipass": { + "version": "2.3.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.2.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "needle": { + "version": "2.2.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "debug": "^2.1.2", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } + }, + "node-pre-gyp": { + "version": "0.10.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "npm-bundled": { + "version": "1.0.5", + "bundled": true, + "dev": true, + "optional": true + }, + "npm-packlist": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, + "npmlog": { + "version": "4.1.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "wrappy": "1" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "osenv": { + "version": "0.1.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "process-nextick-args": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "rc": { + "version": "1.2.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "rimraf": { + "version": "2.6.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "sax": { + "version": "1.2.4", + "bundled": true, + "dev": true, + "optional": true + }, + "semver": { + "version": "5.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "tar": { + "version": "4.4.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.3.4", + "minizlib": "^1.1.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "wide-align": { + "version": "1.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "yallist": { + "version": "3.0.3", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "g-status": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/g-status/-/g-status-2.0.2.tgz", + "integrity": "sha512-kQoE9qH+T1AHKgSSD0Hkv98bobE90ILQcXAF4wvGgsr7uFqNvwmh8j+Lq3l0RVt3E3HjSbv2B9biEGcEtpHLCA==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "matcher": "^1.0.0", + "simple-git": "^1.85.0" + } + }, + "gauge": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-1.2.7.tgz", + "integrity": "sha1-6c7FSD09TuDvRLYKfZnkk14TbZM=", + "dev": true, + "requires": { + "ansi": "^0.3.0", + "has-unicode": "^2.0.0", + "lodash.pad": "^4.1.0", + "lodash.padend": "^4.1.0", + "lodash.padstart": "^4.1.0" + } + }, + "generator-jhipster": { + "version": "5.8.2", + "resolved": "https://registry.npmjs.org/generator-jhipster/-/generator-jhipster-5.8.2.tgz", + "integrity": "sha512-GW33cKnIf0wWuK411U9GDiNKwKVLbL4BpAqyR4b9JD6ClhwHsQg3HRlItN8pV0iTHJtyFnSfcV/9nJIHFWwvKA==", + "dev": true, + "requires": { + "axios": "0.18.0", + "chalk": "2.4.1", + "commander": "2.16.0", + "conf": "2.0.0", + "didyoumean": "1.2.1", + "ejs": "2.6.1", + "glob": "7.1.2", + "gulp-filter": "5.1.0", + "insight": "0.10.1", + "jhipster-core": "3.6.11", + "js-object-pretty-print": "0.3.0", + "js-yaml": "3.12.0", + "lodash": "4.17.10", + "meow": "5.0.0", + "mkdirp": "0.5.1", + "os-locale": "2.1.0", + "parse-gitignore": "1.0.1", + "pluralize": "7.0.0", + "prettier": "1.13.7", + "randexp": "0.4.9", + "semver": "5.5.0", + "shelljs": "0.8.2", + "tabtab": "2.2.2", + "through2": "2.0.3", + "uuid": "3.3.2", + "yeoman-environment": "2.3.0", + "yeoman-generator": "3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "axios": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.0.tgz", + "integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=", + "dev": true, + "requires": { + "follow-redirects": "^1.3.0", + "is-buffer": "^1.1.5" + } + }, + "chalk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "commander": { + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.16.0.tgz", + "integrity": "sha512-sVXqklSaotK9at437sFlFpyOcJonxe0yST/AG9DkQKUdIE6IqGIMv4SfAQSKaJbSdVEJYItASCrBiVQHq1HQew==", + "dev": true + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "lodash": { + "version": "4.17.10", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", + "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==", + "dev": true + }, + "prettier": { + "version": "1.13.7", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.13.7.tgz", + "integrity": "sha512-KIU72UmYPGk4MujZGYMFwinB7lOf2LsDNGSOC8ufevsrPLISrZbNJlWstRi3m0AMuszbH+EFSQ/r6w56RSPK6w==", + "dev": true + }, + "semver": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", + "dev": true + }, + "shelljs": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.2.tgz", + "integrity": "sha512-pRXeNrCA2Wd9itwhvLp5LZQvPJ0wU6bcjaTMywHHGX5XWhVN2nzSu7WV0q+oUY7mGK3mgSkDDzP3MgjqdyIgbQ==", + "dev": true, + "requires": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "through2": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", + "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", + "dev": true, + "requires": { + "readable-stream": "^2.1.5", + "xtend": "~4.0.1" + } + } + } + }, + "genfun": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/genfun/-/genfun-5.0.0.tgz", + "integrity": "sha512-KGDOARWVga7+rnB3z9Sd2Letx515owfk0hSxHGuqjANb1M+x2bGZGqHLiozPsYMdM2OubeMni/Hpwmjq6qIUhA==", + "dev": true + }, + "get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "dev": true + }, + "get-own-enumerable-property-symbols": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.0.tgz", + "integrity": "sha512-CIJYJC4GGF06TakLg8z4GQKvDsx9EMspVxOYih7LerEL/WosUnFIww45CGfxfeKHqlg3twgUrYRT1O3WQqjGCg==", + "dev": true + }, + "get-stdin": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", + "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", + "dev": true + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "gh-got": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/gh-got/-/gh-got-6.0.0.tgz", + "integrity": "sha512-F/mS+fsWQMo1zfgG9MD8KWvTWPPzzhuVwY++fhQ5Ggd+0P+CAMHtzMZhNxG+TqGfHDChJKsbh6otfMGqO2AKBw==", + "dev": true, + "requires": { + "got": "^7.0.0", + "is-plain-obj": "^1.1.0" + } + }, + "github-username": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/github-username/-/github-username-4.1.0.tgz", + "integrity": "sha1-y+KABBiDIG2kISrp5LXxacML9Bc=", + "dev": true, + "requires": { + "gh-got": "^6.0.0" + } + }, + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-base": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", + "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", + "dev": true, + "requires": { + "glob-parent": "^2.0.0", + "is-glob": "^2.0.0" + }, + "dependencies": { + "glob-parent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "dev": true, + "requires": { + "is-glob": "^2.0.0" + } + }, + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "dev": true + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "dev": true, + "requires": { + "is-extglob": "^1.0.0" + } + } + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "glob-to-regexp": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz", + "integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=", + "dev": true + }, + "global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "dev": true, + "requires": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + } + }, + "global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", + "dev": true, + "requires": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + } + }, + "globals": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.11.0.tgz", + "integrity": "sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw==", + "dev": true + }, + "globby": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-7.1.1.tgz", + "integrity": "sha1-+yzP+UAfhgCUXfral0QMypcrhoA=", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "dir-glob": "^2.0.0", + "glob": "^7.1.2", + "ignore": "^3.3.5", + "pify": "^3.0.0", + "slash": "^1.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "got": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/got/-/got-7.1.0.tgz", + "integrity": "sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw==", + "dev": true, + "requires": { + "decompress-response": "^3.2.0", + "duplexer3": "^0.1.4", + "get-stream": "^3.0.0", + "is-plain-obj": "^1.1.0", + "is-retry-allowed": "^1.0.0", + "is-stream": "^1.0.0", + "isurl": "^1.0.0-alpha5", + "lowercase-keys": "^1.0.0", + "p-cancelable": "^0.3.0", + "p-timeout": "^1.1.1", + "safe-buffer": "^5.0.1", + "timed-out": "^4.0.0", + "url-parse-lax": "^1.0.0", + "url-to-options": "^1.0.1" + }, + "dependencies": { + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true + } + } + }, + "graceful-fs": { + "version": "4.1.15", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", + "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", + "dev": true + }, + "grouped-queue": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/grouped-queue/-/grouped-queue-0.3.3.tgz", + "integrity": "sha1-wWfSpTGcWg4JZO9qJbfC34mWyFw=", + "dev": true, + "requires": { + "lodash": "^4.17.2" + } + }, + "growly": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", + "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", + "dev": true + }, + "gulp-filter": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/gulp-filter/-/gulp-filter-5.1.0.tgz", + "integrity": "sha1-oF4Rr/sHz33PQafeHLe2OsN4PnM=", + "dev": true, + "requires": { + "multimatch": "^2.0.0", + "plugin-error": "^0.1.2", + "streamfilter": "^1.0.5" + } + }, + "handle-thing": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.0.tgz", + "integrity": "sha512-d4sze1JNC454Wdo2fkuyzCr6aHcbL6PGGuFAz0Li/NcOm1tCHGnWDRmJP85dh9IhQErTc2svWFEX5xHIOo//kQ==", + "dev": true + }, + "handlebars": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.1.tgz", + "integrity": "sha512-3Zhi6C0euYZL5sM0Zcy7lInLXKQ+YLcF/olbN010mzGQ4XVm50JeyBnMqofHh696GrciGruC7kCcApPDJvVgwA==", + "dev": true, + "requires": { + "neo-async": "^2.6.0", + "optimist": "^0.6.1", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true + }, + "har-validator": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", + "dev": true, + "requires": { + "ajv": "^6.5.5", + "har-schema": "^2.0.0" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "has-binary2": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", + "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", + "dev": true, + "requires": { + "isarray": "2.0.1" + }, + "dependencies": { + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", + "dev": true + } + } + }, + "has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-symbol-support-x": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz", + "integrity": "sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==", + "dev": true + }, + "has-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", + "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", + "dev": true + }, + "has-to-string-tag-x": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz", + "integrity": "sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==", + "dev": true, + "requires": { + "has-symbol-support-x": "^1.4.1" + } + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", + "dev": true + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "hash-base": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", + "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, + "hex-color-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz", + "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==", + "dev": true + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "dev": true, + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "hoek": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", + "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==", + "dev": true + }, + "homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "dev": true, + "requires": { + "parse-passwd": "^1.0.0" + } + }, + "hosted-git-info": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", + "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", + "dev": true + }, + "hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "hsl-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hsl-regex/-/hsl-regex-1.0.0.tgz", + "integrity": "sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4=", + "dev": true + }, + "hsla-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hsla-regex/-/hsla-regex-1.0.0.tgz", + "integrity": "sha1-wc56MWjIxmFAM6S194d/OyJfnDg=", + "dev": true + }, + "html-comment-regex": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.2.tgz", + "integrity": "sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==", + "dev": true + }, + "html-encoding-sniffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz", + "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==", + "dev": true, + "requires": { + "whatwg-encoding": "^1.0.1" + } + }, + "html-entities": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.2.1.tgz", + "integrity": "sha1-DfKTUfByEWNRXfueVUPl9u7VFi8=", + "dev": true + }, + "html-loader": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/html-loader/-/html-loader-0.5.5.tgz", + "integrity": "sha512-7hIW7YinOYUpo//kSYcPB6dCKoceKLmOwjEMmhIobHuWGDVl0Nwe4l68mdG/Ru0wcUxQjVMEoZpkalZ/SE7zog==", + "dev": true, + "requires": { + "es6-templates": "^0.2.3", + "fastparse": "^1.1.1", + "html-minifier": "^3.5.8", + "loader-utils": "^1.1.0", + "object-assign": "^4.1.1" + } + }, + "html-minifier": { + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.21.tgz", + "integrity": "sha512-LKUKwuJDhxNa3uf/LPR/KVjm/l3rBqtYeCOAekvG8F1vItxMUpueGd94i/asDDr8/1u7InxzFA5EeGjhhG5mMA==", + "dev": true, + "requires": { + "camel-case": "3.0.x", + "clean-css": "4.2.x", + "commander": "2.17.x", + "he": "1.2.x", + "param-case": "2.1.x", + "relateurl": "0.2.x", + "uglify-js": "3.4.x" + }, + "dependencies": { + "commander": { + "version": "2.17.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", + "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", + "dev": true + } + } + }, + "html-webpack-plugin": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-3.2.0.tgz", + "integrity": "sha1-sBq71yOsqqeze2r0SS69oD2d03s=", + "dev": true, + "requires": { + "html-minifier": "^3.2.3", + "loader-utils": "^0.2.16", + "lodash": "^4.17.3", + "pretty-error": "^2.0.2", + "tapable": "^1.0.0", + "toposort": "^1.0.0", + "util.promisify": "1.0.0" + }, + "dependencies": { + "big.js": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", + "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==", + "dev": true + }, + "json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "dev": true + }, + "loader-utils": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz", + "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=", + "dev": true, + "requires": { + "big.js": "^3.1.3", + "emojis-list": "^2.0.0", + "json5": "^0.5.0", + "object-assign": "^4.0.1" + } + } + } + }, + "htmlparser2": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", + "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", + "dev": true, + "requires": { + "domelementtype": "^1.3.1", + "domhandler": "^2.3.0", + "domutils": "^1.5.1", + "entities": "^1.1.1", + "inherits": "^2.0.1", + "readable-stream": "^3.1.1" + }, + "dependencies": { + "readable-stream": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.2.0.tgz", + "integrity": "sha512-RV20kLjdmpZuTF1INEb9IA3L68Nmi+Ri7ppZqo78wj//Pn62fCoJyV9zalccNzDD/OuJpMG4f+pfMl8+L6QdGw==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "http-cache-semantics": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz", + "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==", + "dev": true + }, + "http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=", + "dev": true + }, + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "dependencies": { + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "dev": true + } + } + }, + "http-parser-js": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.0.tgz", + "integrity": "sha512-cZdEF7r4gfRIq7ezX9J0T+kQmJNOub71dWbgAXVHDct80TKP4MCETtZQ31xyv38UwgzkWPYF/Xc0ge55dW9Z9w==", + "dev": true + }, + "http-proxy": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.15.2.tgz", + "integrity": "sha1-ZC/cr/5S00SNK9o7AHnpQJBk2jE=", + "dev": true, + "requires": { + "eventemitter3": "1.x.x", + "requires-port": "1.x.x" + } + }, + "http-proxy-agent": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", + "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", + "dev": true, + "requires": { + "agent-base": "4", + "debug": "3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "http-proxy-middleware": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.18.0.tgz", + "integrity": "sha512-Fs25KVMPAIIcgjMZkVHJoKg9VcXcC1C8yb9JUgeDvVXY0S/zgVIhMb+qVswDIgtJe2DfckMSY2d6TuTEutlk6Q==", + "dev": true, + "requires": { + "http-proxy": "^1.16.2", + "is-glob": "^4.0.0", + "lodash": "^4.17.5", + "micromatch": "^3.1.9" + }, + "dependencies": { + "eventemitter3": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.0.tgz", + "integrity": "sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA==", + "dev": true + }, + "http-proxy": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.17.0.tgz", + "integrity": "sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==", + "dev": true, + "requires": { + "eventemitter3": "^3.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + } + } + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", + "dev": true + }, + "https-proxy-agent": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz", + "integrity": "sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==", + "dev": true, + "requires": { + "agent-base": "^4.1.0", + "debug": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + } + } + }, + "humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0=", + "dev": true, + "requires": { + "ms": "^2.0.0" + } + }, + "husky": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/husky/-/husky-1.3.1.tgz", + "integrity": "sha512-86U6sVVVf4b5NYSZ0yvv88dRgBSSXXmHaiq5pP4KDj5JVzdwKgBjEtUPOm8hcoytezFwbU+7gotXNhpHdystlg==", + "dev": true, + "requires": { + "cosmiconfig": "^5.0.7", + "execa": "^1.0.0", + "find-up": "^3.0.0", + "get-stdin": "^6.0.0", + "is-ci": "^2.0.0", + "pkg-dir": "^3.0.0", + "please-upgrade-node": "^3.1.1", + "read-pkg": "^4.0.1", + "run-node": "^1.0.0", + "slash": "^2.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", + "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.1.0.tgz", + "integrity": "sha512-H2RyIJ7+A3rjkwKC2l5GGtU4H1vkxKCAGsWasNVd0Set+6i4znxbWy6/j16YDPJDWxhsgZiKAstMEP8wCdSpjA==", + "dev": true + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + }, + "read-pkg": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-4.0.1.tgz", + "integrity": "sha1-ljYlN48+HE1IyFhytabsfV0JMjc=", + "dev": true, + "requires": { + "normalize-package-data": "^2.3.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0" + } + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + } + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "icss-replace-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz", + "integrity": "sha1-Bupvg2ead0njhs/h/oEq5dsiPe0=", + "dev": true + }, + "icss-utils": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-4.1.0.tgz", + "integrity": "sha512-3DEun4VOeMvSczifM3F2cKQrDQ5Pj6WKhkOq6HD4QTnDUAq8MQRxy5TX6Sy1iY6WPBe4gQ3p5vTECjbIkglkkQ==", + "dev": true, + "requires": { + "postcss": "^7.0.14" + } + }, + "ieee754": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.12.tgz", + "integrity": "sha512-GguP+DRY+pJ3soyIiGPTvdiVXjZ+DbXOxGpXn3eMvNW4x4irjqXm4wHKscC+TfxSJ0yw/S1F24tqdMNsMZTiLA==", + "dev": true + }, + "iferr": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", + "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=", + "dev": true + }, + "ignore": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", + "dev": true + }, + "ignore-walk": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz", + "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", + "dev": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "immutable": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.8.2.tgz", + "integrity": "sha1-wkOZUUVbs5kT2vKBN28VMOEErfM=", + "dev": true + }, + "import-cwd": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz", + "integrity": "sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk=", + "dev": true, + "requires": { + "import-from": "^2.1.0" + } + }, + "import-fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", + "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", + "dev": true, + "requires": { + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + } + }, + "import-from": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-from/-/import-from-2.1.0.tgz", + "integrity": "sha1-M1238qev/VOqpHHUuAId7ja387E=", + "dev": true, + "requires": { + "resolve-from": "^3.0.0" + } + }, + "import-local": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", + "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", + "dev": true, + "requires": { + "pkg-dir": "^3.0.0", + "resolve-cwd": "^2.0.0" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", + "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.1.0.tgz", + "integrity": "sha512-H2RyIJ7+A3rjkwKC2l5GGtU4H1vkxKCAGsWasNVd0Set+6i4znxbWy6/j16YDPJDWxhsgZiKAstMEP8wCdSpjA==", + "dev": true + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + } + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "indent-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", + "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", + "dev": true + }, + "indexes-of": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", + "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=", + "dev": true + }, + "indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "dev": true + }, + "inquirer": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.0.6.tgz", + "integrity": "sha1-4EqqnQW3o8ubD0B9BDdfBEcZA0c=", + "requires": { + "ansi-escapes": "^1.1.0", + "chalk": "^1.0.0", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^2.0.1", + "figures": "^2.0.0", + "lodash": "^4.3.0", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rx": "^4.1.0", + "string-width": "^2.0.0", + "strip-ansi": "^3.0.0", + "through": "^2.3.6" + } + }, + "insight": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/insight/-/insight-0.10.1.tgz", + "integrity": "sha512-kLGeYQkh18f8KuC68QKdi0iwUcIaayJVB/STpX7x452/7pAUm1yfG4giJwcxbrTh0zNYtc8kBR+6maLMOzglOQ==", + "dev": true, + "requires": { + "async": "^2.1.4", + "chalk": "^2.3.0", + "conf": "^1.3.1", + "inquirer": "^5.0.0", + "lodash.debounce": "^4.0.8", + "os-name": "^2.0.1", + "request": "^2.74.0", + "tough-cookie": "^2.0.0", + "uuid": "^3.0.0" + }, + "dependencies": { + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true + }, + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz", + "integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==", + "dev": true, + "requires": { + "lodash": "^4.17.11" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "conf": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/conf/-/conf-1.4.0.tgz", + "integrity": "sha512-bzlVWS2THbMetHqXKB8ypsXN4DQ/1qopGwNJi1eYbpwesJcd86FBjFciCQX/YwAhp9bM7NVnPFqZ5LpV7gP0Dg==", + "dev": true, + "requires": { + "dot-prop": "^4.1.0", + "env-paths": "^1.0.0", + "make-dir": "^1.0.0", + "pkg-up": "^2.0.0", + "write-file-atomic": "^2.3.0" + } + }, + "inquirer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-5.2.0.tgz", + "integrity": "sha512-E9BmnJbAKLPGonz0HeWHtbKf+EeSP93paWO3ZYoUpq/aowXvYGjjCSuashhXPpzbArIjBbji39THkxTz9ZeEUQ==", + "dev": true, + "requires": { + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.0", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^2.1.0", + "figures": "^2.0.0", + "lodash": "^4.3.0", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rxjs": "^5.5.2", + "string-width": "^2.1.0", + "strip-ansi": "^4.0.0", + "through": "^2.3.6" + } + }, + "rxjs": { + "version": "5.5.12", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.12.tgz", + "integrity": "sha512-xx2itnL5sBbqeeiVgNPVuQQ1nC8Jp2WfNJhXWHmElW9YmrpS9UVnNzhP3EH3HFqexO5Tlp8GhYY+WEcqcVMvGw==", + "dev": true, + "requires": { + "symbol-observable": "1.0.1" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "symbol-observable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.1.tgz", + "integrity": "sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ=", + "dev": true + } + } + }, + "internal-ip": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-3.0.1.tgz", + "integrity": "sha512-NXXgESC2nNVtU+pqmC9e6R8B1GpKxzsAQhffvh5AL79qKnodd+L7tnEQmTiUAVngqLalPbSqRA7XGIEL5nCd0Q==", + "dev": true, + "requires": { + "default-gateway": "^2.6.0", + "ipaddr.js": "^1.5.2" + } + }, + "interpret": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", + "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==", + "dev": true + }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dev": true, + "requires": { + "loose-envify": "^1.0.0" + } + }, + "invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", + "dev": true + }, + "ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", + "dev": true + }, + "ip-regex": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", + "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", + "dev": true + }, + "ipaddr.js": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz", + "integrity": "sha1-6qM9bd16zo9/b+DJygRA5wZzix4=", + "dev": true + }, + "is-absolute-url": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz", + "integrity": "sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=", + "dev": true + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-callable": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", + "dev": true + }, + "is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, + "requires": { + "ci-info": "^2.0.0" + } + }, + "is-color-stop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-color-stop/-/is-color-stop-1.1.0.tgz", + "integrity": "sha1-z/9HGu5N1cnhWFmPvhKWe1za00U=", + "dev": true, + "requires": { + "css-color-names": "^0.0.4", + "hex-color-regex": "^1.1.0", + "hsl-regex": "^1.0.0", + "hsla-regex": "^1.0.0", + "rgb-regex": "^1.0.1", + "rgba-regex": "^1.0.0" + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-date-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", + "dev": true + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "is-directory": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", + "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", + "dev": true + }, + "is-dotfile": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", + "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=", + "dev": true + }, + "is-equal-shallow": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", + "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", + "dev": true, + "requires": { + "is-primitive": "^2.0.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + }, + "is-generator-fn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.0.0.tgz", + "integrity": "sha512-elzyIdM7iKoFHzcrndIqjYomImhxrFRnGP3galODoII4TB9gI7mZ+FnlLQmmjf27SxHS2gKEeyhX5/+YRS6H9g==", + "dev": true + }, + "is-glob": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz", + "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-number-like": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/is-number-like/-/is-number-like-1.0.8.tgz", + "integrity": "sha512-6rZi3ezCyFcn5L71ywzz2bS5b2Igl1En3eTlZlvKjpz1n3IZLAYMbKYAIQgFmEu0GENg92ziU/faEOA/aixjbA==", + "dev": true, + "requires": { + "lodash.isfinite": "^3.3.2" + } + }, + "is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", + "dev": true + }, + "is-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", + "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=", + "dev": true + }, + "is-observable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-observable/-/is-observable-1.1.0.tgz", + "integrity": "sha512-NqCa4Sa2d+u7BWc6CukaObG3Fh+CU9bvixbpcXYhy2VvYS7vVGIdAgnIS5Ks3A/cqk4rebLJ9s8zBstT2aKnIA==", + "dev": true, + "requires": { + "symbol-observable": "^1.1.0" + } + }, + "is-path-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", + "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", + "dev": true + }, + "is-path-in-cwd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", + "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", + "dev": true, + "requires": { + "is-path-inside": "^1.0.0" + } + }, + "is-path-inside": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", + "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", + "dev": true, + "requires": { + "path-is-inside": "^1.0.1" + } + }, + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", + "dev": true + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-posix-bracket": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", + "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=", + "dev": true + }, + "is-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", + "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", + "dev": true + }, + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=" + }, + "is-regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", + "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "dev": true, + "requires": { + "has": "^1.0.1" + } + }, + "is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=", + "dev": true + }, + "is-resolvable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", + "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", + "dev": true + }, + "is-retry-allowed": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz", + "integrity": "sha1-EaBgVotnM5REAz0BJaYaINVk+zQ=", + "dev": true + }, + "is-scoped": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-scoped/-/is-scoped-1.0.0.tgz", + "integrity": "sha1-RJypgpnnEwOCViieyytUDcQ3yzA=", + "dev": true, + "requires": { + "scoped-regex": "^1.0.0" + } + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" + }, + "is-svg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-3.0.0.tgz", + "integrity": "sha512-gi4iHK53LR2ujhLVVj+37Ykh9GLqYHX6JOVXbLAucaG/Cqw9xwdFOjDM2qeifLs1sF1npXXFvDu0r5HNgCMrzQ==", + "dev": true, + "requires": { + "html-comment-regex": "^1.1.0" + } + }, + "is-symbol": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", + "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", + "dev": true, + "requires": { + "has-symbols": "^1.0.0" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "dev": true + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isbinaryfile": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.3.tgz", + "integrity": "sha512-8cJBL5tTd2OS0dM4jz07wQd5g0dCCqIhUxPIGtZfa5L6hWlvV5MHTITy/DBAsF+Oe2LS1X3krBUhNwaGUWpWxw==", + "dev": true, + "requires": { + "buffer-alloc": "^1.2.0" + } + }, + "isemail": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/isemail/-/isemail-3.2.0.tgz", + "integrity": "sha512-zKqkK+O+dGqevc93KNsbZ/TqTUFd46MwWjYOoMrjIMZ51eU7DtQG3Wmd9SQQT7i7RVnuTPEiYEWHU3MSbxC1Tg==", + "dev": true, + "requires": { + "punycode": "2.x.x" + } + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "istanbul-api": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/istanbul-api/-/istanbul-api-2.1.1.tgz", + "integrity": "sha512-kVmYrehiwyeBAk/wE71tW6emzLiHGjYIiDrc8sfyty4F8M02/lrgXSm+R1kXysmF20zArvmZXjlE/mg24TVPJw==", + "dev": true, + "requires": { + "async": "^2.6.1", + "compare-versions": "^3.2.1", + "fileset": "^2.0.3", + "istanbul-lib-coverage": "^2.0.3", + "istanbul-lib-hook": "^2.0.3", + "istanbul-lib-instrument": "^3.1.0", + "istanbul-lib-report": "^2.0.4", + "istanbul-lib-source-maps": "^3.0.2", + "istanbul-reports": "^2.1.1", + "js-yaml": "^3.12.0", + "make-dir": "^1.3.0", + "minimatch": "^3.0.4", + "once": "^1.4.0" + }, + "dependencies": { + "async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz", + "integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==", + "dev": true, + "requires": { + "lodash": "^4.17.11" + } + } + } + }, + "istanbul-lib-coverage": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", + "integrity": "sha512-dKWuzRGCs4G+67VfW9pBFFz2Jpi4vSp/k7zBcJ888ofV5Mi1g5CUML5GvMvV6u9Cjybftu+E8Cgp+k0dI1E5lw==", + "dev": true + }, + "istanbul-lib-hook": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-2.0.3.tgz", + "integrity": "sha512-CLmEqwEhuCYtGcpNVJjLV1DQyVnIqavMLFHV/DP+np/g3qvdxu3gsPqYoJMXm15sN84xOlckFB3VNvRbf5yEgA==", + "dev": true, + "requires": { + "append-transform": "^1.0.0" + } + }, + "istanbul-lib-instrument": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.1.0.tgz", + "integrity": "sha512-ooVllVGT38HIk8MxDj/OIHXSYvH+1tq/Vb38s8ixt9GoJadXska4WkGY+0wkmtYCZNYtaARniH/DixUGGLZ0uA==", + "dev": true, + "requires": { + "@babel/generator": "^7.0.0", + "@babel/parser": "^7.0.0", + "@babel/template": "^7.0.0", + "@babel/traverse": "^7.0.0", + "@babel/types": "^7.0.0", + "istanbul-lib-coverage": "^2.0.3", + "semver": "^5.5.0" + } + }, + "istanbul-lib-report": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.4.tgz", + "integrity": "sha512-sOiLZLAWpA0+3b5w5/dq0cjm2rrNdAfHWaGhmn7XEFW6X++IV9Ohn+pnELAl9K3rfpaeBfbmH9JU5sejacdLeA==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^2.0.3", + "make-dir": "^1.3.0", + "supports-color": "^6.0.0" + }, + "dependencies": { + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "istanbul-lib-source-maps": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.2.tgz", + "integrity": "sha512-JX4v0CiKTGp9fZPmoxpu9YEkPbEqCqBbO3403VabKjH+NRXo72HafD5UgnjTEqHL2SAjaZK1XDuDOkn6I5QVfQ==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^2.0.3", + "make-dir": "^1.3.0", + "rimraf": "^2.6.2", + "source-map": "^0.6.1" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "istanbul-reports": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.1.1.tgz", + "integrity": "sha512-FzNahnidyEPBCI0HcufJoSEoKykesRlFcSzQqjH9x0+LC8tnnE/p/90PBLu8iZTxr8yYZNyTtiAujUqyN+CIxw==", + "dev": true, + "requires": { + "handlebars": "^4.1.0" + } + }, + "istextorbinary": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-2.5.1.tgz", + "integrity": "sha512-pv/JNPWnfpwGjPx7JrtWTwsWsxkrK3fNzcEVnt92YKEIErps4Fsk49+qzCe9iQF2hjqK8Naqf8P9kzoeCuQI1g==", + "dev": true, + "requires": { + "binaryextensions": "^2.1.2", + "editions": "^2.1.3", + "textextensions": "^2.4.0" + } + }, + "isurl": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz", + "integrity": "sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==", + "dev": true, + "requires": { + "has-to-string-tag-x": "^1.2.0", + "is-object": "^1.0.1" + } + }, + "jest": { + "version": "24.1.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-24.1.0.tgz", + "integrity": "sha512-+q91L65kypqklvlRFfXfdzUKyngQLOcwGhXQaLmVHv+d09LkNXuBuGxlofTFW42XMzu3giIcChchTsCNUjQ78A==", + "dev": true, + "requires": { + "import-local": "^2.0.0", + "jest-cli": "^24.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "camelcase": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.2.0.tgz", + "integrity": "sha512-IXFsBS2pC+X0j0N/GE7Dm7j3bsEBp+oTpb7F50dwEVX7rf3IgwO9XatnegTsDtniKCUtEJH4fSU6Asw7uoVLfQ==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "cliui": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", + "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", + "dev": true, + "requires": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", + "wrap-ansi": "^2.0.0" + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "invert-kv": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", + "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", + "dev": true + }, + "jest-cli": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-24.5.0.tgz", + "integrity": "sha512-P+Jp0SLO4KWN0cGlNtC7JV0dW1eSFR7eRpoOucP2UM0sqlzp/bVHeo71Omonvigrj9AvCKy7NtQANtqJ7FXz8g==", + "dev": true, + "requires": { + "@jest/core": "^24.5.0", + "@jest/test-result": "^24.5.0", + "@jest/types": "^24.5.0", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "import-local": "^2.0.0", + "is-ci": "^2.0.0", + "jest-config": "^24.5.0", + "jest-util": "^24.5.0", + "jest-validate": "^24.5.0", + "prompts": "^2.0.1", + "realpath-native": "^1.1.0", + "yargs": "^12.0.2" + } + }, + "lcid": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", + "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", + "dev": true, + "requires": { + "invert-kv": "^2.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "mem": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-4.2.0.tgz", + "integrity": "sha512-5fJxa68urlY0Ir8ijatKa3eRz5lwXnRCTvo9+TbTGAuTFJOwpGcY0X05moBd0nW45965Njt4CDI2GFQoG8DvqA==", + "dev": true, + "requires": { + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^2.0.0", + "p-is-promise": "^2.0.0" + } + }, + "mimic-fn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.0.0.tgz", + "integrity": "sha512-jbex9Yd/3lmICXwYT6gA/j2mNQGU48wCh/VzRd+/Y/PjYQtlg1gLMdZqvu9s/xH7qKvngxRObl56XZR609IMbA==", + "dev": true + }, + "os-locale": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", + "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", + "dev": true, + "requires": { + "execa": "^1.0.0", + "lcid": "^2.0.0", + "mem": "^4.0.0" + } + }, + "p-limit": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", + "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.1.0.tgz", + "integrity": "sha512-H2RyIJ7+A3rjkwKC2l5GGtU4H1vkxKCAGsWasNVd0Set+6i4znxbWy6/j16YDPJDWxhsgZiKAstMEP8wCdSpjA==", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "yargs": { + "version": "12.0.5", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", + "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", + "dev": true, + "requires": { + "cliui": "^4.0.0", + "decamelize": "^1.2.0", + "find-up": "^3.0.0", + "get-caller-file": "^1.0.1", + "os-locale": "^3.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1 || ^4.0.0", + "yargs-parser": "^11.1.1" + } + }, + "yargs-parser": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", + "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "jest-changed-files": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-24.5.0.tgz", + "integrity": "sha512-Ikl29dosYnTsH9pYa1Tv9POkILBhN/TLZ37xbzgNsZ1D2+2n+8oEZS2yP1BrHn/T4Rs4Ggwwbp/x8CKOS5YJOg==", + "dev": true, + "requires": { + "@jest/types": "^24.5.0", + "execa": "^1.0.0", + "throat": "^4.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + } + } + }, + "jest-config": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-24.5.0.tgz", + "integrity": "sha512-t2UTh0Z2uZhGBNVseF8wA2DS2SuBiLOL6qpLq18+OZGfFUxTM7BzUVKyHFN/vuN+s/aslY1COW95j1Rw81huOQ==", + "dev": true, + "requires": { + "@babel/core": "^7.1.0", + "@jest/types": "^24.5.0", + "babel-jest": "^24.5.0", + "chalk": "^2.0.1", + "glob": "^7.1.1", + "jest-environment-jsdom": "^24.5.0", + "jest-environment-node": "^24.5.0", + "jest-get-type": "^24.3.0", + "jest-jasmine2": "^24.5.0", + "jest-regex-util": "^24.3.0", + "jest-resolve": "^24.5.0", + "jest-util": "^24.5.0", + "jest-validate": "^24.5.0", + "micromatch": "^3.1.10", + "pretty-format": "^24.5.0", + "realpath-native": "^1.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "jest-diff": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-24.5.0.tgz", + "integrity": "sha512-mCILZd9r7zqL9Uh6yNoXjwGQx0/J43OD2vvWVKwOEOLZliQOsojXwqboubAQ+Tszrb6DHGmNU7m4whGeB9YOqw==", + "dev": true, + "requires": { + "chalk": "^2.0.1", + "diff-sequences": "^24.3.0", + "jest-get-type": "^24.3.0", + "pretty-format": "^24.5.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "jest-docblock": { + "version": "24.3.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-24.3.0.tgz", + "integrity": "sha512-nlANmF9Yq1dufhFlKG9rasfQlrY7wINJbo3q01tu56Jv5eBU5jirylhF2O5ZBnLxzOVBGRDz/9NAwNyBtG4Nyg==", + "dev": true, + "requires": { + "detect-newline": "^2.1.0" + } + }, + "jest-each": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-24.5.0.tgz", + "integrity": "sha512-6gy3Kh37PwIT5sNvNY2VchtIFOOBh8UCYnBlxXMb5sr5wpJUDPTUATX2Axq1Vfk+HWTMpsYPeVYp4TXx5uqUBw==", + "dev": true, + "requires": { + "@jest/types": "^24.5.0", + "chalk": "^2.0.1", + "jest-get-type": "^24.3.0", + "jest-util": "^24.5.0", + "pretty-format": "^24.5.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "jest-environment-jsdom": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-24.5.0.tgz", + "integrity": "sha512-62Ih5HbdAWcsqBx2ktUnor/mABBo1U111AvZWcLKeWN/n/gc5ZvDBKe4Og44fQdHKiXClrNGC6G0mBo6wrPeGQ==", + "dev": true, + "requires": { + "@jest/environment": "^24.5.0", + "@jest/fake-timers": "^24.5.0", + "@jest/types": "^24.5.0", + "jest-mock": "^24.5.0", + "jest-util": "^24.5.0", + "jsdom": "^11.5.1" + } + }, + "jest-environment-node": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-24.5.0.tgz", + "integrity": "sha512-du6FuyWr/GbKLsmAbzNF9mpr2Iu2zWSaq/BNHzX+vgOcts9f2ayXBweS7RAhr+6bLp6qRpMB6utAMF5Ygktxnw==", + "dev": true, + "requires": { + "@jest/environment": "^24.5.0", + "@jest/fake-timers": "^24.5.0", + "@jest/types": "^24.5.0", + "jest-mock": "^24.5.0", + "jest-util": "^24.5.0" + } + }, + "jest-get-type": { + "version": "24.3.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.3.0.tgz", + "integrity": "sha512-HYF6pry72YUlVcvUx3sEpMRwXEWGEPlJ0bSPVnB3b3n++j4phUEoSPcS6GC0pPJ9rpyPSe4cb5muFo6D39cXow==", + "dev": true + }, + "jest-haste-map": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-24.5.0.tgz", + "integrity": "sha512-mb4Yrcjw9vBgSvobDwH8QUovxApdimGcOkp+V1ucGGw4Uvr3VzZQBJhNm1UY3dXYm4XXyTW2G7IBEZ9pM2ggRQ==", + "dev": true, + "requires": { + "@jest/types": "^24.5.0", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.1.15", + "invariant": "^2.2.4", + "jest-serializer": "^24.4.0", + "jest-util": "^24.5.0", + "jest-worker": "^24.4.0", + "micromatch": "^3.1.10", + "sane": "^4.0.3" + } + }, + "jest-jasmine2": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-24.5.0.tgz", + "integrity": "sha512-sfVrxVcx1rNUbBeyIyhkqZ4q+seNKyAG6iM0S2TYBdQsXjoFDdqWFfsUxb6uXSsbimbXX/NMkJIwUZ1uT9+/Aw==", + "dev": true, + "requires": { + "@babel/traverse": "^7.1.0", + "@jest/environment": "^24.5.0", + "@jest/test-result": "^24.5.0", + "@jest/types": "^24.5.0", + "chalk": "^2.0.1", + "co": "^4.6.0", + "expect": "^24.5.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^24.5.0", + "jest-matcher-utils": "^24.5.0", + "jest-message-util": "^24.5.0", + "jest-runtime": "^24.5.0", + "jest-snapshot": "^24.5.0", + "jest-util": "^24.5.0", + "pretty-format": "^24.5.0", + "throat": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "jest-junit": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jest-junit/-/jest-junit-6.2.1.tgz", + "integrity": "sha512-zMbwKzZGo9TQOjdBUNQdTEf81QvOrwiQtLIUSEyCwPXYx/G/DJGXEJcqs8viXxn6poJ4Xh4pYGDLD0DKDwtfVA==", + "dev": true, + "requires": { + "jest-validate": "^24.0.0", + "mkdirp": "^0.5.1", + "strip-ansi": "^4.0.0", + "xml": "^1.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "jest-leak-detector": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-24.5.0.tgz", + "integrity": "sha512-LZKBjGovFRx3cRBkqmIg+BZnxbrLqhQl09IziMk3oeh1OV81Hg30RUIx885mq8qBv1PA0comB9bjKcuyNO1bCQ==", + "dev": true, + "requires": { + "pretty-format": "^24.5.0" + } + }, + "jest-matcher-utils": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-24.5.0.tgz", + "integrity": "sha512-QM1nmLROjLj8GMGzg5VBra3I9hLpjMPtF1YqzQS3rvWn2ltGZLrGAO1KQ9zUCVi5aCvrkbS5Ndm2evIP9yZg1Q==", + "dev": true, + "requires": { + "chalk": "^2.0.1", + "jest-diff": "^24.5.0", + "jest-get-type": "^24.3.0", + "pretty-format": "^24.5.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "jest-message-util": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.5.0.tgz", + "integrity": "sha512-6ZYgdOojowCGiV0D8WdgctZEAe+EcFU+KrVds+0ZjvpZurUW2/oKJGltJ6FWY2joZwYXN5VL36GPV6pNVRqRnQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@jest/test-result": "^24.5.0", + "@jest/types": "^24.5.0", + "@types/stack-utils": "^1.0.1", + "chalk": "^2.0.1", + "micromatch": "^3.1.10", + "slash": "^2.0.0", + "stack-utils": "^1.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "jest-mock": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-24.5.0.tgz", + "integrity": "sha512-ZnAtkWrKf48eERgAOiUxVoFavVBziO2pAi2MfZ1+bGXVkDfxWLxU0//oJBkgwbsv6OAmuLBz4XFFqvCFMqnGUw==", + "dev": true, + "requires": { + "@jest/types": "^24.5.0" + } + }, + "jest-pnp-resolver": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.1.tgz", + "integrity": "sha512-pgFw2tm54fzgYvc/OHrnysABEObZCUNFnhjoRjaVOCN8NYc032/gVjPaHD4Aq6ApkSieWtfKAFQtmDKAmhupnQ==", + "dev": true + }, + "jest-preset-angular": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/jest-preset-angular/-/jest-preset-angular-6.0.2.tgz", + "integrity": "sha512-uhrllY41tUvkeR41aX9bU5w3/EvvmwZiJ3UitDhRSEJL2Jvq2N/xKlmw7qvlZoGZnciFjOUJ2WDKv5fmCrvnQA==", + "dev": true, + "requires": { + "@types/jest": "^23.3.1", + "jest-zone-patch": ">=0.0.9 <1.0.0", + "ts-jest": "~23.1.3" + }, + "dependencies": { + "@types/jest": { + "version": "23.3.14", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-23.3.14.tgz", + "integrity": "sha512-Q5hTcfdudEL2yOmluA1zaSyPbzWPmJ3XfSWeP3RyoYvS9hnje1ZyagrZOuQ6+1nQC1Gw+7gap3pLNL3xL6UBug==", + "dev": true + } + } + }, + "jest-regex-util": { + "version": "24.3.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-24.3.0.tgz", + "integrity": "sha512-tXQR1NEOyGlfylyEjg1ImtScwMq8Oh3iJbGTjN7p0J23EuVX1MA8rwU69K4sLbCmwzgCUbVkm0FkSF9TdzOhtg==", + "dev": true + }, + "jest-resolve": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.5.0.tgz", + "integrity": "sha512-ZIfGqLX1Rg8xJpQqNjdoO8MuxHV1q/i2OO1hLXjgCWFWs5bsedS8UrOdgjUqqNae6DXA+pCyRmdcB7lQEEbXew==", + "dev": true, + "requires": { + "@jest/types": "^24.5.0", + "browser-resolve": "^1.11.3", + "chalk": "^2.0.1", + "jest-pnp-resolver": "^1.2.1", + "realpath-native": "^1.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "jest-resolve-dependencies": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-24.5.0.tgz", + "integrity": "sha512-dRVM1D+gWrFfrq2vlL5P9P/i8kB4BOYqYf3S7xczZ+A6PC3SgXYSErX/ScW/469pWMboM1uAhgLF+39nXlirCQ==", + "dev": true, + "requires": { + "@jest/types": "^24.5.0", + "jest-regex-util": "^24.3.0", + "jest-snapshot": "^24.5.0" + } + }, + "jest-runner": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-24.5.0.tgz", + "integrity": "sha512-oqsiS9TkIZV5dVkD+GmbNfWBRPIvxqmlTQ+AQUJUQ07n+4xTSDc40r+aKBynHw9/tLzafC00DIbJjB2cOZdvMA==", + "dev": true, + "requires": { + "@jest/console": "^24.3.0", + "@jest/environment": "^24.5.0", + "@jest/test-result": "^24.5.0", + "@jest/types": "^24.5.0", + "chalk": "^2.4.2", + "exit": "^0.1.2", + "graceful-fs": "^4.1.15", + "jest-config": "^24.5.0", + "jest-docblock": "^24.3.0", + "jest-haste-map": "^24.5.0", + "jest-jasmine2": "^24.5.0", + "jest-leak-detector": "^24.5.0", + "jest-message-util": "^24.5.0", + "jest-resolve": "^24.5.0", + "jest-runtime": "^24.5.0", + "jest-util": "^24.5.0", + "jest-worker": "^24.4.0", + "source-map-support": "^0.5.6", + "throat": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "jest-runtime": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-24.5.0.tgz", + "integrity": "sha512-GTFHzfLdwpaeoDPilNpBrorlPoNZuZrwKKzKJs09vWwHo+9TOsIIuszK8cWOuKC7ss07aN1922Ge8fsGdsqCuw==", + "dev": true, + "requires": { + "@jest/console": "^24.3.0", + "@jest/environment": "^24.5.0", + "@jest/source-map": "^24.3.0", + "@jest/transform": "^24.5.0", + "@jest/types": "^24.5.0", + "@types/yargs": "^12.0.2", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.1.15", + "jest-config": "^24.5.0", + "jest-haste-map": "^24.5.0", + "jest-message-util": "^24.5.0", + "jest-mock": "^24.5.0", + "jest-regex-util": "^24.3.0", + "jest-resolve": "^24.5.0", + "jest-snapshot": "^24.5.0", + "jest-util": "^24.5.0", + "jest-validate": "^24.5.0", + "realpath-native": "^1.1.0", + "slash": "^2.0.0", + "strip-bom": "^3.0.0", + "yargs": "^12.0.2" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "camelcase": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.2.0.tgz", + "integrity": "sha512-IXFsBS2pC+X0j0N/GE7Dm7j3bsEBp+oTpb7F50dwEVX7rf3IgwO9XatnegTsDtniKCUtEJH4fSU6Asw7uoVLfQ==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "cliui": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", + "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", + "dev": true, + "requires": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", + "wrap-ansi": "^2.0.0" + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "invert-kv": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", + "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", + "dev": true + }, + "lcid": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", + "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", + "dev": true, + "requires": { + "invert-kv": "^2.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "mem": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-4.2.0.tgz", + "integrity": "sha512-5fJxa68urlY0Ir8ijatKa3eRz5lwXnRCTvo9+TbTGAuTFJOwpGcY0X05moBd0nW45965Njt4CDI2GFQoG8DvqA==", + "dev": true, + "requires": { + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^2.0.0", + "p-is-promise": "^2.0.0" + } + }, + "mimic-fn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.0.0.tgz", + "integrity": "sha512-jbex9Yd/3lmICXwYT6gA/j2mNQGU48wCh/VzRd+/Y/PjYQtlg1gLMdZqvu9s/xH7qKvngxRObl56XZR609IMbA==", + "dev": true + }, + "os-locale": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", + "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", + "dev": true, + "requires": { + "execa": "^1.0.0", + "lcid": "^2.0.0", + "mem": "^4.0.0" + } + }, + "p-limit": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", + "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.1.0.tgz", + "integrity": "sha512-H2RyIJ7+A3rjkwKC2l5GGtU4H1vkxKCAGsWasNVd0Set+6i4znxbWy6/j16YDPJDWxhsgZiKAstMEP8wCdSpjA==", + "dev": true + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "yargs": { + "version": "12.0.5", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", + "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", + "dev": true, + "requires": { + "cliui": "^4.0.0", + "decamelize": "^1.2.0", + "find-up": "^3.0.0", + "get-caller-file": "^1.0.1", + "os-locale": "^3.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1 || ^4.0.0", + "yargs-parser": "^11.1.1" + } + }, + "yargs-parser": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", + "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "jest-serializer": { + "version": "24.4.0", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-24.4.0.tgz", + "integrity": "sha512-k//0DtglVstc1fv+GY/VHDIjrtNjdYvYjMlbLUed4kxrE92sIUewOi5Hj3vrpB8CXfkJntRPDRjCrCvUhBdL8Q==", + "dev": true + }, + "jest-snapshot": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-24.5.0.tgz", + "integrity": "sha512-eBEeJb5ROk0NcpodmSKnCVgMOo+Qsu5z9EDl3tGffwPzK1yV37mjGWF2YeIz1NkntgTzP+fUL4s09a0+0dpVWA==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0", + "@jest/types": "^24.5.0", + "chalk": "^2.0.1", + "expect": "^24.5.0", + "jest-diff": "^24.5.0", + "jest-matcher-utils": "^24.5.0", + "jest-message-util": "^24.5.0", + "jest-resolve": "^24.5.0", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "pretty-format": "^24.5.0", + "semver": "^5.5.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "jest-sonar-reporter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jest-sonar-reporter/-/jest-sonar-reporter-2.0.0.tgz", + "integrity": "sha512-ZervDCgEX5gdUbdtWsjdipLN3bKJwpxbvhkYNXTAYvAckCihobSLr9OT/IuyNIRT1EZMDDwR6DroWtrq+IL64w==", + "dev": true, + "requires": { + "xml": "^1.0.1" + } + }, + "jest-util": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-24.5.0.tgz", + "integrity": "sha512-Xy8JsD0jvBz85K7VsTIQDuY44s+hYJyppAhcsHsOsGisVtdhar6fajf2UOf2mEVEgh15ZSdA0zkCuheN8cbr1Q==", + "dev": true, + "requires": { + "@jest/console": "^24.3.0", + "@jest/fake-timers": "^24.5.0", + "@jest/source-map": "^24.3.0", + "@jest/test-result": "^24.5.0", + "@jest/types": "^24.5.0", + "@types/node": "*", + "callsites": "^3.0.0", + "chalk": "^2.0.1", + "graceful-fs": "^4.1.15", + "is-ci": "^2.0.0", + "mkdirp": "^0.5.1", + "slash": "^2.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "callsites": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.0.0.tgz", + "integrity": "sha512-tWnkwu9YEq2uzlBDI4RcLn8jrFvF9AOi8PxDNU3hZZjJcjkcRAq3vCI+vZcg1SuxISDYe86k9VZFwAxDiJGoAw==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "jest-validate": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-24.5.0.tgz", + "integrity": "sha512-gg0dYszxjgK2o11unSIJhkOFZqNRQbWOAB2/LOUdsd2LfD9oXiMeuee8XsT0iRy5EvSccBgB4h/9HRbIo3MHgQ==", + "dev": true, + "requires": { + "@jest/types": "^24.5.0", + "camelcase": "^5.0.0", + "chalk": "^2.0.1", + "jest-get-type": "^24.3.0", + "leven": "^2.1.0", + "pretty-format": "^24.5.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "camelcase": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.2.0.tgz", + "integrity": "sha512-IXFsBS2pC+X0j0N/GE7Dm7j3bsEBp+oTpb7F50dwEVX7rf3IgwO9XatnegTsDtniKCUtEJH4fSU6Asw7uoVLfQ==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "jest-watcher": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-24.5.0.tgz", + "integrity": "sha512-/hCpgR6bg0nKvD3nv4KasdTxuhwfViVMHUATJlnGCD0r1QrmIssimPbmc5KfAQblAVxkD8xrzuij9vfPUk1/rA==", + "dev": true, + "requires": { + "@jest/test-result": "^24.5.0", + "@jest/types": "^24.5.0", + "@types/node": "*", + "@types/yargs": "^12.0.9", + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.1", + "jest-util": "^24.5.0", + "string-length": "^2.0.0" + }, + "dependencies": { + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "jest-worker": { + "version": "24.4.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.4.0.tgz", + "integrity": "sha512-BH9X/klG9vxwoO99ZBUbZFfV8qO0XNZ5SIiCyYK2zOuJBl6YJVAeNIQjcoOVNu4HGEHeYEKsUWws8kSlSbZ9YQ==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^1.0.1", + "supports-color": "^6.1.0" + }, + "dependencies": { + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "jest-zone-patch": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/jest-zone-patch/-/jest-zone-patch-0.0.10.tgz", + "integrity": "sha512-K5uHLHgMgi2Eyj74gbY+xSeGGekb5U48bXsgDwgipRbFdaekyZK+TAcp8auamqU4UjrAt5S4sIUZz/2bBNyTTA==", + "dev": true + }, + "jhipster-core": { + "version": "3.6.11", + "resolved": "https://registry.npmjs.org/jhipster-core/-/jhipster-core-3.6.11.tgz", + "integrity": "sha512-OibJay1+nwKk+mfRfuTrt2rW2h7BmGNfKWR7TQO4oYqG+I096EvJxZkIMCcjA9KuKLOZvnzfEi4UbtKyRTmHkg==", + "dev": true, + "requires": { + "chevrotain": "4.2.0", + "fs-extra": "7.0.1", + "lodash": "4.17.11", + "winston": "3.2.1" + }, + "dependencies": { + "fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + } + } + }, + "joi": { + "version": "11.4.0", + "resolved": "https://registry.npmjs.org/joi/-/joi-11.4.0.tgz", + "integrity": "sha512-O7Uw+w/zEWgbL6OcHbyACKSj0PkQeUgmehdoXVSxt92QFCq4+1390Rwh5moI2K/OgC7D8RHRZqHZxT2husMJHA==", + "dev": true, + "requires": { + "hoek": "4.x.x", + "isemail": "3.x.x", + "topo": "2.x.x" + } + }, + "js-object-pretty-print": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/js-object-pretty-print/-/js-object-pretty-print-0.3.0.tgz", + "integrity": "sha1-RnDkUAZu4ezPNRdMfRl/WqOLz3Q=", + "dev": true + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + }, + "js-yaml": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz", + "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true + }, + "jsdom": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz", + "integrity": "sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw==", + "dev": true, + "requires": { + "abab": "^2.0.0", + "acorn": "^5.5.3", + "acorn-globals": "^4.1.0", + "array-equal": "^1.0.0", + "cssom": ">= 0.3.2 < 0.4.0", + "cssstyle": "^1.0.0", + "data-urls": "^1.0.0", + "domexception": "^1.0.1", + "escodegen": "^1.9.1", + "html-encoding-sniffer": "^1.0.2", + "left-pad": "^1.3.0", + "nwsapi": "^2.0.7", + "parse5": "4.0.0", + "pn": "^1.1.0", + "request": "^2.87.0", + "request-promise-native": "^1.0.5", + "sax": "^1.2.4", + "symbol-tree": "^3.2.2", + "tough-cookie": "^2.3.4", + "w3c-hr-time": "^1.0.1", + "webidl-conversions": "^4.0.2", + "whatwg-encoding": "^1.0.3", + "whatwg-mimetype": "^2.1.0", + "whatwg-url": "^6.4.1", + "ws": "^5.2.0", + "xml-name-validator": "^3.0.0" + }, + "dependencies": { + "ws": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", + "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0" + } + } + } + }, + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "dev": true + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", + "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", + "dev": true, + "requires": { + "jsonify": "~0.0.0" + } + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "json3": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", + "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=", + "dev": true + }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "jsonfile": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-3.0.1.tgz", + "integrity": "sha1-pezG9l9T9mLEQVx2daAzHQmS7GY=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", + "dev": true + }, + "jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", + "dev": true + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "jstransform": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/jstransform/-/jstransform-11.0.3.tgz", + "integrity": "sha1-CaeJk+CuTU70SH9hVakfYZDLQiM=", + "dev": true, + "requires": { + "base62": "^1.1.0", + "commoner": "^0.10.1", + "esprima-fb": "^15001.1.0-dev-harmony-fb", + "object-assign": "^2.0.0", + "source-map": "^0.4.2" + }, + "dependencies": { + "esprima-fb": { + "version": "15001.1.0-dev-harmony-fb", + "resolved": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-15001.1.0-dev-harmony-fb.tgz", + "integrity": "sha1-MKlHMDxrjV6VW+4rmbHSMyBqaQE=", + "dev": true + }, + "object-assign": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz", + "integrity": "sha1-Q8NuXVaf+OSBbE76i+AtJpZ8GKo=", + "dev": true + }, + "source-map": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "dev": true, + "requires": { + "amdefine": ">=0.0.4" + } + } + } + }, + "killable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", + "integrity": "sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==", + "dev": true + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + }, + "kleur": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.2.tgz", + "integrity": "sha512-3h7B2WRT5LNXOtQiAaWonilegHcPSf9nLVXlSTci8lu1dZUuui61+EsPEZqSVxY7rXYmB2DVKMQILxaO5WL61Q==", + "dev": true + }, + "kuler": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-1.0.1.tgz", + "integrity": "sha512-J9nVUucG1p/skKul6DU3PUZrhs0LPulNaeUOox0IyXDi8S4CztTHs1gQphhuZmzXG7VOQSf6NJfKuzteQLv9gQ==", + "dev": true, + "requires": { + "colornames": "^1.1.1" + } + }, + "last-call-webpack-plugin": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/last-call-webpack-plugin/-/last-call-webpack-plugin-3.0.0.tgz", + "integrity": "sha512-7KI2l2GIZa9p2spzPIVZBYyNKkN+e/SQPpnjlTiPhdbDW3F86tdKKELxKpzJ5sgU19wQWsACULZmpTPYHeWO5w==", + "dev": true, + "requires": { + "lodash": "^4.17.5", + "webpack-sources": "^1.1.0" + } + }, + "lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "dev": true, + "requires": { + "invert-kv": "^1.0.0" + } + }, + "left-pad": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz", + "integrity": "sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==", + "dev": true + }, + "leven": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz", + "integrity": "sha1-wuep93IJTe6dNCAq6KzORoeHVYA=", + "dev": true + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "limiter": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/limiter/-/limiter-1.1.4.tgz", + "integrity": "sha512-XCpr5bElgDI65vVgstP8TWjv6/QKWm9GU5UG0Pr5sLQ3QLo8NVKsioe+Jed5/3vFOe3IQuqE7DKwTvKQkjTHvg==", + "dev": true + }, + "lint-staged": { + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-8.1.3.tgz", + "integrity": "sha512-6TGkikL1B+6mIOuSNq2TV6oP21IhPMnV8q0cf9oYZ296ArTVNcbFh1l1pfVOHHbBIYLlziWNsQ2q45/ffmJ4AA==", + "dev": true, + "requires": { + "@iamstarkov/listr-update-renderer": "0.4.1", + "chalk": "^2.3.1", + "commander": "^2.14.1", + "cosmiconfig": "^5.0.2", + "debug": "^3.1.0", + "dedent": "^0.7.0", + "del": "^3.0.0", + "execa": "^1.0.0", + "find-parent-dir": "^0.3.0", + "g-status": "^2.0.2", + "is-glob": "^4.0.0", + "is-windows": "^1.0.2", + "listr": "^0.14.2", + "lodash": "^4.17.5", + "log-symbols": "^2.2.0", + "micromatch": "^3.1.8", + "npm-which": "^3.0.1", + "p-map": "^1.1.1", + "path-is-inside": "^1.0.2", + "pify": "^3.0.0", + "please-upgrade-node": "^3.0.2", + "staged-git-files": "1.1.2", + "string-argv": "^0.0.2", + "stringify-object": "^3.2.2", + "yup": "^0.26.10" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "listr": { + "version": "0.14.3", + "resolved": "https://registry.npmjs.org/listr/-/listr-0.14.3.tgz", + "integrity": "sha512-RmAl7su35BFd/xoMamRjpIE4j3v+L28o8CT5YhAXQJm1fD+1l9ngXY8JAQRJ+tFK2i5njvi0iRUKV09vPwA0iA==", + "dev": true, + "requires": { + "@samverschueren/stream-to-observable": "^0.3.0", + "is-observable": "^1.1.0", + "is-promise": "^2.1.0", + "is-stream": "^1.1.0", + "listr-silent-renderer": "^1.1.1", + "listr-update-renderer": "^0.5.0", + "listr-verbose-renderer": "^0.5.0", + "p-map": "^2.0.0", + "rxjs": "^6.3.3" + }, + "dependencies": { + "p-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.0.0.tgz", + "integrity": "sha512-GO107XdrSUmtHxVoi60qc9tUl/KkNKm+X2CF4P9amalpGxv5YqVPJNfSb0wcA+syCopkZvYYIzW8OVTQW59x/w==", + "dev": true + } + } + }, + "listr-silent-renderer": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz", + "integrity": "sha1-kktaN1cVN3C/Go4/v3S4u/P5JC4=", + "dev": true + }, + "listr-update-renderer": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/listr-update-renderer/-/listr-update-renderer-0.5.0.tgz", + "integrity": "sha512-tKRsZpKz8GSGqoI/+caPmfrypiaq+OQCbd+CovEC24uk1h952lVj5sC7SqyFUm+OaJ5HN/a1YLt5cit2FMNsFA==", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "cli-truncate": "^0.2.1", + "elegant-spinner": "^1.0.1", + "figures": "^1.7.0", + "indent-string": "^3.0.0", + "log-symbols": "^1.0.2", + "log-update": "^2.3.0", + "strip-ansi": "^3.0.1" + }, + "dependencies": { + "figures": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5", + "object-assign": "^4.1.0" + } + }, + "log-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", + "integrity": "sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg=", + "dev": true, + "requires": { + "chalk": "^1.0.0" + } + } + } + }, + "listr-verbose-renderer": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/listr-verbose-renderer/-/listr-verbose-renderer-0.5.0.tgz", + "integrity": "sha512-04PDPqSlsqIOaaaGZ+41vq5FejI9auqTInicFRndCBgE3bXG8D6W1I+mWhk+1nqbHmyhla/6BUrd5OSiHwKRXw==", + "dev": true, + "requires": { + "chalk": "^2.4.1", + "cli-cursor": "^2.1.0", + "date-fns": "^1.27.2", + "figures": "^2.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" + } + }, + "loader-runner": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", + "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==", + "dev": true + }, + "loader-utils": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", + "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^2.0.0", + "json5": "^1.0.1" + } + }, + "localtunnel": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/localtunnel/-/localtunnel-1.9.1.tgz", + "integrity": "sha512-HWrhOslklDvxgOGFLxi6fQVnvpl6XdX4sPscfqMZkzi3gtt9V7LKBWYvNUcpHSVvjwCQ6xzXacVvICNbNcyPnQ==", + "dev": true, + "requires": { + "axios": "0.17.1", + "debug": "2.6.9", + "openurl": "1.1.1", + "yargs": "6.6.0" + }, + "dependencies": { + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "dev": true + }, + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "requires": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + } + }, + "os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "dev": true, + "requires": { + "lcid": "^1.0.0" + } + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "requires": { + "pinkie-promise": "^2.0.0" + } + }, + "path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "dev": true, + "requires": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "dev": true, + "requires": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true, + "requires": { + "is-utf8": "^0.2.0" + } + }, + "which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=", + "dev": true + }, + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", + "dev": true + }, + "yargs": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-6.6.0.tgz", + "integrity": "sha1-eC7CHvQDNF+DCoCMo9UTr1YGUgg=", + "dev": true, + "requires": { + "camelcase": "^3.0.0", + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "os-locale": "^1.4.0", + "read-pkg-up": "^1.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^1.0.2", + "which-module": "^1.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^4.2.0" + } + }, + "yargs-parser": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-4.2.1.tgz", + "integrity": "sha1-KczqwNxPA8bIe0qfIX3RjJ90hxw=", + "dev": true, + "requires": { + "camelcase": "^3.0.0" + } + } + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" + }, + "lodash._reinterpolate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", + "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", + "dev": true + }, + "lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", + "dev": true + }, + "lodash.difference": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", + "integrity": "sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw=", + "dev": true + }, + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", + "dev": true + }, + "lodash.isfinite": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/lodash.isfinite/-/lodash.isfinite-3.3.2.tgz", + "integrity": "sha1-+4m2WpqAKBgz8LdHizpRBPiY67M=", + "dev": true + }, + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", + "dev": true + }, + "lodash.pad": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/lodash.pad/-/lodash.pad-4.5.1.tgz", + "integrity": "sha1-QzCUmoM6fI2iLMIPaibE1Z3runA=", + "dev": true + }, + "lodash.padend": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/lodash.padend/-/lodash.padend-4.6.1.tgz", + "integrity": "sha1-U8y6BH0G4VjTEfRdpiX05J5vFm4=", + "dev": true + }, + "lodash.padstart": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/lodash.padstart/-/lodash.padstart-4.6.1.tgz", + "integrity": "sha1-0uPuv/DZ05rVD1y9G1KnvOa7YRs=", + "dev": true + }, + "lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", + "dev": true + }, + "lodash.tail": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.tail/-/lodash.tail-4.1.1.tgz", + "integrity": "sha1-0jM6NtnncXyK0vfKyv7HwytERmQ=", + "dev": true + }, + "lodash.template": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.4.0.tgz", + "integrity": "sha1-5zoDhcg1VZF0bgILmWecaQ5o+6A=", + "dev": true, + "requires": { + "lodash._reinterpolate": "~3.0.0", + "lodash.templatesettings": "^4.0.0" + } + }, + "lodash.templatesettings": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.1.0.tgz", + "integrity": "sha1-K01OlbpEDZFf8IvImeRVNmZxMxY=", + "dev": true, + "requires": { + "lodash._reinterpolate": "~3.0.0" + } + }, + "lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=", + "dev": true + }, + "log-symbols": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "dev": true, + "requires": { + "chalk": "^2.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "log-update": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-2.3.0.tgz", + "integrity": "sha1-iDKP19HOeTiykoN0bwsbwSayRwg=", + "dev": true, + "requires": { + "ansi-escapes": "^3.0.0", + "cli-cursor": "^2.0.0", + "wrap-ansi": "^3.0.1" + }, + "dependencies": { + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true + }, + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "wrap-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-3.0.1.tgz", + "integrity": "sha1-KIoE2H7aXChuBg3+jxNc6NAH+Lo=", + "dev": true, + "requires": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0" + } + } + } + }, + "logform": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.1.2.tgz", + "integrity": "sha512-+lZh4OpERDBLqjiwDLpAWNQu6KMjnlXH2ByZwCuSqVPJletw0kTWJf5CgSNAUKn1KUkv3m2cUz/LK8zyEy7wzQ==", + "dev": true, + "requires": { + "colors": "^1.2.1", + "fast-safe-stringify": "^2.0.4", + "fecha": "^2.3.3", + "ms": "^2.1.1", + "triple-beam": "^1.3.0" + }, + "dependencies": { + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + } + } + }, + "loglevel": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.1.tgz", + "integrity": "sha1-4PyVEztu8nbNyIh82vJKpvFW+Po=", + "dev": true + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "loud-rejection": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", + "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", + "dev": true, + "requires": { + "currently-unhandled": "^0.4.1", + "signal-exit": "^3.0.0" + } + }, + "lower-case": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", + "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=", + "dev": true + }, + "lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "dev": true + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "macos-release": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/macos-release/-/macos-release-1.1.0.tgz", + "integrity": "sha512-mmLbumEYMi5nXReB9js3WGsB8UE6cDBWyIO62Z4DNx6GbRhDxHNjA1MlzSpJ2S2KM1wyiPRA0d19uHWYYvMHjA==", + "dev": true + }, + "magic-string": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.2.tgz", + "integrity": "sha512-iLs9mPjh9IuTtRsqqhNGYcZXGei0Nh/A4xirrsqW7c+QhKVFL2vm7U09ru6cHRD22azaP/wMDgI+HCqbETMTtg==", + "dev": true, + "requires": { + "sourcemap-codec": "^1.4.4" + } + }, + "make-dir": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "dev": true, + "requires": { + "pify": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "make-fetch-happen": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-4.0.1.tgz", + "integrity": "sha512-7R5ivfy9ilRJ1EMKIOziwrns9fGeAD4bAha8EB7BIiBBLHm2KeTUGCrICFt2rbHfzheTLynv50GnNTK1zDTrcQ==", + "dev": true, + "requires": { + "agentkeepalive": "^3.4.1", + "cacache": "^11.0.1", + "http-cache-semantics": "^3.8.1", + "http-proxy-agent": "^2.1.0", + "https-proxy-agent": "^2.2.1", + "lru-cache": "^4.1.2", + "mississippi": "^3.0.0", + "node-fetch-npm": "^2.0.2", + "promise-retry": "^1.1.1", + "socks-proxy-agent": "^4.0.0", + "ssri": "^6.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + } + } + }, + "makeerror": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", + "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", + "dev": true, + "requires": { + "tmpl": "1.0.x" + } + }, + "map-age-cleaner": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", + "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", + "dev": true, + "requires": { + "p-defer": "^1.0.0" + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true + }, + "map-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-2.0.0.tgz", + "integrity": "sha1-plzSkIepJZi4eRJXpSPgISIqwfk=", + "dev": true + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "requires": { + "object-visit": "^1.0.0" + } + }, + "matcher": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/matcher/-/matcher-1.1.1.tgz", + "integrity": "sha512-+BmqxWIubKTRKNWx/ahnCkk3mG8m7OturVlqq6HiojGJTd5hVYbgZm6WzcYPCoB+KBT4Vd6R7WSRG2OADNaCjg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.4" + } + }, + "math-random": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz", + "integrity": "sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==", + "dev": true + }, + "md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "mdn-data": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-1.1.4.tgz", + "integrity": "sha512-FSYbp3lyKjyj3E7fMl6rYvUdX0FBXaluGqlFoYESWQlyUTq8R+wp0rkFxoYFqZlHCvsUXGjyJmLQSnXToYhOSA==", + "dev": true + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "dev": true + }, + "mem": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", + "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + } + }, + "mem-fs": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/mem-fs/-/mem-fs-1.1.3.tgz", + "integrity": "sha1-uK6NLj/Lb10/kWXBLUVRoGXZicw=", + "dev": true, + "requires": { + "through2": "^2.0.0", + "vinyl": "^1.1.0", + "vinyl-file": "^2.0.0" + } + }, + "mem-fs-editor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/mem-fs-editor/-/mem-fs-editor-5.1.0.tgz", + "integrity": "sha512-2Yt2GCYEbcotYbIJagmow4gEtHDqzpq5XN94+yAx/NT5+bGqIjkXnm3KCUQfE6kRfScGp9IZknScoGRKu8L78w==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "deep-extend": "^0.6.0", + "ejs": "^2.5.9", + "glob": "^7.0.3", + "globby": "^8.0.1", + "isbinaryfile": "^3.0.2", + "mkdirp": "^0.5.0", + "multimatch": "^2.0.0", + "rimraf": "^2.2.8", + "through2": "^2.0.0", + "vinyl": "^2.0.1" + }, + "dependencies": { + "clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", + "dev": true + }, + "clone-stats": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", + "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=", + "dev": true + }, + "dir-glob": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.0.0.tgz", + "integrity": "sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "path-type": "^3.0.0" + } + }, + "globby": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-8.0.2.tgz", + "integrity": "sha512-yTzMmKygLp8RUpG1Ymu2VXPSJQZjNAZPD4ywgYEaG7e4tBJeUQBO8OpXrf1RCNcEs5alsoJYPAMiIHP0cmeC7w==", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "dir-glob": "2.0.0", + "fast-glob": "^2.0.2", + "glob": "^7.1.2", + "ignore": "^3.3.5", + "pify": "^3.0.0", + "slash": "^1.0.0" + } + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "replace-ext": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz", + "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=", + "dev": true + }, + "vinyl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.0.tgz", + "integrity": "sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg==", + "dev": true, + "requires": { + "clone": "^2.1.1", + "clone-buffer": "^1.0.0", + "clone-stats": "^1.0.0", + "cloneable-readable": "^1.0.0", + "remove-trailing-separator": "^1.0.1", + "replace-ext": "^1.0.0" + } + } + } + }, + "memory-fs": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", + "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", + "dev": true, + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + }, + "meow": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-5.0.0.tgz", + "integrity": "sha512-CbTqYU17ABaLefO8vCU153ZZlprKYWDljcndKKDCFcYQITzWCXZAVk4QMFZPgvzrnUQ3uItnIE/LoUOwrT15Ig==", + "dev": true, + "requires": { + "camelcase-keys": "^4.0.0", + "decamelize-keys": "^1.0.0", + "loud-rejection": "^1.0.0", + "minimist-options": "^3.0.1", + "normalize-package-data": "^2.3.4", + "read-pkg-up": "^3.0.0", + "redent": "^2.0.0", + "trim-newlines": "^2.0.0", + "yargs-parser": "^10.0.0" + }, + "dependencies": { + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + } + }, + "read-pkg-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", + "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^3.0.0" + } + }, + "yargs-parser": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz", + "integrity": "sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==", + "dev": true, + "requires": { + "camelcase": "^4.1.0" + } + } + } + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", + "dev": true + }, + "merge-stream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-1.0.1.tgz", + "integrity": "sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE=", + "dev": true, + "requires": { + "readable-stream": "^2.0.1" + } + }, + "merge2": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.2.3.tgz", + "integrity": "sha512-gdUU1Fwj5ep4kplwcmftruWofEFt6lfpkkr3h860CXbAB9c3hGb55EOL2ali0Td5oebvW0E1+3Sr+Ur7XfKpRA==", + "dev": true + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + } + }, + "mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", + "dev": true + }, + "mime-db": { + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.38.0.tgz", + "integrity": "sha512-bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg==", + "dev": true + }, + "mime-types": { + "version": "2.1.22", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.22.tgz", + "integrity": "sha512-aGl6TZGnhm/li6F7yx82bJiBZwgiEa4Hf6CNr8YO+r5UHr53tSTYZb102zyU50DOWWKeOv0uQLRL0/9EiKWCog==", + "dev": true, + "requires": { + "mime-db": "~1.38.0" + } + }, + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==" + }, + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true + }, + "mini-css-extract-plugin": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.5.0.tgz", + "integrity": "sha512-IuaLjruM0vMKhUUT51fQdQzBYTX49dLj8w68ALEAe2A4iYNpIC4eMac67mt3NzycvjOlf07/kYxJDc0RTl1Wqw==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0", + "schema-utils": "^1.0.0", + "webpack-sources": "^1.1.0" + } + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + }, + "minimist-options": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-3.0.2.tgz", + "integrity": "sha512-FyBrT/d0d4+uiZRbqznPXqw3IpZZG3gl3wKWiX784FycUKVwBt0uLBFkQrtE4tZOrgo78nZp2jnKz3L65T5LdQ==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0" + } + }, + "minipass": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz", + "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.2.1.tgz", + "integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==", + "dev": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "mississippi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", + "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", + "dev": true, + "requires": { + "concat-stream": "^1.5.0", + "duplexify": "^3.4.2", + "end-of-stream": "^1.1.0", + "flush-write-stream": "^1.0.0", + "from2": "^2.1.0", + "parallel-transform": "^1.1.0", + "pump": "^3.0.0", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" + } + }, + "mitt": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-1.1.3.tgz", + "integrity": "sha512-mUDCnVNsAi+eD6qA0HkRkwYczbLHJ49z17BGe2PYRhZL4wpZUFZGJHU7/5tmvohoma+Hdn0Vh/oJTiPEmgSruA==", + "dev": true + }, + "mixin-deep": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", + "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", + "dev": true, + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "mixin-object": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mixin-object/-/mixin-object-2.0.1.tgz", + "integrity": "sha1-T7lJRB2rGCVA8f4DW6YOGUel5X4=", + "dev": true, + "requires": { + "for-in": "^0.1.3", + "is-extendable": "^0.1.1" + }, + "dependencies": { + "for-in": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-0.1.8.tgz", + "integrity": "sha1-2Hc5COMSVhCZUrH9ubP6hn0ndeE=", + "dev": true + } + } + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + } + } + }, + "moment": { + "version": "2.24.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", + "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==" + }, + "moment-locales-webpack-plugin": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/moment-locales-webpack-plugin/-/moment-locales-webpack-plugin-1.0.7.tgz", + "integrity": "sha512-KjYpaAhmuzGFZl6534FlZoK7QtW3vqlxd+A17W9DlgHJ5yhXANy7AZJl7iYtZpWjAfMTAWiVrQ7YDZdkFO6uRw==", + "dev": true, + "requires": { + "lodash.difference": "^4.5.0" + } + }, + "move-concurrently": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", + "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", + "dev": true, + "requires": { + "aproba": "^1.1.1", + "copy-concurrently": "^1.0.0", + "fs-write-stream-atomic": "^1.0.8", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.3" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "multicast-dns": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz", + "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", + "dev": true, + "requires": { + "dns-packet": "^1.3.1", + "thunky": "^1.0.2" + } + }, + "multicast-dns-service-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", + "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=", + "dev": true + }, + "multimatch": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-2.1.0.tgz", + "integrity": "sha1-nHkGoi+0wCkZ4vX3UWG0zb1LKis=", + "dev": true, + "requires": { + "array-differ": "^1.0.0", + "array-union": "^1.0.1", + "arrify": "^1.0.0", + "minimatch": "^3.0.0" + } + }, + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=" + }, + "nan": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.13.1.tgz", + "integrity": "sha512-I6YB/YEuDeUZMmhscXKxGgZlFnhsn5y0hgOZBadkzfTRrZBtJDZeg6eQf7PYMIEclwmorTKK8GztsyOUSVBREA==", + "dev": true, + "optional": true + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + } + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "negotiator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=", + "dev": true + }, + "neo-async": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.0.tgz", + "integrity": "sha512-MFh0d/Wa7vkKO3Y3LlacqAEeHK0mckVqzDieUKTT+KGxi+zIpeVsFxymkIiRpbpDziHc290Xr9A1O4Om7otoRA==", + "dev": true + }, + "ng-jhipster": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/ng-jhipster/-/ng-jhipster-0.9.1.tgz", + "integrity": "sha512-/ViJ6bNtc/4w6valKNvHKyvXF1cn1OBnSEh3Q8aEUHtmoyr9owReTGHT7ylNclthUsxztRMUS4GrMMEQ5kM09Q==", + "requires": { + "tslib": "^1.9.0" + } + }, + "ngx-cookie": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ngx-cookie/-/ngx-cookie-2.0.1.tgz", + "integrity": "sha512-3+agXZkoPxRP3IyELf7Eiuhk6TX+EAX974kkCR6Xjm+N7boEA+Fin2Q90AAE4XZzY48skkVzLH96TOikb5yU3g==" + }, + "ngx-infinite-scroll": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/ngx-infinite-scroll/-/ngx-infinite-scroll-7.0.1.tgz", + "integrity": "sha512-be9DAAuabV7VGI06/JUnS6pXC6mcBOzA4+SBCwOcP9WwJ2r5GjdZyOa34ls9hi1MnCOj3zrXLvPKQ/UDp6csIw==", + "requires": { + "opencollective": "^1.0.3" + } + }, + "ngx-webstorage": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ngx-webstorage/-/ngx-webstorage-2.0.1.tgz", + "integrity": "sha512-AhBkl1v5sBLYiGC1DuHxM90B8OewqyhYhm+KGtJIFxMh5dj3tlNgPokmWCtKcUZF26m8MgxDDuP5e6NeDCpYQw==" + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "no-case": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", + "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", + "dev": true, + "requires": { + "lower-case": "^1.1.1" + } + }, + "node-fetch": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.6.3.tgz", + "integrity": "sha1-3CNO3WSJmC1Y6PDbT2lQKavNjAQ=", + "requires": { + "encoding": "^0.1.11", + "is-stream": "^1.0.1" + } + }, + "node-fetch-npm": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-fetch-npm/-/node-fetch-npm-2.0.2.tgz", + "integrity": "sha512-nJIxm1QmAj4v3nfCvEeCrYSoVwXyxLnaPBK5W1W5DGEJwjlKuC2VEUycGw5oxk+4zZahRrB84PUJJgEmhFTDFw==", + "dev": true, + "requires": { + "encoding": "^0.1.11", + "json-parse-better-errors": "^1.0.0", + "safe-buffer": "^5.1.1" + } + }, + "node-forge": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.5.tgz", + "integrity": "sha512-MmbQJ2MTESTjt3Gi/3yG1wGpIMhUfcIypUCGtTizFR9IiccFwxSpfp0vtIZlkFclEqERemxfnSdZEMR9VqqEFQ==", + "dev": true + }, + "node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", + "dev": true + }, + "node-libs-browser": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.0.tgz", + "integrity": "sha512-5MQunG/oyOaBdttrL40dA7bUfPORLRWMUJLQtMg7nluxUvk5XwnLdL9twQHFAjRx/y7mIMkLKT9++qPbbk6BZA==", + "dev": true, + "requires": { + "assert": "^1.1.1", + "browserify-zlib": "^0.2.0", + "buffer": "^4.3.0", + "console-browserify": "^1.1.0", + "constants-browserify": "^1.0.0", + "crypto-browserify": "^3.11.0", + "domain-browser": "^1.1.1", + "events": "^3.0.0", + "https-browserify": "^1.0.0", + "os-browserify": "^0.3.0", + "path-browserify": "0.0.0", + "process": "^0.11.10", + "punycode": "^1.2.4", + "querystring-es3": "^0.2.0", + "readable-stream": "^2.3.3", + "stream-browserify": "^2.0.1", + "stream-http": "^2.7.2", + "string_decoder": "^1.0.0", + "timers-browserify": "^2.0.4", + "tty-browserify": "0.0.0", + "url": "^0.11.0", + "util": "^0.11.0", + "vm-browserify": "0.0.4" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + } + } + }, + "node-modules-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", + "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", + "dev": true + }, + "node-notifier": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.4.0.tgz", + "integrity": "sha512-SUDEb+o71XR5lXSTyivXd9J7fCloE3SyP4lSgt3lU2oSANiox+SxlNRGPjDKrwU1YN3ix2KN/VGGCg0t01rttQ==", + "dev": true, + "requires": { + "growly": "^1.3.0", + "is-wsl": "^1.1.0", + "semver": "^5.5.0", + "shellwords": "^0.1.1", + "which": "^1.3.0" + } + }, + "node-releases": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.11.tgz", + "integrity": "sha512-8v1j5KfP+s5WOTa1spNUAOfreajQPN12JXbRR0oDE+YrJBQCXBnNqUDj27EKpPLOoSiU3tKi3xGPB+JaOdUEQQ==", + "dev": true, + "requires": { + "semver": "^5.3.0" + } + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + }, + "normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", + "dev": true + }, + "normalize-url": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz", + "integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==", + "dev": true + }, + "npm-bundled": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.6.tgz", + "integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==", + "dev": true + }, + "npm-package-arg": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-6.1.0.tgz", + "integrity": "sha512-zYbhP2k9DbJhA0Z3HKUePUgdB1x7MfIfKssC+WLPFMKTBZKpZh5m13PgexJjCq6KW7j17r0jHWcCpxEqnnncSA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.6.0", + "osenv": "^0.1.5", + "semver": "^5.5.0", + "validate-npm-package-name": "^3.0.0" + } + }, + "npm-packlist": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.1.tgz", + "integrity": "sha512-+TcdO7HJJ8peiiYhvPxsEDhF3PJFGUGRcFsGve3vxvxdcpO2Z4Z7rkosRM0kWj6LfbK/P0gu3dzk5RU1ffvFcw==", + "dev": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, + "npm-path": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/npm-path/-/npm-path-2.0.4.tgz", + "integrity": "sha512-IFsj0R9C7ZdR5cP+ET342q77uSRdtWOlWpih5eC+lu29tIDbNEgDbzgVJ5UFvYHWhxDZ5TFkJafFioO0pPQjCw==", + "dev": true, + "requires": { + "which": "^1.2.10" + } + }, + "npm-pick-manifest": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-2.2.3.tgz", + "integrity": "sha512-+IluBC5K201+gRU85vFlUwX3PFShZAbAgDNp2ewJdWMVSppdo/Zih0ul2Ecky/X7b51J7LrrUAP+XOmOCvYZqA==", + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1", + "npm-package-arg": "^6.0.0", + "semver": "^5.4.1" + } + }, + "npm-registry-fetch": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-3.9.0.tgz", + "integrity": "sha512-srwmt8YhNajAoSAaDWndmZgx89lJwIZ1GWxOuckH4Coek4uHv5S+o/l9FLQe/awA+JwTnj4FJHldxhlXdZEBmw==", + "dev": true, + "requires": { + "JSONStream": "^1.3.4", + "bluebird": "^3.5.1", + "figgy-pudding": "^3.4.1", + "lru-cache": "^4.1.3", + "make-fetch-happen": "^4.0.1", + "npm-package-arg": "^6.1.0" + }, + "dependencies": { + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + } + } + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "npm-which": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/npm-which/-/npm-which-3.0.1.tgz", + "integrity": "sha1-kiXybsOihcIJyuZ8OxGmtKtxQKo=", + "dev": true, + "requires": { + "commander": "^2.9.0", + "npm-path": "^2.0.2", + "which": "^1.2.10" + } + }, + "npmlog": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-2.0.4.tgz", + "integrity": "sha1-mLUlMPJRTKkNCexbIsiEZyI3VpI=", + "dev": true, + "requires": { + "ansi": "~0.3.1", + "are-we-there-yet": "~1.1.2", + "gauge": "~1.2.5" + } + }, + "nth-check": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", + "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", + "dev": true, + "requires": { + "boolbase": "~1.0.0" + } + }, + "num2fraction": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", + "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=", + "dev": true + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, + "nwsapi": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.1.1.tgz", + "integrity": "sha512-T5GaA1J/d34AC8mkrFD2O0DR17kwJ702ZOtJOsS8RpbsQZVOC2/xYFb1i/cw+xdM54JIlMuojjDOYct8GIWtwg==", + "dev": true + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "object-component": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", + "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=", + "dev": true + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "object-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.0.tgz", + "integrity": "sha512-6OO5X1+2tYkNyNEx6TsCxEqFfRWaqx6EtMiSbGrw8Ob8v9Ne+Hl8rBAgLBZn5wjEz3s/s6U1WXFUFOcxxAwUpg==", + "dev": true + }, + "object-path": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/object-path/-/object-path-0.9.2.tgz", + "integrity": "sha1-D9mnT8X60a45aLWGvaXGMr1sBaU=", + "dev": true + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "requires": { + "isobject": "^3.0.0" + } + }, + "object.getownpropertydescriptors": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", + "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.5.1" + } + }, + "object.omit": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", + "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", + "dev": true, + "requires": { + "for-own": "^0.1.4", + "is-extendable": "^0.1.1" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "object.values": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.0.tgz", + "integrity": "sha512-8mf0nKLAoFX6VlNVdhGj31SVYpaNFtUnuoOXWyFEstsWRgU837AK+JYM0iAxwkSzGRbwn8cbFmgbyxj1j4VbXg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.12.0", + "function-bind": "^1.1.1", + "has": "^1.0.3" + } + }, + "obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "one-time": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-0.0.4.tgz", + "integrity": "sha1-+M33eISCb+Tf+T46nMN7HkSAdC4=", + "dev": true + }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "requires": { + "mimic-fn": "^1.0.0" + } + }, + "opencollective": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/opencollective/-/opencollective-1.0.3.tgz", + "integrity": "sha1-ruY3K8KBRFg2kMPKja7PwSDdDvE=", + "requires": { + "babel-polyfill": "6.23.0", + "chalk": "1.1.3", + "inquirer": "3.0.6", + "minimist": "1.2.0", + "node-fetch": "1.6.3", + "opn": "4.0.2" + } + }, + "openurl": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/openurl/-/openurl-1.1.1.tgz", + "integrity": "sha1-OHW0sO96UsFW8NtB1GCduw+Us4c=", + "dev": true + }, + "opn": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/opn/-/opn-4.0.2.tgz", + "integrity": "sha1-erwi5kTf9jsKltWrfyeQwPAavJU=", + "requires": { + "object-assign": "^4.0.1", + "pinkie-promise": "^2.0.0" + } + }, + "optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "dev": true, + "requires": { + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" + }, + "dependencies": { + "minimist": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", + "dev": true + } + } + }, + "optimize-css-assets-webpack-plugin": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/optimize-css-assets-webpack-plugin/-/optimize-css-assets-webpack-plugin-5.0.1.tgz", + "integrity": "sha512-Rqm6sSjWtx9FchdP0uzTQDc7GXDKnwVEGoSxjezPkzMewx7gEWE9IMUYKmigTRC4U3RaNSwYVnUDLuIdtTpm0A==", + "dev": true, + "requires": { + "cssnano": "^4.1.0", + "last-call-webpack-plugin": "^3.0.0" + } + }, + "optionator": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.4", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "wordwrap": "~1.0.0" + }, + "dependencies": { + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + } + } + }, + "original": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz", + "integrity": "sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==", + "dev": true, + "requires": { + "url-parse": "^1.4.3" + } + }, + "os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", + "dev": true + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true + }, + "os-locale": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", + "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", + "dev": true, + "requires": { + "execa": "^0.7.0", + "lcid": "^1.0.0", + "mem": "^1.1.0" + } + }, + "os-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/os-name/-/os-name-2.0.1.tgz", + "integrity": "sha1-uaOGNhwXrjohc27wWZQFyajF3F4=", + "dev": true, + "requires": { + "macos-release": "^1.0.0", + "win-release": "^1.0.0" + } + }, + "os-shim": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/os-shim/-/os-shim-0.1.3.tgz", + "integrity": "sha1-a2LDeRz3kJ6jXtRuF2WLtBfLORc=", + "dev": true + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + }, + "osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "dev": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "p-cancelable": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.3.0.tgz", + "integrity": "sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw==", + "dev": true + }, + "p-defer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", + "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", + "dev": true + }, + "p-each-series": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-1.0.0.tgz", + "integrity": "sha1-kw89Et0fUOdDRFeiLNbwSsatf3E=", + "dev": true, + "requires": { + "p-reduce": "^1.0.0" + } + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, + "p-is-promise": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.0.0.tgz", + "integrity": "sha512-pzQPhYMCAgLAKPWD2jC3Se9fEfrD9npNos0y150EeqZll7akhEgGhTW/slB6lHku8AvYGiJ+YJ5hfHKePPgFWg==", + "dev": true + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-map": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz", + "integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==", + "dev": true + }, + "p-reduce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-1.0.0.tgz", + "integrity": "sha1-GMKw3ZNqRpClKfgjH1ig/bakffo=", + "dev": true + }, + "p-timeout": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-1.2.1.tgz", + "integrity": "sha1-XrOzU7f86Z8QGhA4iAuwVOu+o4Y=", + "dev": true, + "requires": { + "p-finally": "^1.0.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "pacote": { + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-9.4.0.tgz", + "integrity": "sha512-WQ1KL/phGMkedYEQx9ODsjj7xvwLSpdFJJdEXrLyw5SILMxcTNt5DTxT2Z93fXuLFYJBlZJdnwdalrQdB/rX5w==", + "dev": true, + "requires": { + "bluebird": "^3.5.3", + "cacache": "^11.3.2", + "figgy-pudding": "^3.5.1", + "get-stream": "^4.1.0", + "glob": "^7.1.3", + "lru-cache": "^5.1.1", + "make-fetch-happen": "^4.0.1", + "minimatch": "^3.0.4", + "minipass": "^2.3.5", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "normalize-package-data": "^2.4.0", + "npm-package-arg": "^6.1.0", + "npm-packlist": "^1.1.12", + "npm-pick-manifest": "^2.2.3", + "npm-registry-fetch": "^3.8.0", + "osenv": "^0.1.5", + "promise-inflight": "^1.0.1", + "promise-retry": "^1.1.1", + "protoduck": "^5.0.1", + "rimraf": "^2.6.2", + "safe-buffer": "^5.1.2", + "semver": "^5.6.0", + "ssri": "^6.0.1", + "tar": "^4.4.8", + "unique-filename": "^1.1.1", + "which": "^1.3.1" + } + }, + "pako": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.10.tgz", + "integrity": "sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==", + "dev": true + }, + "parallel-transform": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.1.0.tgz", + "integrity": "sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY=", + "dev": true, + "requires": { + "cyclist": "~0.2.2", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" + } + }, + "param-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", + "integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=", + "dev": true, + "requires": { + "no-case": "^2.2.0" + } + }, + "parse-asn1": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.4.tgz", + "integrity": "sha512-Qs5duJcuvNExRfFZ99HDD3z4mAi3r9Wl/FOjEOijlxwCZs7E7mW2vjTpgQ4J8LpTF8x5v+1Vn5UQFejmWT11aw==", + "dev": true, + "requires": { + "asn1.js": "^4.0.0", + "browserify-aes": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "parse-gitignore": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-gitignore/-/parse-gitignore-1.0.1.tgz", + "integrity": "sha512-UGyowyjtx26n65kdAMWhm6/3uy5uSrpcuH7tt+QEVudiBoVS+eqHxD5kbi9oWVRwj7sCzXqwuM+rUGw7earl6A==", + "dev": true + }, + "parse-glob": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", + "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", + "dev": true, + "requires": { + "glob-base": "^0.3.0", + "is-dotfile": "^1.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.0" + }, + "dependencies": { + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "dev": true + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "dev": true, + "requires": { + "is-extglob": "^1.0.0" + } + } + } + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + }, + "parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", + "dev": true + }, + "parse5": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz", + "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==", + "dev": true + }, + "parseqs": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", + "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", + "dev": true, + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseuri": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", + "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", + "dev": true, + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseurl": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", + "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=", + "dev": true + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true + }, + "path-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz", + "integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=", + "dev": true + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "dev": true + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=", + "dev": true + }, + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "requires": { + "pify": "^2.0.0" + } + }, + "pbkdf2": { + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz", + "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==", + "dev": true, + "requires": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "requires": { + "pinkie": "^2.0.0" + } + }, + "pirates": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", + "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", + "dev": true, + "requires": { + "node-modules-regexp": "^1.0.0" + } + }, + "pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + } + }, + "pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz", + "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + } + }, + "please-upgrade-node": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.1.1.tgz", + "integrity": "sha512-KY1uHnQ2NlQHqIJQpnh/i54rKkuxCEBx+voJIS/Mvb+L2iYd2NMotwduhKTMjfC1uKoX3VXOxLjIYG66dfJTVQ==", + "dev": true, + "requires": { + "semver-compare": "^1.0.0" + } + }, + "plugin-error": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-0.1.2.tgz", + "integrity": "sha1-O5uzM1zPAPQl4HQ34ZJ2ln2kes4=", + "dev": true, + "requires": { + "ansi-cyan": "^0.1.1", + "ansi-red": "^0.1.1", + "arr-diff": "^1.0.1", + "arr-union": "^2.0.1", + "extend-shallow": "^1.1.2" + }, + "dependencies": { + "arr-diff": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-1.1.0.tgz", + "integrity": "sha1-aHwydYFjWI/vfeezb6vklesaOZo=", + "dev": true, + "requires": { + "arr-flatten": "^1.0.1", + "array-slice": "^0.2.3" + } + }, + "arr-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-2.1.0.tgz", + "integrity": "sha1-IPnqtexw9cfSFbEHexw5Fh0pLH0=", + "dev": true + }, + "extend-shallow": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-1.1.4.tgz", + "integrity": "sha1-Gda/lN/AnXa6cR85uHLSH/TdkHE=", + "dev": true, + "requires": { + "kind-of": "^1.1.0" + } + }, + "kind-of": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz", + "integrity": "sha1-FAo9LUGjbS78+pN3tiwk+ElaXEQ=", + "dev": true + } + } + }, + "pluralize": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", + "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", + "dev": true + }, + "pn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", + "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==", + "dev": true + }, + "portfinder": { + "version": "1.0.20", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.20.tgz", + "integrity": "sha512-Yxe4mTyDzTd59PZJY4ojZR8F+E5e97iq2ZOHPz3HDgSvYC5siNad2tLooQ5y5QHyQhc3xVqvyk/eNA3wuoa7Sw==", + "dev": true, + "requires": { + "async": "^1.5.2", + "debug": "^2.2.0", + "mkdirp": "0.5.x" + } + }, + "portscanner": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/portscanner/-/portscanner-2.1.1.tgz", + "integrity": "sha1-6rtAnk3iSVD1oqUW01rnaTQ/u5Y=", + "dev": true, + "requires": { + "async": "1.5.2", + "is-number-like": "^1.0.3" + } + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true + }, + "postcss": { + "version": "7.0.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.14.tgz", + "integrity": "sha512-NsbD6XUUMZvBxtQAJuWDJeeC4QFsmWsfozWxCJPWf3M55K9iu2iMDaKqyoOdTJ1R4usBXuxlVFAIo8rZPQD4Bg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-calc": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-7.0.1.tgz", + "integrity": "sha512-oXqx0m6tb4N3JGdmeMSc/i91KppbYsFZKdH0xMOqK8V1rJlzrKlTdokz8ozUXLVejydRN6u2IddxpcijRj2FqQ==", + "dev": true, + "requires": { + "css-unit-converter": "^1.1.1", + "postcss": "^7.0.5", + "postcss-selector-parser": "^5.0.0-rc.4", + "postcss-value-parser": "^3.3.1" + }, + "dependencies": { + "cssesc": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", + "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==", + "dev": true + }, + "postcss-selector-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", + "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", + "dev": true, + "requires": { + "cssesc": "^2.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "postcss-colormin": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-4.0.3.tgz", + "integrity": "sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw==", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "color": "^3.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-convert-values": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz", + "integrity": "sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ==", + "dev": true, + "requires": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-discard-comments": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-4.0.2.tgz", + "integrity": "sha512-RJutN259iuRf3IW7GZyLM5Sw4GLTOH8FmsXBnv8Ab/Tc2k4SR4qbV4DNbyyY4+Sjo362SyDmW2DQ7lBSChrpkg==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-discard-duplicates": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.2.tgz", + "integrity": "sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-discard-empty": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-4.0.1.tgz", + "integrity": "sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-discard-overridden": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-4.0.1.tgz", + "integrity": "sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-load-config": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-2.0.0.tgz", + "integrity": "sha512-V5JBLzw406BB8UIfsAWSK2KSwIJ5yoEIVFb4gVkXci0QdKgA24jLmHZ/ghe/GgX0lJ0/D1uUK1ejhzEY94MChQ==", + "dev": true, + "requires": { + "cosmiconfig": "^4.0.0", + "import-cwd": "^2.0.0" + }, + "dependencies": { + "cosmiconfig": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-4.0.0.tgz", + "integrity": "sha512-6e5vDdrXZD+t5v0L8CrurPeybg4Fmf+FCSYxXKYVAqLUtyCSbuyqE059d0kDthTNRzKVjL7QMgNpEUlsoYH3iQ==", + "dev": true, + "requires": { + "is-directory": "^0.3.1", + "js-yaml": "^3.9.0", + "parse-json": "^4.0.0", + "require-from-string": "^2.0.1" + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + } + } + }, + "postcss-loader": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-3.0.0.tgz", + "integrity": "sha512-cLWoDEY5OwHcAjDnkyRQzAXfs2jrKjXpO/HQFcc5b5u/r7aa471wdmChmwfnv7x2u840iat/wi0lQ5nbRgSkUA==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0", + "postcss": "^7.0.0", + "postcss-load-config": "^2.0.0", + "schema-utils": "^1.0.0" + } + }, + "postcss-merge-longhand": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz", + "integrity": "sha512-alx/zmoeXvJjp7L4mxEMjh8lxVlDFX1gqWHzaaQewwMZiVhLo42TEClKaeHbRf6J7j82ZOdTJ808RtN0ZOZwvw==", + "dev": true, + "requires": { + "css-color-names": "0.0.4", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "stylehacks": "^4.0.0" + } + }, + "postcss-merge-rules": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-4.0.3.tgz", + "integrity": "sha512-U7e3r1SbvYzO0Jr3UT/zKBVgYYyhAz0aitvGIYOYK5CPmkNih+WDSsS5tvPrJ8YMQYlEMvsZIiqmn7HdFUaeEQ==", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "caniuse-api": "^3.0.0", + "cssnano-util-same-parent": "^4.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0", + "vendors": "^1.0.0" + }, + "dependencies": { + "postcss-selector-parser": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.1.tgz", + "integrity": "sha1-T4dfSvsMllc9XPTXQBGu4lCn6GU=", + "dev": true, + "requires": { + "dot-prop": "^4.1.1", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "postcss-minify-font-values": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-4.0.2.tgz", + "integrity": "sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg==", + "dev": true, + "requires": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-minify-gradients": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-4.0.2.tgz", + "integrity": "sha512-qKPfwlONdcf/AndP1U8SJ/uzIJtowHlMaSioKzebAXSG4iJthlWC9iSWznQcX4f66gIWX44RSA841HTHj3wK+Q==", + "dev": true, + "requires": { + "cssnano-util-get-arguments": "^4.0.0", + "is-color-stop": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-minify-params": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-4.0.2.tgz", + "integrity": "sha512-G7eWyzEx0xL4/wiBBJxJOz48zAKV2WG3iZOqVhPet/9geefm/Px5uo1fzlHu+DOjT+m0Mmiz3jkQzVHe6wxAWg==", + "dev": true, + "requires": { + "alphanum-sort": "^1.0.0", + "browserslist": "^4.0.0", + "cssnano-util-get-arguments": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "uniqs": "^2.0.0" + } + }, + "postcss-minify-selectors": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-4.0.2.tgz", + "integrity": "sha512-D5S1iViljXBj9kflQo4YutWnJmwm8VvIsU1GeXJGiG9j8CIg9zs4voPMdQDUmIxetUOh60VilsNzCiAFTOqu3g==", + "dev": true, + "requires": { + "alphanum-sort": "^1.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0" + }, + "dependencies": { + "postcss-selector-parser": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.1.tgz", + "integrity": "sha1-T4dfSvsMllc9XPTXQBGu4lCn6GU=", + "dev": true, + "requires": { + "dot-prop": "^4.1.1", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "postcss-modules-extract-imports": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz", + "integrity": "sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ==", + "dev": true, + "requires": { + "postcss": "^7.0.5" + } + }, + "postcss-modules-local-by-default": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-2.0.6.tgz", + "integrity": "sha512-oLUV5YNkeIBa0yQl7EYnxMgy4N6noxmiwZStaEJUSe2xPMcdNc8WmBQuQCx18H5psYbVxz8zoHk0RAAYZXP9gA==", + "dev": true, + "requires": { + "postcss": "^7.0.6", + "postcss-selector-parser": "^6.0.0", + "postcss-value-parser": "^3.3.1" + } + }, + "postcss-modules-scope": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-2.1.0.tgz", + "integrity": "sha512-91Rjps0JnmtUB0cujlc8KIKCsJXWjzuxGeT/+Q2i2HXKZ7nBUeF9YQTZZTNvHVoNYj1AthsjnGLtqDUE0Op79A==", + "dev": true, + "requires": { + "postcss": "^7.0.6", + "postcss-selector-parser": "^6.0.0" + } + }, + "postcss-modules-values": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-2.0.0.tgz", + "integrity": "sha512-Ki7JZa7ff1N3EIMlPnGTZfUMe69FFwiQPnVSXC9mnn3jozCRBYIxiZd44yJOV2AmabOo4qFf8s0dC/+lweG7+w==", + "dev": true, + "requires": { + "icss-replace-symbols": "^1.1.0", + "postcss": "^7.0.6" + } + }, + "postcss-normalize-charset": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz", + "integrity": "sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-normalize-display-values": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.2.tgz", + "integrity": "sha512-3F2jcsaMW7+VtRMAqf/3m4cPFhPD3EFRgNs18u+k3lTJJlVe7d0YPO+bnwqo2xg8YiRpDXJI2u8A0wqJxMsQuQ==", + "dev": true, + "requires": { + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-normalize-positions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-4.0.2.tgz", + "integrity": "sha512-Dlf3/9AxpxE+NF1fJxYDeggi5WwV35MXGFnnoccP/9qDtFrTArZ0D0R+iKcg5WsUd8nUYMIl8yXDCtcrT8JrdA==", + "dev": true, + "requires": { + "cssnano-util-get-arguments": "^4.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-normalize-repeat-style": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.2.tgz", + "integrity": "sha512-qvigdYYMpSuoFs3Is/f5nHdRLJN/ITA7huIoCyqqENJe9PvPmLhNLMu7QTjPdtnVf6OcYYO5SHonx4+fbJE1+Q==", + "dev": true, + "requires": { + "cssnano-util-get-arguments": "^4.0.0", + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-normalize-string": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-4.0.2.tgz", + "integrity": "sha512-RrERod97Dnwqq49WNz8qo66ps0swYZDSb6rM57kN2J+aoyEAJfZ6bMx0sx/F9TIEX0xthPGCmeyiam/jXif0eA==", + "dev": true, + "requires": { + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-normalize-timing-functions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.2.tgz", + "integrity": "sha512-acwJY95edP762e++00Ehq9L4sZCEcOPyaHwoaFOhIwWCDfik6YvqsYNxckee65JHLKzuNSSmAdxwD2Cud1Z54A==", + "dev": true, + "requires": { + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-normalize-unicode": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.1.tgz", + "integrity": "sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg==", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-normalize-url": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-4.0.1.tgz", + "integrity": "sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA==", + "dev": true, + "requires": { + "is-absolute-url": "^2.0.0", + "normalize-url": "^3.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-normalize-whitespace": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.2.tgz", + "integrity": "sha512-tO8QIgrsI3p95r8fyqKV+ufKlSHh9hMJqACqbv2XknufqEDhDvbguXGBBqxw9nsQoXWf0qOqppziKJKHMD4GtA==", + "dev": true, + "requires": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-ordered-values": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-4.1.2.tgz", + "integrity": "sha512-2fCObh5UanxvSxeXrtLtlwVThBvHn6MQcu4ksNT2tsaV2Fg76R2CV98W7wNSlX+5/pFwEyaDwKLLoEV7uRybAw==", + "dev": true, + "requires": { + "cssnano-util-get-arguments": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-reduce-initial": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz", + "integrity": "sha512-gKWmR5aUulSjbzOfD9AlJiHCGH6AEVLaM0AV+aSioxUDd16qXP1PCh8d1/BGVvpdWn8k/HiK7n6TjeoXN1F7DA==", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "caniuse-api": "^3.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0" + } + }, + "postcss-reduce-transforms": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.2.tgz", + "integrity": "sha512-EEVig1Q2QJ4ELpJXMZR8Vt5DQx8/mo+dGWSR7vWXqcob2gQLyQGsionYcGKATXvQzMPn6DSN1vTN7yFximdIAg==", + "dev": true, + "requires": { + "cssnano-util-get-match": "^4.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-selector-parser": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.2.tgz", + "integrity": "sha512-36P2QR59jDTOAiIkqEprfJDsoNrvwFei3eCqKd1Y0tUsBimsq39BLp7RD+JWny3WgB1zGhJX8XVePwm9k4wdBg==", + "dev": true, + "requires": { + "cssesc": "^3.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + }, + "dependencies": { + "cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true + } + } + }, + "postcss-svgo": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-4.0.2.tgz", + "integrity": "sha512-C6wyjo3VwFm0QgBy+Fu7gCYOkCmgmClghO+pjcxvrcBKtiKt0uCF+hvbMO1fyv5BMImRK90SMb+dwUnfbGd+jw==", + "dev": true, + "requires": { + "is-svg": "^3.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "svgo": "^1.0.0" + } + }, + "postcss-unique-selectors": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz", + "integrity": "sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg==", + "dev": true, + "requires": { + "alphanum-sort": "^1.0.0", + "postcss": "^7.0.0", + "uniqs": "^2.0.0" + } + }, + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, + "prepend-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", + "dev": true + }, + "preserve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", + "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", + "dev": true + }, + "prettier": { + "version": "1.16.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.16.4.tgz", + "integrity": "sha512-ZzWuos7TI5CKUeQAtFd6Zhm2s6EpAD/ZLApIhsF9pRvRtM1RFo61dM/4MSRUA0SuLugA/zgrZD8m0BaY46Og7g==", + "dev": true + }, + "pretty-bytes": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.1.0.tgz", + "integrity": "sha512-wa5+qGVg9Yt7PB6rYm3kXlKzgzgivYTLRandezh43jjRqgyDyP+9YxfJpJiLs9yKD1WeU8/OvtToWpW7255FtA==", + "dev": true + }, + "pretty-error": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.1.tgz", + "integrity": "sha1-X0+HyPkeWuPzuoerTPXgOxoX8aM=", + "dev": true, + "requires": { + "renderkid": "^2.0.1", + "utila": "~0.4" + } + }, + "pretty-format": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.5.0.tgz", + "integrity": "sha512-/3RuSghukCf8Riu5Ncve0iI+BzVkbRU5EeUoArKARZobREycuH5O4waxvaNIloEXdb0qwgmEAed5vTpX1HNROQ==", + "dev": true, + "requires": { + "@jest/types": "^24.5.0", + "ansi-regex": "^4.0.0", + "ansi-styles": "^3.2.0", + "react-is": "^16.8.4" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + } + } + }, + "private": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", + "dev": true + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", + "dev": true + }, + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "dev": true + }, + "promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "dev": true, + "requires": { + "asap": "~2.0.3" + } + }, + "promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", + "dev": true + }, + "promise-retry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-1.1.1.tgz", + "integrity": "sha1-ZznpaOMFHaIM5kl/srUPaRHfPW0=", + "dev": true, + "requires": { + "err-code": "^1.0.0", + "retry": "^0.10.0" + } + }, + "prompts": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.0.4.tgz", + "integrity": "sha512-HTzM3UWp/99A0gk51gAegwo1QRYA7xjcZufMNe33rCclFszUYAuHe1fIN/3ZmiHeGPkUsNaRyQm1hHOfM0PKxA==", + "dev": true, + "requires": { + "kleur": "^3.0.2", + "sisteransi": "^1.0.0" + } + }, + "property-expr": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-1.5.1.tgz", + "integrity": "sha512-CGuc0VUTGthpJXL36ydB6jnbyOf/rAHFvmVrJlH+Rg0DqqLFQGAP6hIaxD/G0OAmBJPhXDHuEJigrp0e0wFV6g==", + "dev": true + }, + "protoduck": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/protoduck/-/protoduck-5.0.1.tgz", + "integrity": "sha512-WxoCeDCoCBY55BMvj4cAEjdVUFGRWed9ZxPlqTKYyw1nDDTQ4pqmnIMAGfJlg7Dx35uB/M+PHJPTmGOvaCaPTg==", + "dev": true, + "requires": { + "genfun": "^5.0.0" + } + }, + "proxy-addr": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz", + "integrity": "sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA==", + "dev": true, + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.8.0" + } + }, + "prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", + "dev": true + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "psl": { + "version": "1.1.31", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.31.tgz", + "integrity": "sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw==", + "dev": true + }, + "public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "dev": true, + "requires": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + }, + "dependencies": { + "pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", + "dev": true + }, + "qs": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.2.3.tgz", + "integrity": "sha1-HPyyXBCpsrSDBT/zn138kjOQjP4=", + "dev": true + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "dev": true + }, + "querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", + "dev": true + }, + "querystringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.0.tgz", + "integrity": "sha512-sluvZZ1YiTLD5jsqZcDmFyV2EwToyXZBfpoVOmktMmW+VEnhgakFHnasVph65fOjGPTWN0Nw3+XQaSeMayr0kg==", + "dev": true + }, + "quick-lru": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-1.1.0.tgz", + "integrity": "sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g=", + "dev": true + }, + "randexp": { + "version": "0.4.9", + "resolved": "https://registry.npmjs.org/randexp/-/randexp-0.4.9.tgz", + "integrity": "sha512-maAX1cnBkzIZ89O4tSQUOF098xjGMC8N+9vuY/WfHwg87THw6odD2Br35donlj5e6KnB1SB0QBHhTQhhDHuTPQ==", + "dev": true, + "requires": { + "drange": "^1.0.0", + "ret": "^0.2.0" + }, + "dependencies": { + "ret": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.2.2.tgz", + "integrity": "sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ==", + "dev": true + } + } + }, + "randomatic": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz", + "integrity": "sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==", + "dev": true, + "requires": { + "is-number": "^4.0.0", + "kind-of": "^6.0.0", + "math-random": "^1.0.1" + }, + "dependencies": { + "is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "dev": true + } + } + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "dev": true, + "requires": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=", + "dev": true + }, + "raw-body": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", + "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==", + "dev": true, + "requires": { + "bytes": "3.0.0", + "http-errors": "1.6.3", + "iconv-lite": "0.4.23", + "unpipe": "1.0.0" + }, + "dependencies": { + "iconv-lite": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", + "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + } + } + }, + "react": { + "version": "0.14.9", + "resolved": "https://registry.npmjs.org/react/-/react-0.14.9.tgz", + "integrity": "sha1-kRCmSXxJ1EuhwO3TF67CnC4NkdE=", + "dev": true, + "requires": { + "envify": "^3.0.0", + "fbjs": "^0.6.1" + } + }, + "react-dom": { + "version": "0.14.9", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-0.14.9.tgz", + "integrity": "sha1-BQZKPc8PsYgKOyv8nVjFXY2fYpM=", + "dev": true + }, + "react-is": { + "version": "16.8.4", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.4.tgz", + "integrity": "sha512-PVadd+WaUDOAciICm/J1waJaSvgq+4rHE/K70j0PFqKhkTBsPv/82UGQJNXAngz1fOQLLxI6z1sEDmJDQhCTAA==", + "dev": true + }, + "read-chunk": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/read-chunk/-/read-chunk-2.1.0.tgz", + "integrity": "sha1-agTAkoAF7Z1C4aasVgDhnLx/9lU=", + "dev": true, + "requires": { + "pify": "^3.0.0", + "safe-buffer": "^5.1.1" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "requires": { + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^2.0.0" + } + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, + "realpath-native": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-1.1.0.tgz", + "integrity": "sha512-wlgPA6cCIIg9gKz0fgAPjnzh4yR/LnXovwuo9hvyGvx3h8nX4+/iLZplfUWasXpqD8BdnGnP5njOFjkUwPzvjA==", + "dev": true, + "requires": { + "util.promisify": "^1.0.0" + } + }, + "recast": { + "version": "0.11.23", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.11.23.tgz", + "integrity": "sha1-RR/TAEqx5N+bTktmN2sqIZEkYtM=", + "dev": true, + "requires": { + "ast-types": "0.9.6", + "esprima": "~3.1.0", + "private": "~0.1.5", + "source-map": "~0.5.0" + }, + "dependencies": { + "esprima": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "dev": true, + "requires": { + "resolve": "^1.1.6" + } + }, + "redent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-2.0.0.tgz", + "integrity": "sha1-wbIAe0LVfrE4kHmzyDM2OdXhzKo=", + "dev": true, + "requires": { + "indent-string": "^3.0.0", + "strip-indent": "^2.0.0" + } + }, + "reflect-metadata": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==", + "dev": true + }, + "regenerate": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", + "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==", + "dev": true + }, + "regenerator-runtime": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz", + "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=" + }, + "regex-cache": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", + "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", + "dev": true, + "requires": { + "is-equal-shallow": "^0.1.3" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "regexp-to-ast": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/regexp-to-ast/-/regexp-to-ast-0.3.5.tgz", + "integrity": "sha512-1CJygtdvsfNFwiyjaMLBWtg2tfEqx/jSZ8S6TV+GlNL8kiH8rb4cm5Pb7A/C2BpyM/fA8ZJEudlCwi/jvAY+Ow==", + "dev": true + }, + "regexpu-core": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-1.0.0.tgz", + "integrity": "sha1-hqdj9Y7k18L2sQLkdkBQ3n7ZDGs=", + "dev": true, + "requires": { + "regenerate": "^1.2.1", + "regjsgen": "^0.2.0", + "regjsparser": "^0.1.4" + } + }, + "regjsgen": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", + "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=", + "dev": true + }, + "regjsparser": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", + "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", + "dev": true, + "requires": { + "jsesc": "~0.5.0" + } + }, + "relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", + "dev": true + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "renderkid": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.3.tgz", + "integrity": "sha512-z8CLQp7EZBPCwCnncgf9C4XAi3WR0dv+uWu/PjIyhhAb5d6IJ/QZqlHFprHeKT+59//V6BNUsLbvN8+2LarxGA==", + "dev": true, + "requires": { + "css-select": "^1.1.0", + "dom-converter": "^0.2", + "htmlparser2": "^3.3.0", + "strip-ansi": "^3.0.0", + "utila": "^0.4.0" + } + }, + "repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "replace-ext": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", + "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=", + "dev": true + }, + "request": { + "version": "2.88.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", + "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", + "dev": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.0", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.4.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true + }, + "tough-cookie": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", + "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", + "dev": true, + "requires": { + "psl": "^1.1.24", + "punycode": "^1.4.1" + } + } + } + }, + "request-promise-core": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.2.tgz", + "integrity": "sha512-UHYyq1MO8GsefGEt7EprS8UrXsm1TxEvFUX1IMTuSLU2Rh7fTIdFtl8xD7JiEYiWU2dl+NYAjCTksTehQUxPag==", + "dev": true, + "requires": { + "lodash": "^4.17.11" + } + }, + "request-promise-native": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.7.tgz", + "integrity": "sha512-rIMnbBdgNViL37nZ1b3L/VfPOpSi0TqVDQPAvO6U14lMzOLrt5nilxCQqtDKhZeDiW0/hkCXGoQjhgJd/tCh6w==", + "dev": true, + "requires": { + "request-promise-core": "1.1.2", + "stealthy-require": "^1.1.1", + "tough-cookie": "^2.3.3" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true + }, + "require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", + "dev": true + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "dev": true + }, + "resolve": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", + "integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "resolve-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", + "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", + "dev": true, + "requires": { + "resolve-from": "^3.0.0" + } + }, + "resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", + "dev": true, + "requires": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + } + }, + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "dev": true + }, + "resp-modifier": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/resp-modifier/-/resp-modifier-6.0.2.tgz", + "integrity": "sha1-sSTeXE+6/LpUH0j/pzlw9KpFa08=", + "dev": true, + "requires": { + "debug": "^2.2.0", + "minimatch": "^3.0.2" + } + }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "requires": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + } + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true + }, + "retry": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz", + "integrity": "sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q=", + "dev": true + }, + "rgb-regex": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/rgb-regex/-/rgb-regex-1.0.1.tgz", + "integrity": "sha1-wODWiC3w4jviVKR16O3UGRX+rrE=", + "dev": true + }, + "rgba-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rgba-regex/-/rgba-regex-1.0.0.tgz", + "integrity": "sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=", + "dev": true + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "rsvp": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.4.tgz", + "integrity": "sha512-6FomvYPfs+Jy9TfXmBpBuMWNH94SgCsZmJKcanySzgNNP6LjWxBvyLTa9KaMfDDM5oxRfrKDB0r/qeRsLwnBfA==", + "dev": true + }, + "run-async": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", + "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "requires": { + "is-promise": "^2.1.0" + } + }, + "run-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/run-node/-/run-node-1.0.0.tgz", + "integrity": "sha512-kc120TBlQ3mih1LSzdAJXo4xn/GWS2ec0l3S+syHDXP9uRr0JAT8Qd3mdMuyjqCzeZktgP3try92cEgf9Nks8A==", + "dev": true + }, + "run-queue": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", + "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", + "dev": true, + "requires": { + "aproba": "^1.1.1" + } + }, + "rx": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/rx/-/rx-4.1.0.tgz", + "integrity": "sha1-pfE/957zt0D+MKqAP7CfmIBdR4I=" + }, + "rxjs": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz", + "integrity": "sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==", + "requires": { + "tslib": "^1.9.0" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "requires": { + "ret": "~0.1.10" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "sane": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/sane/-/sane-4.1.0.tgz", + "integrity": "sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==", + "dev": true, + "requires": { + "@cnakazawa/watch": "^1.0.3", + "anymatch": "^2.0.0", + "capture-exit": "^2.0.0", + "exec-sh": "^0.3.2", + "execa": "^1.0.0", + "fb-watchman": "^2.0.0", + "micromatch": "^3.1.4", + "minimist": "^1.1.1", + "walker": "~1.0.5" + }, + "dependencies": { + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + } + } + }, + "sass": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.17.0.tgz", + "integrity": "sha512-aFi9RQqrCYkHB2DaLKBBbdUhos1N5o3l1ke9N5JqWzgSPmYwZsdmA+ViPVatUy/RPA21uejgYVUXM7GCh8lcdw==", + "dev": true, + "requires": { + "chokidar": "^2.0.0" + } + }, + "sass-loader": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-7.1.0.tgz", + "integrity": "sha512-+G+BKGglmZM2GUSfT9TLuEp6tzehHPjAMoRRItOojWIqIGPloVCMhNIQuG639eJ+y033PaGTSjLaTHts8Kw79w==", + "dev": true, + "requires": { + "clone-deep": "^2.0.1", + "loader-utils": "^1.0.1", + "lodash.tail": "^4.1.1", + "neo-async": "^2.5.0", + "pify": "^3.0.0", + "semver": "^5.5.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + }, + "scoped-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/scoped-regex/-/scoped-regex-1.0.0.tgz", + "integrity": "sha1-o0a7Gs1CB65wvXwMfKnlZra63bg=", + "dev": true + }, + "select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=", + "dev": true + }, + "selfsigned": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.4.tgz", + "integrity": "sha512-9AukTiDmHXGXWtWjembZ5NDmVvP2695EtpgbCsxCa68w3c88B+alqbmZ4O3hZ4VWGXeGWzEVdvqgAJD8DQPCDw==", + "dev": true, + "requires": { + "node-forge": "0.7.5" + } + }, + "semver": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", + "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", + "dev": true + }, + "semver-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", + "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=", + "dev": true + }, + "semver-dsl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/semver-dsl/-/semver-dsl-1.0.1.tgz", + "integrity": "sha1-02eN5VVeimH2Ke7QJTZq5fJzQKA=", + "dev": true, + "requires": { + "semver": "^5.3.0" + } + }, + "semver-intersect": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/semver-intersect/-/semver-intersect-1.4.0.tgz", + "integrity": "sha512-d8fvGg5ycKAq0+I6nfWeCx6ffaWJCsBYU0H2Rq56+/zFePYfT8mXkB3tWBSjR5BerkHNZ5eTPIk1/LBYas35xQ==", + "dev": true, + "requires": { + "semver": "^5.0.0" + } + }, + "send": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", + "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", + "dev": true, + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.4.0" + }, + "dependencies": { + "statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", + "dev": true + } + } + }, + "serialize-javascript": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.6.1.tgz", + "integrity": "sha512-A5MOagrPFga4YaKQSWHryl7AXvbQkEqpw4NNYMTNYUNV51bA8ABHgYFpqKx+YFFrw59xMV1qGH1R4AgoNIVgCw==", + "dev": true + }, + "serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", + "dev": true, + "requires": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + } + }, + "serve-static": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", + "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", + "dev": true, + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.2", + "send": "0.16.2" + } + }, + "server-destroy": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/server-destroy/-/server-destroy-1.0.1.tgz", + "integrity": "sha1-8Tv5KOQrnD55OD5hzDmYtdFObN0=", + "dev": true + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "set-value": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", + "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", + "dev": true + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + }, + "sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "shallow-clone": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-1.0.0.tgz", + "integrity": "sha512-oeXreoKR/SyNJtRJMAKPDSvd28OqEwG4eR/xc856cRGBII7gX9lvAqDxusPm0846z/w/hWYjI1NpKwJ00NHzRA==", + "dev": true, + "requires": { + "is-extendable": "^0.1.1", + "kind-of": "^5.0.0", + "mixin-object": "^2.0.1" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "shelljs": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.3.tgz", + "integrity": "sha512-fc0BKlAWiLpwZljmOvAOTE/gXawtCoNrP5oaY7KIaQbbyHeQVg01pSEuEGvGh3HEdBU4baCD7wQBwADmM/7f7A==", + "dev": true, + "requires": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + } + }, + "shellwords": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", + "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" + }, + "simple-git": { + "version": "1.107.0", + "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-1.107.0.tgz", + "integrity": "sha512-t4OK1JRlp4ayKRfcW6owrWcRVLyHRUlhGd0uN6ZZTqfDq8a5XpcUdOKiGRNobHEuMtNqzp0vcJNvhYWwh5PsQA==", + "dev": true, + "requires": { + "debug": "^4.0.1" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + } + } + }, + "simple-progress-webpack-plugin": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/simple-progress-webpack-plugin/-/simple-progress-webpack-plugin-1.1.2.tgz", + "integrity": "sha512-bNQfb3qSqbtsfxg6d0dGechUUJH2lZqKG5+bj2aoJmEA0rSzcm+2JVfC2YgkDABfuGItZ/O5ttt6BssWZW4SNg==", + "dev": true, + "requires": { + "chalk": "2.3.x", + "figures": "2.0.x", + "log-update": "2.3.x" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.2.tgz", + "integrity": "sha512-ZM4j2/ld/YZDc3Ma8PgN7gyAk+kHMMMyzLNryCPGhWrsfAuDVeuid5bpRFTDgMH9JBK2lA4dyyAkkZYF/WcqDQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", + "dev": true, + "requires": { + "is-arrayish": "^0.3.1" + }, + "dependencies": { + "is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "dev": true + } + } + }, + "sisteransi": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.0.tgz", + "integrity": "sha512-N+z4pHB4AmUv0SjveWRd6q1Nj5w62m5jodv+GD8lvmbY/83T/rpbJGZOnK5T149OldDj4Db07BSv9xY4K6NTPQ==", + "dev": true + }, + "slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "dev": true + }, + "slice-ansi": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", + "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=", + "dev": true + }, + "smart-buffer": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.0.2.tgz", + "integrity": "sha512-JDhEpTKzXusOqXZ0BUIdH+CjFdO/CR3tLlf5CN34IypI+xMmXW1uB16OOY8z3cICbJlDAVJzNbwBhNO0wt9OAw==", + "dev": true + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "requires": { + "kind-of": "^3.2.0" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "socket.io": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.1.1.tgz", + "integrity": "sha512-rORqq9c+7W0DAK3cleWNSyfv/qKXV99hV4tZe+gGLfBECw3XEhBy7x85F3wypA9688LKjtwO9pX9L33/xQI8yA==", + "dev": true, + "requires": { + "debug": "~3.1.0", + "engine.io": "~3.2.0", + "has-binary2": "~1.0.2", + "socket.io-adapter": "~1.1.0", + "socket.io-client": "2.1.1", + "socket.io-parser": "~3.2.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "engine.io-client": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz", + "integrity": "sha512-y5AbkytWeM4jQr7m/koQLc5AxpRKC1hEVUb/s1FUAWEJq5AzJJ4NLvzuKPuxtDi5Mq755WuDvZ6Iv2rXj4PTzw==", + "dev": true, + "requires": { + "component-emitter": "1.2.1", + "component-inherit": "0.0.3", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.1", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "ws": "~3.3.1", + "xmlhttprequest-ssl": "~1.5.4", + "yeast": "0.1.2" + } + }, + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", + "dev": true + }, + "socket.io-client": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.1.1.tgz", + "integrity": "sha512-jxnFyhAuFxYfjqIgduQlhzqTcOEQSn+OHKVfAxWaNWa7ecP7xSNk2Dx/3UEsDcY7NcFafxvNvKPmmO7HTwTxGQ==", + "dev": true, + "requires": { + "backo2": "1.0.2", + "base64-arraybuffer": "0.1.5", + "component-bind": "1.0.0", + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "engine.io-client": "~3.2.0", + "has-binary2": "~1.0.2", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "object-component": "0.0.3", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "socket.io-parser": "~3.2.0", + "to-array": "0.1.4" + } + }, + "socket.io-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.2.0.tgz", + "integrity": "sha512-FYiBx7rc/KORMJlgsXysflWx/RIvtqZbyGLlHZvjfmPTPeuD/I8MaW7cfFrj5tRltICJdgwflhfZ3NVVbVLFQA==", + "dev": true, + "requires": { + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "isarray": "2.0.1" + } + }, + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + } + } + }, + "socket.io-adapter": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz", + "integrity": "sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs=", + "dev": true + }, + "socket.io-client": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.2.0.tgz", + "integrity": "sha512-56ZrkTDbdTLmBIyfFYesgOxsjcLnwAKoN4CiPyTVkMQj3zTUh0QAx3GbvIvLpFEOvQWu92yyWICxB0u7wkVbYA==", + "dev": true, + "requires": { + "backo2": "1.0.2", + "base64-arraybuffer": "0.1.5", + "component-bind": "1.0.0", + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "engine.io-client": "~3.3.1", + "has-binary2": "~1.0.2", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "object-component": "0.0.3", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "socket.io-parser": "~3.3.0", + "to-array": "0.1.4" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "socket.io-parser": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.0.tgz", + "integrity": "sha512-hczmV6bDgdaEbVqhAeVMM/jfUfzuEZHsQg6eOmLgJht6G3mPKMxYm75w2+qhAQZ+4X+1+ATZ+QFKeOZD5riHng==", + "dev": true, + "requires": { + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "isarray": "2.0.1" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", + "dev": true + } + } + }, + "sockjs": { + "version": "0.3.19", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.19.tgz", + "integrity": "sha512-V48klKZl8T6MzatbLlzzRNhMepEys9Y4oGFpypBFFn1gLI/QQ9HtLLyWJNbPlwGLelOVOEijUbTTJeLLI59jLw==", + "dev": true, + "requires": { + "faye-websocket": "^0.10.0", + "uuid": "^3.0.1" + } + }, + "sockjs-client": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.3.0.tgz", + "integrity": "sha512-R9jxEzhnnrdxLCNln0xg5uGHqMnkhPSTzUZH2eXcR03S/On9Yvoq2wyUZILRUhZCNVu2PmwWVoyuiPz8th8zbg==", + "dev": true, + "requires": { + "debug": "^3.2.5", + "eventsource": "^1.0.7", + "faye-websocket": "~0.11.1", + "inherits": "^2.0.3", + "json3": "^3.3.2", + "url-parse": "^1.4.3" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "faye-websocket": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.1.tgz", + "integrity": "sha1-8O/hjE9W5PQK/H4Gxxn9XuYYjzg=", + "dev": true, + "requires": { + "websocket-driver": ">=0.5.1" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + } + } + }, + "socks": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.3.2.tgz", + "integrity": "sha512-pCpjxQgOByDHLlNqlnh/mNSAxIUkyBBuwwhTcV+enZGbDaClPvHdvm6uvOwZfFJkam7cGhBNbb4JxiP8UZkRvQ==", + "dev": true, + "requires": { + "ip": "^1.1.5", + "smart-buffer": "4.0.2" + } + }, + "socks-proxy-agent": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-4.0.2.tgz", + "integrity": "sha512-NT6syHhI9LmuEMSK6Kd2V7gNv5KFZoLE7V5udWmn0de+3Mkj3UMA/AJPLyeNUVmElCurSHtUdM3ETpR3z770Wg==", + "dev": true, + "requires": { + "agent-base": "~4.2.1", + "socks": "~2.3.2" + } + }, + "source-list-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", + "dev": true + }, + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true + }, + "source-map-resolve": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", + "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", + "dev": true, + "requires": { + "atob": "^2.1.1", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-support": { + "version": "0.5.11", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.11.tgz", + "integrity": "sha512-//sajEx/fGL3iw6fltKMdPvy8kL3kJ2O3iuYlRoT3k9Kb4BjOoZ+BZzaNHeuaruSt+Kf3Zk9tnfAQg9/AJqUVQ==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "dev": true + }, + "sourcemap-codec": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.4.tgz", + "integrity": "sha512-CYAPYdBu34781kLHkaW3m6b/uUSyMOC2R61gcYMWooeuaGtjof86ZA/8T+qVPPt7np1085CR9hmMGrySwEc8Xg==", + "dev": true + }, + "spawn-sync": { + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/spawn-sync/-/spawn-sync-1.0.15.tgz", + "integrity": "sha1-sAeZVX63+wyDdsKdROih6mfldHY=", + "dev": true, + "requires": { + "concat-stream": "^1.4.7", + "os-shim": "^0.1.2" + } + }, + "spdx-correct": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", + "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", + "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", + "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.3.tgz", + "integrity": "sha512-uBIcIl3Ih6Phe3XHK1NqboJLdGfwr1UN3k6wSD1dZpmPsIkb8AGNbZYJ1fOBk834+Gxy8rpfDxrS6XLEMZMY2g==", + "dev": true + }, + "spdy": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.0.tgz", + "integrity": "sha512-ot0oEGT/PGUpzf/6uk4AWLqkq+irlqHXkrdbk51oWONh3bxQmBuljxPNl66zlRRcIJStWq0QkLUCPOPjgjvU0Q==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + } + } + }, + "spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "readable-stream": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.2.0.tgz", + "integrity": "sha512-RV20kLjdmpZuTF1INEb9IA3L68Nmi+Ri7ppZqo78wj//Pn62fCoJyV9zalccNzDD/OuJpMG4f+pfMl8+L6QdGw==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "sprintf-js": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", + "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", + "dev": true + }, + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "dev": true, + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "ssri": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", + "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1" + } + }, + "stable": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", + "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", + "dev": true + }, + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", + "dev": true + }, + "stack-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.2.tgz", + "integrity": "sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA==", + "dev": true + }, + "stackframe": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.0.4.tgz", + "integrity": "sha512-to7oADIniaYwS3MhtCa/sQhrxidCCQiF/qp4/m5iN3ipf0Y7Xlri0f6eG29r08aL7JYl8n32AF3Q5GYBZ7K8vw==", + "dev": true + }, + "staged-git-files": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/staged-git-files/-/staged-git-files-1.1.2.tgz", + "integrity": "sha512-0Eyrk6uXW6tg9PYkhi/V/J4zHp33aNyi2hOCmhFLqLTIhbgqWn5jlSzI+IU0VqrZq6+DbHcabQl/WP6P3BG0QA==", + "dev": true + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "statuses": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", + "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=", + "dev": true + }, + "stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", + "dev": true + }, + "stream-browserify": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", + "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", + "dev": true, + "requires": { + "inherits": "~2.0.1", + "readable-stream": "^2.0.2" + } + }, + "stream-each": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", + "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "stream-shift": "^1.0.0" + } + }, + "stream-http": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", + "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", + "dev": true, + "requires": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.3.6", + "to-arraybuffer": "^1.0.0", + "xtend": "^4.0.0" + } + }, + "stream-shift": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", + "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=", + "dev": true + }, + "stream-throttle": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/stream-throttle/-/stream-throttle-0.1.3.tgz", + "integrity": "sha1-rdV8jXzHOoFjDTHNVdOWHPr7qcM=", + "dev": true, + "requires": { + "commander": "^2.2.0", + "limiter": "^1.0.5" + } + }, + "streamfilter": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/streamfilter/-/streamfilter-1.0.7.tgz", + "integrity": "sha512-Gk6KZM+yNA1JpW0KzlZIhjo3EaBJDkYfXtYSbOwNIQ7Zd6006E6+sCFlW1NDvFG/vnXhKmw6TJJgiEQg/8lXfQ==", + "dev": true, + "requires": { + "readable-stream": "^2.0.2" + } + }, + "string-argv": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.0.2.tgz", + "integrity": "sha1-2sMECGkMIfPDYwo/86BYd73L1zY=", + "dev": true + }, + "string-length": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-2.0.0.tgz", + "integrity": "sha1-1A27aGo6zpYMHP/KVivyxF+DY+0=", + "dev": true, + "requires": { + "astral-regex": "^1.0.0", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "string-template": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz", + "integrity": "sha1-QpMuWYo1LQH8IuwzZ9nYTuxsmt0=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "stringify-object": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", + "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", + "dev": true, + "requires": { + "get-own-enumerable-property-symbols": "^3.0.0", + "is-obj": "^1.0.1", + "is-regexp": "^1.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "strip-bom-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom-stream/-/strip-bom-stream-2.0.0.tgz", + "integrity": "sha1-+H217yYT9paKpUWr/h7HKLaoKco=", + "dev": true, + "requires": { + "first-chunk-stream": "^2.0.0", + "strip-bom": "^2.0.0" + }, + "dependencies": { + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true, + "requires": { + "is-utf8": "^0.2.0" + } + } + } + }, + "strip-comments": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/strip-comments/-/strip-comments-1.0.2.tgz", + "integrity": "sha512-kL97alc47hoyIQSV165tTt9rG5dn4w1dNnBhOQ3bOU1Nc1hel09jnXANaHJ7vzHLd4Ju8kseDGzlev96pghLFw==", + "dev": true, + "requires": { + "babel-extract-comments": "^1.0.0", + "babel-plugin-transform-object-rest-spread": "^6.26.0" + } + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true + }, + "strip-indent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-2.0.0.tgz", + "integrity": "sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g=", + "dev": true + }, + "style-loader": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.23.1.tgz", + "integrity": "sha512-XK+uv9kWwhZMZ1y7mysB+zoihsEj4wneFWAS5qoiLwzW0WzSqMrrsIy+a3zkQJq0ipFtBpX5W3MqyRIBF/WFGg==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0", + "schema-utils": "^1.0.0" + } + }, + "stylehacks": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-4.0.3.tgz", + "integrity": "sha512-7GlLk9JwlElY4Y6a/rmbH2MhVlTyVmiJd1PfTCqFaIBEGMYNsrO/v3SeGTdhBThLg4Z+NbOk/qFMwCa+J+3p/g==", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0" + }, + "dependencies": { + "postcss-selector-parser": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.1.tgz", + "integrity": "sha1-T4dfSvsMllc9XPTXQBGu4lCn6GU=", + "dev": true, + "requires": { + "dot-prop": "^4.1.1", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + }, + "svgo": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.2.0.tgz", + "integrity": "sha512-xBfxJxfk4UeVN8asec9jNxHiv3UAMv/ujwBWGYvQhhMb2u3YTGKkiybPcLFDLq7GLLWE9wa73e0/m8L5nTzQbw==", + "dev": true, + "requires": { + "chalk": "^2.4.1", + "coa": "^2.0.2", + "css-select": "^2.0.0", + "css-select-base-adapter": "^0.1.1", + "css-tree": "1.0.0-alpha.28", + "css-url-regex": "^1.1.0", + "csso": "^3.5.1", + "js-yaml": "^3.12.0", + "mkdirp": "~0.5.1", + "object.values": "^1.1.0", + "sax": "~1.2.4", + "stable": "^0.1.8", + "unquote": "~1.1.1", + "util.promisify": "~1.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "css-select": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.0.2.tgz", + "integrity": "sha512-dSpYaDVoWaELjvZ3mS6IKZM/y2PMPa/XYoEfYNZePL4U/XgyxZNroHEHReDx/d+VgXh9VbCTtFqLkFbmeqeaRQ==", + "dev": true, + "requires": { + "boolbase": "^1.0.0", + "css-what": "^2.1.2", + "domutils": "^1.7.0", + "nth-check": "^1.0.2" + } + }, + "domutils": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", + "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", + "dev": true, + "requires": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "swagger-ui": { + "version": "2.2.10", + "resolved": "https://registry.npmjs.org/swagger-ui/-/swagger-ui-2.2.10.tgz", + "integrity": "sha1-sl56IWZOXZC/OR2zDbCN5B6FLXs=" + }, + "symbol-observable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", + "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==", + "dev": true + }, + "symbol-tree": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.2.tgz", + "integrity": "sha1-rifbOPZgp64uHDt9G8KQgZuFGeY=", + "dev": true + }, + "synchronous-promise": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/synchronous-promise/-/synchronous-promise-2.0.6.tgz", + "integrity": "sha512-TyOuWLwkmtPL49LHCX1caIwHjRzcVd62+GF6h8W/jHOeZUFHpnd2XJDVuUlaTaLPH1nuu2M69mfHr5XbQJnf/g==", + "dev": true + }, + "tabtab": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/tabtab/-/tabtab-2.2.2.tgz", + "integrity": "sha1-egR/FDsBC0y9MfhX6ClhUSy/ThQ=", + "dev": true, + "requires": { + "debug": "^2.2.0", + "inquirer": "^1.0.2", + "lodash.difference": "^4.5.0", + "lodash.uniq": "^4.5.0", + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "npmlog": "^2.0.3", + "object-assign": "^4.1.0" + }, + "dependencies": { + "cli-cursor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", + "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", + "dev": true, + "requires": { + "restore-cursor": "^1.0.1" + } + }, + "external-editor": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-1.1.1.tgz", + "integrity": "sha1-Etew24UPf/fnCBuvQAVwAGDEYAs=", + "dev": true, + "requires": { + "extend": "^3.0.0", + "spawn-sync": "^1.0.15", + "tmp": "^0.0.29" + } + }, + "figures": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5", + "object-assign": "^4.1.0" + } + }, + "inquirer": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-1.2.3.tgz", + "integrity": "sha1-TexvMvN+97sLLtPx0aXD9UUHSRg=", + "dev": true, + "requires": { + "ansi-escapes": "^1.1.0", + "chalk": "^1.0.0", + "cli-cursor": "^1.0.1", + "cli-width": "^2.0.0", + "external-editor": "^1.1.0", + "figures": "^1.3.5", + "lodash": "^4.3.0", + "mute-stream": "0.0.6", + "pinkie-promise": "^2.0.0", + "run-async": "^2.2.0", + "rx": "^4.1.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.0", + "through": "^2.3.6" + } + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "mute-stream": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.6.tgz", + "integrity": "sha1-SJYrGeFp/R38JAs/HnMXYnu8R9s=", + "dev": true + }, + "onetime": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", + "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", + "dev": true + }, + "restore-cursor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", + "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", + "dev": true, + "requires": { + "exit-hook": "^1.0.0", + "onetime": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "tmp": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.29.tgz", + "integrity": "sha1-8lEl/w3Z2jzLDC3Tce4SiLuRKMA=", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.1" + } + } + } + }, + "tapable": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.1.tgz", + "integrity": "sha512-9I2ydhj8Z9veORCw5PRm4u9uebCn0mcCa6scWoNcbZ6dAtoo2618u9UUzxgmsCOreJpqDDuv61LvwofW7hLcBA==", + "dev": true + }, + "tar": { + "version": "4.4.8", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.8.tgz", + "integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==", + "dev": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.3.4", + "minizlib": "^1.1.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.2" + } + }, + "terser": { + "version": "3.17.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-3.17.0.tgz", + "integrity": "sha512-/FQzzPJmCpjAH9Xvk2paiWrFq+5M6aVOf+2KRbwhByISDX/EujxsK+BAvrhb6H+2rtrLCHK9N01wO014vrIwVQ==", + "dev": true, + "requires": { + "commander": "^2.19.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.10" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "terser-webpack-plugin": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.2.2.tgz", + "integrity": "sha512-1DMkTk286BzmfylAvLXwpJrI7dWa5BnFmscV/2dCr8+c56egFcbaeFAl7+sujAjdmpLam21XRdhA4oifLyiWWg==", + "dev": true, + "requires": { + "cacache": "^11.0.2", + "find-cache-dir": "^2.0.0", + "schema-utils": "^1.0.0", + "serialize-javascript": "^1.4.0", + "source-map": "^0.6.1", + "terser": "^3.16.1", + "webpack-sources": "^1.1.0", + "worker-farm": "^1.5.2" + }, + "dependencies": { + "find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + } + }, + "p-limit": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", + "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.1.0.tgz", + "integrity": "sha512-H2RyIJ7+A3rjkwKC2l5GGtU4H1vkxKCAGsWasNVd0Set+6i4znxbWy6/j16YDPJDWxhsgZiKAstMEP8wCdSpjA==", + "dev": true + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "test-exclude": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.1.0.tgz", + "integrity": "sha512-gwf0S2fFsANC55fSeSqpb8BYk6w3FDvwZxfNjeF6FRgvFa43r+7wRiA/Q0IxoRU37wB/LE8IQ4221BsNucTaCA==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "minimatch": "^3.0.4", + "read-pkg-up": "^4.0.0", + "require-main-filename": "^1.0.1" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", + "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.1.0.tgz", + "integrity": "sha512-H2RyIJ7+A3rjkwKC2l5GGtU4H1vkxKCAGsWasNVd0Set+6i4znxbWy6/j16YDPJDWxhsgZiKAstMEP8wCdSpjA==", + "dev": true + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + } + }, + "read-pkg-up": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", + "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", + "dev": true, + "requires": { + "find-up": "^3.0.0", + "read-pkg": "^3.0.0" + } + } + } + }, + "text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==", + "dev": true + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "textextensions": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/textextensions/-/textextensions-2.4.0.tgz", + "integrity": "sha512-qftQXnX1DzpSV8EddtHIT0eDDEiBF8ywhFYR2lI9xrGtxqKN+CvLXhACeCIGbCpQfxxERbrkZEFb8cZcDKbVZA==", + "dev": true + }, + "tfunk": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/tfunk/-/tfunk-3.1.0.tgz", + "integrity": "sha1-OORBT8ZJd9h6/apy+sttKfgve1s=", + "dev": true, + "requires": { + "chalk": "^1.1.1", + "object-path": "^0.9.0" + } + }, + "thread-loader": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/thread-loader/-/thread-loader-2.1.2.tgz", + "integrity": "sha512-7xpuc9Ifg6WU+QYw/8uUqNdRwMD+N5gjwHKMqETrs96Qn+7BHwECpt2Brzr4HFlf4IAkZsayNhmGdbkBsTJ//w==", + "dev": true, + "requires": { + "loader-runner": "^2.3.1", + "loader-utils": "^1.1.0", + "neo-async": "^2.6.0" + } + }, + "throat": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/throat/-/throat-4.1.0.tgz", + "integrity": "sha1-iQN8vJLFarGJJua6TLsgDhVnKmo=", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "thunky": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.0.3.tgz", + "integrity": "sha512-YwT8pjmNcAXBZqrubu22P4FYsh2D4dxRmnWBOL8Jk8bUcRUtc5326kx32tuTmFDAZtLOGEVNl8POAR8j896Iow==", + "dev": true + }, + "timed-out": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", + "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=", + "dev": true + }, + "timers-browserify": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.10.tgz", + "integrity": "sha512-YvC1SV1XdOUaL6gx5CoGroT3Gu49pK9+TZ38ErPldOWW4j49GI1HKs9DV+KGq/w6y+LZ72W1c8cKz2vzY+qpzg==", + "dev": true, + "requires": { + "setimmediate": "^1.0.4" + } + }, + "timsort": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", + "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=", + "dev": true + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "tmpl": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", + "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=", + "dev": true + }, + "to-array": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", + "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=", + "dev": true + }, + "to-arraybuffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", + "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", + "dev": true + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "to-string-loader": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/to-string-loader/-/to-string-loader-1.1.5.tgz", + "integrity": "sha1-e3qheJG3u0lHp6Eb+wO1/enG5pU=", + "dev": true, + "requires": { + "loader-utils": "^0.2.16" + }, + "dependencies": { + "big.js": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", + "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==", + "dev": true + }, + "json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "dev": true + }, + "loader-utils": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz", + "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=", + "dev": true, + "requires": { + "big.js": "^3.1.3", + "emojis-list": "^2.0.0", + "json5": "^0.5.0", + "object-assign": "^4.0.1" + } + } + } + }, + "topo": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/topo/-/topo-2.0.2.tgz", + "integrity": "sha1-zVYVdSU5BXwNwEkaYhw7xvvh0YI=", + "dev": true, + "requires": { + "hoek": "4.x.x" + } + }, + "toposort": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/toposort/-/toposort-1.0.7.tgz", + "integrity": "sha1-LmhELZ9k7HILjMieZEOsbKqVACk=", + "dev": true + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, + "tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "tree-kill": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.1.tgz", + "integrity": "sha512-4hjqbObwlh2dLyW4tcz0Ymw0ggoaVDMveUB9w8kFSQScdRLo0gxO9J7WFcUBo+W3C1TLdFIEwNOWebgZZ0RH9Q==", + "dev": true + }, + "trim-newlines": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-2.0.0.tgz", + "integrity": "sha1-tAPQuRvlDDMd/EuC7s6yLD3hbSA=", + "dev": true + }, + "trim-right": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", + "dev": true + }, + "triple-beam": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", + "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==", + "dev": true + }, + "ts-jest": { + "version": "23.1.4", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-23.1.4.tgz", + "integrity": "sha512-9rCSxbWfoZxxeXnSoEIzRNr9hDIQ8iEJAWmSRsWhDHDT8OeuGfURhJQUE8jtJlkyEygs6rngH8RYtHz9cfjmEA==", + "dev": true, + "requires": { + "closest-file-data": "^0.1.4", + "fs-extra": "6.0.1", + "json5": "^0.5.0", + "lodash": "^4.17.10" + }, + "dependencies": { + "fs-extra": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-6.0.1.tgz", + "integrity": "sha512-GnyIkKhhzXZUWFCaJzvyDLEEgDkPfb4/TPvJCJVuS8MWZgoSsErf++QpiAlDnKFcqhRlm+tIOcencCjyJE6ZCA==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "dev": true + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + } + } + }, + "ts-loader": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-5.3.3.tgz", + "integrity": "sha512-KwF1SplmOJepnoZ4eRIloH/zXL195F51skt7reEsS6jvDqzgc/YSbz9b8E07GxIUwLXdcD4ssrJu6v8CwaTafA==", + "dev": true, + "requires": { + "chalk": "^2.3.0", + "enhanced-resolve": "^4.0.0", + "loader-utils": "^1.0.2", + "micromatch": "^3.1.4", + "semver": "^5.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "tslib": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", + "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==" + }, + "tslint": { + "version": "5.12.1", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.12.1.tgz", + "integrity": "sha512-sfodBHOucFg6egff8d1BvuofoOQ/nOeYNfbp7LDlKBcLNrL3lmS5zoiDGyOMdT7YsEXAwWpTdAHwOGOc8eRZAw==", + "dev": true, + "requires": { + "babel-code-frame": "^6.22.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^3.2.0", + "glob": "^7.1.1", + "js-yaml": "^3.7.0", + "minimatch": "^3.0.4", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.8.0", + "tsutils": "^2.27.2" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "tslint-config-prettier": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/tslint-config-prettier/-/tslint-config-prettier-1.18.0.tgz", + "integrity": "sha512-xPw9PgNPLG3iKRxmK7DWr+Ea/SzrvfHtjFt5LBl61gk2UBG/DB9kCXRjv+xyIU1rUtnayLeMUVJBcMX8Z17nDg==", + "dev": true + }, + "tslint-loader": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/tslint-loader/-/tslint-loader-3.6.0.tgz", + "integrity": "sha512-Me9Qf/87BOfCY8uJJw+J7VMF4U8WiMXKLhKKKugMydF0xMhMOt9wo2mjYTNhwbF9H7SHh8PAIwRG8roisTNekQ==", + "dev": true, + "requires": { + "loader-utils": "^1.0.2", + "mkdirp": "^0.5.1", + "object-assign": "^4.1.1", + "rimraf": "^2.4.4", + "semver": "^5.3.0" + } + }, + "tsutils": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", + "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, + "tty-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", + "dev": true + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "type-is": { + "version": "1.6.16", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", + "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", + "dev": true, + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.18" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "typescript": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.2.4.tgz", + "integrity": "sha512-0RNDbSdEokBeEAkgNbxJ+BLwSManFy9TeXz8uW+48j/xhEXv1ePME60olyzw2XzUqUBNAYFeJadIqAgNqIACwg==", + "dev": true + }, + "ua-parser-js": { + "version": "0.7.17", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.17.tgz", + "integrity": "sha512-uRdSdu1oA1rncCQL7sCj8vSyZkgtL7faaw9Tc9rZ3mGgraQ7+Pdx7w5mnOSF3gw9ZNG6oc+KXfkon3bKuROm0g==", + "dev": true + }, + "uglify-js": { + "version": "3.4.10", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz", + "integrity": "sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw==", + "dev": true, + "requires": { + "commander": "~2.19.0", + "source-map": "~0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==", + "dev": true + }, + "union-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", + "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^0.4.3" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "set-value": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", + "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.1", + "to-object-path": "^0.3.0" + } + } + } + }, + "uniq": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", + "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", + "dev": true + }, + "uniqs": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/uniqs/-/uniqs-2.0.0.tgz", + "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=", + "dev": true + }, + "unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "dev": true, + "requires": { + "unique-slug": "^2.0.0" + } + }, + "unique-slug": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.1.tgz", + "integrity": "sha512-n9cU6+gITaVu7VGj1Z8feKMmfAjEAQGhwD9fE3zvpRRa0wEIx8ODYkVGfSc94M2OX00tUFV8wH3zYbm1I8mxFg==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "dev": true + }, + "unquote": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz", + "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=", + "dev": true + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true + } + } + }, + "untildify": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-3.0.3.tgz", + "integrity": "sha512-iSk/J8efr8uPT/Z4eSUywnqyrQU7DSdMfdqK4iWEaUVVmcP5JcnpRqmVMwcwcnmI1ATFNgC5V90u09tBynNFKA==", + "dev": true + }, + "upath": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.2.tgz", + "integrity": "sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q==", + "dev": true + }, + "upper-case": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", + "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=", + "dev": true + }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "dev": true + }, + "url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "dev": true, + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", + "dev": true + } + } + }, + "url-parse": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.4.tgz", + "integrity": "sha512-/92DTTorg4JjktLNLe6GPS2/RvAd/RGr6LuktmWSMLEOa6rjnlrFXNgSbSmkNvCoL2T028A0a1JaJLzRMlFoHg==", + "dev": true, + "requires": { + "querystringify": "^2.0.0", + "requires-port": "^1.0.0" + } + }, + "url-parse-lax": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", + "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", + "dev": true, + "requires": { + "prepend-http": "^1.0.1" + } + }, + "url-to-options": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz", + "integrity": "sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=", + "dev": true + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true + }, + "util": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", + "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", + "dev": true, + "requires": { + "inherits": "2.0.3" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "util.promisify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", + "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "object.getownpropertydescriptors": "^2.0.3" + } + }, + "utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=", + "dev": true + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "dev": true + }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "dev": true + }, + "v8-compile-cache": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.0.2.tgz", + "integrity": "sha512-1wFuMUIM16MDJRCrpbpuEPTUGmM5QMUg0cr3KFwra2XgOgFcPGDQHDh3CszSCD2Zewc/dh/pamNEW8CbfDebUw==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "validate-npm-package-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz", + "integrity": "sha1-X6kS2B630MdK/BQN5zF/DKffQ34=", + "dev": true, + "requires": { + "builtins": "^1.0.3" + } + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "dev": true + }, + "vendors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.2.tgz", + "integrity": "sha512-w/hry/368nO21AN9QljsaIhb9ZiZtZARoVH5f3CsFbawdLdayCgKRPup7CggujvySMxx0I91NOyxdVENohprLQ==", + "dev": true + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "vinyl": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz", + "integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=", + "dev": true, + "requires": { + "clone": "^1.0.0", + "clone-stats": "^0.0.1", + "replace-ext": "0.0.1" + } + }, + "vinyl-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/vinyl-file/-/vinyl-file-2.0.0.tgz", + "integrity": "sha1-p+v1/779obfRjRQPyweyI++2dRo=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "pify": "^2.3.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0", + "strip-bom-stream": "^2.0.0", + "vinyl": "^1.1.0" + }, + "dependencies": { + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true, + "requires": { + "is-utf8": "^0.2.0" + } + } + } + }, + "vm-browserify": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", + "integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=", + "dev": true, + "requires": { + "indexof": "0.0.1" + } + }, + "w3c-hr-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz", + "integrity": "sha1-gqwr/2PZUOqeMYmlimViX+3xkEU=", + "dev": true, + "requires": { + "browser-process-hrtime": "^0.1.2" + } + }, + "walker": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", + "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", + "dev": true, + "requires": { + "makeerror": "1.0.x" + } + }, + "watchpack": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz", + "integrity": "sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA==", + "dev": true, + "requires": { + "chokidar": "^2.0.2", + "graceful-fs": "^4.1.2", + "neo-async": "^2.5.0" + } + }, + "wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "requires": { + "minimalistic-assert": "^1.0.0" + } + }, + "webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", + "dev": true + }, + "webpack": { + "version": "4.29.3", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.29.3.tgz", + "integrity": "sha512-xPJvFeB+8tUflXFq+OgdpiSnsCD5EANyv56co5q8q8+YtEasn5Sj3kzY44mta+csCIEB0vneSxnuaHkOL2h94A==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.7.11", + "@webassemblyjs/helper-module-context": "1.7.11", + "@webassemblyjs/wasm-edit": "1.7.11", + "@webassemblyjs/wasm-parser": "1.7.11", + "acorn": "^6.0.5", + "acorn-dynamic-import": "^4.0.0", + "ajv": "^6.1.0", + "ajv-keywords": "^3.1.0", + "chrome-trace-event": "^1.0.0", + "enhanced-resolve": "^4.1.0", + "eslint-scope": "^4.0.0", + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^2.3.0", + "loader-utils": "^1.1.0", + "memory-fs": "~0.4.1", + "micromatch": "^3.1.8", + "mkdirp": "~0.5.0", + "neo-async": "^2.5.0", + "node-libs-browser": "^2.0.0", + "schema-utils": "^1.0.0", + "tapable": "^1.1.0", + "terser-webpack-plugin": "^1.1.0", + "watchpack": "^1.5.0", + "webpack-sources": "^1.3.0" + }, + "dependencies": { + "acorn": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.1.1.tgz", + "integrity": "sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA==", + "dev": true + } + } + }, + "webpack-cli": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.2.3.tgz", + "integrity": "sha512-Ik3SjV6uJtWIAN5jp5ZuBMWEAaP5E4V78XJ2nI+paFPh8v4HPSwo/myN0r29Xc/6ZKnd2IdrAlpSgNOu2CDQ6Q==", + "dev": true, + "requires": { + "chalk": "^2.4.1", + "cross-spawn": "^6.0.5", + "enhanced-resolve": "^4.1.0", + "findup-sync": "^2.0.0", + "global-modules": "^1.0.0", + "import-local": "^2.0.0", + "interpret": "^1.1.0", + "loader-utils": "^1.1.0", + "supports-color": "^5.5.0", + "v8-compile-cache": "^2.0.2", + "yargs": "^12.0.4" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "camelcase": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.2.0.tgz", + "integrity": "sha512-IXFsBS2pC+X0j0N/GE7Dm7j3bsEBp+oTpb7F50dwEVX7rf3IgwO9XatnegTsDtniKCUtEJH4fSU6Asw7uoVLfQ==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "cliui": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", + "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", + "dev": true, + "requires": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", + "wrap-ansi": "^2.0.0" + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "invert-kv": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", + "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", + "dev": true + }, + "lcid": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", + "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", + "dev": true, + "requires": { + "invert-kv": "^2.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "mem": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-4.2.0.tgz", + "integrity": "sha512-5fJxa68urlY0Ir8ijatKa3eRz5lwXnRCTvo9+TbTGAuTFJOwpGcY0X05moBd0nW45965Njt4CDI2GFQoG8DvqA==", + "dev": true, + "requires": { + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^2.0.0", + "p-is-promise": "^2.0.0" + } + }, + "mimic-fn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.0.0.tgz", + "integrity": "sha512-jbex9Yd/3lmICXwYT6gA/j2mNQGU48wCh/VzRd+/Y/PjYQtlg1gLMdZqvu9s/xH7qKvngxRObl56XZR609IMbA==", + "dev": true + }, + "os-locale": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", + "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", + "dev": true, + "requires": { + "execa": "^1.0.0", + "lcid": "^2.0.0", + "mem": "^4.0.0" + } + }, + "p-limit": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", + "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.1.0.tgz", + "integrity": "sha512-H2RyIJ7+A3rjkwKC2l5GGtU4H1vkxKCAGsWasNVd0Set+6i4znxbWy6/j16YDPJDWxhsgZiKAstMEP8wCdSpjA==", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "yargs": { + "version": "12.0.5", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", + "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", + "dev": true, + "requires": { + "cliui": "^4.0.0", + "decamelize": "^1.2.0", + "find-up": "^3.0.0", + "get-caller-file": "^1.0.1", + "os-locale": "^3.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1 || ^4.0.0", + "yargs-parser": "^11.1.1" + } + }, + "yargs-parser": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", + "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "webpack-dev-middleware": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.4.0.tgz", + "integrity": "sha512-Q9Iyc0X9dP9bAsYskAVJ/hmIZZQwf/3Sy4xCAZgL5cUkjZmUZLt4l5HpbST/Pdgjn3u6pE7u5OdGd1apgzRujA==", + "dev": true, + "requires": { + "memory-fs": "~0.4.1", + "mime": "^2.3.1", + "range-parser": "^1.0.3", + "webpack-log": "^2.0.0" + }, + "dependencies": { + "mime": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.0.tgz", + "integrity": "sha512-ikBcWwyqXQSHKtciCcctu9YfPbFYZ4+gbHEmE0Q8jzcTYQg5dHCr3g2wwAZjPoJfQVXZq6KXAjpXOTf5/cjT7w==", + "dev": true + } + } + }, + "webpack-dev-server": { + "version": "3.1.14", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.1.14.tgz", + "integrity": "sha512-mGXDgz5SlTxcF3hUpfC8hrQ11yhAttuUQWf1Wmb+6zo3x6rb7b9mIfuQvAPLdfDRCGRGvakBWHdHOa0I9p/EVQ==", + "dev": true, + "requires": { + "ansi-html": "0.0.7", + "bonjour": "^3.5.0", + "chokidar": "^2.0.0", + "compression": "^1.5.2", + "connect-history-api-fallback": "^1.3.0", + "debug": "^3.1.0", + "del": "^3.0.0", + "express": "^4.16.2", + "html-entities": "^1.2.0", + "http-proxy-middleware": "~0.18.0", + "import-local": "^2.0.0", + "internal-ip": "^3.0.1", + "ip": "^1.1.5", + "killable": "^1.0.0", + "loglevel": "^1.4.1", + "opn": "^5.1.0", + "portfinder": "^1.0.9", + "schema-utils": "^1.0.0", + "selfsigned": "^1.9.1", + "semver": "^5.6.0", + "serve-index": "^1.7.2", + "sockjs": "0.3.19", + "sockjs-client": "1.3.0", + "spdy": "^4.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^5.1.0", + "url": "^0.11.0", + "webpack-dev-middleware": "3.4.0", + "webpack-log": "^2.0.0", + "yargs": "12.0.2" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "cliui": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", + "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", + "dev": true, + "requires": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", + "wrap-ansi": "^2.0.0" + }, + "dependencies": { + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "decamelize": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-2.0.0.tgz", + "integrity": "sha512-Ikpp5scV3MSYxY39ymh45ZLEecsTdv/Xj2CaQfI8RLMuwi7XvjX9H/fhraiSuU+C5w5NTDu4ZU72xNiZnurBPg==", + "dev": true, + "requires": { + "xregexp": "4.0.0" + } + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "invert-kv": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", + "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", + "dev": true + }, + "lcid": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", + "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", + "dev": true, + "requires": { + "invert-kv": "^2.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "mem": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-4.2.0.tgz", + "integrity": "sha512-5fJxa68urlY0Ir8ijatKa3eRz5lwXnRCTvo9+TbTGAuTFJOwpGcY0X05moBd0nW45965Njt4CDI2GFQoG8DvqA==", + "dev": true, + "requires": { + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^2.0.0", + "p-is-promise": "^2.0.0" + } + }, + "mimic-fn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.0.0.tgz", + "integrity": "sha512-jbex9Yd/3lmICXwYT6gA/j2mNQGU48wCh/VzRd+/Y/PjYQtlg1gLMdZqvu9s/xH7qKvngxRObl56XZR609IMbA==", + "dev": true + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "opn": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz", + "integrity": "sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==", + "dev": true, + "requires": { + "is-wsl": "^1.1.0" + } + }, + "os-locale": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", + "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", + "dev": true, + "requires": { + "execa": "^1.0.0", + "lcid": "^2.0.0", + "mem": "^4.0.0" + } + }, + "p-limit": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", + "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.1.0.tgz", + "integrity": "sha512-H2RyIJ7+A3rjkwKC2l5GGtU4H1vkxKCAGsWasNVd0Set+6i4znxbWy6/j16YDPJDWxhsgZiKAstMEP8wCdSpjA==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "yargs": { + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.2.tgz", + "integrity": "sha512-e7SkEx6N6SIZ5c5H22RTZae61qtn3PYUE8JYbBFlK9sYmh3DMQ6E5ygtaG/2BW0JZi4WGgTR2IV5ChqlqrDGVQ==", + "dev": true, + "requires": { + "cliui": "^4.0.0", + "decamelize": "^2.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^1.0.1", + "os-locale": "^3.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1 || ^4.0.0", + "yargs-parser": "^10.1.0" + } + }, + "yargs-parser": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz", + "integrity": "sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==", + "dev": true, + "requires": { + "camelcase": "^4.1.0" + } + } + } + }, + "webpack-log": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz", + "integrity": "sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==", + "dev": true, + "requires": { + "ansi-colors": "^3.0.0", + "uuid": "^3.3.2" + } + }, + "webpack-merge": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.2.1.tgz", + "integrity": "sha512-4p8WQyS98bUJcCvFMbdGZyZmsKuWjWVnVHnAS3FFg0HDaRVrPbkivx2RYCre8UiemD67RsiFFLfn4JhLAin8Vw==", + "dev": true, + "requires": { + "lodash": "^4.17.5" + } + }, + "webpack-notifier": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/webpack-notifier/-/webpack-notifier-1.7.0.tgz", + "integrity": "sha512-L3UKrl500xk0VDYKkwQxy5/BPhBWsZ2xHsAx2Qe3dVKYUEk9+y690RcNTMIUcVOK2fRgK7KK3PA4ccOq1h+fTg==", + "dev": true, + "requires": { + "node-notifier": "^5.1.2", + "object-assign": "^4.1.0", + "strip-ansi": "^3.0.1" + } + }, + "webpack-sources": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.3.0.tgz", + "integrity": "sha512-OiVgSrbGu7NEnEvQJJgdSFPl2qWKkWq5lHMhgiToIiN9w34EBnjYzSYs+VbL5KoYiLNtFFa7BZIKxRED3I32pA==", + "dev": true, + "requires": { + "source-list-map": "^2.0.0", + "source-map": "~0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "webpack-visualizer-plugin": { + "version": "0.1.11", + "resolved": "https://registry.npmjs.org/webpack-visualizer-plugin/-/webpack-visualizer-plugin-0.1.11.tgz", + "integrity": "sha1-uHcK2GtPZSYSxosbeCJT+vn4o04=", + "dev": true, + "requires": { + "d3": "^3.5.6", + "mkdirp": "^0.5.1", + "react": "^0.14.0", + "react-dom": "^0.14.0" + } + }, + "websocket-driver": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.0.tgz", + "integrity": "sha1-DK+dLXVdk67gSdS90NP+LMoqJOs=", + "dev": true, + "requires": { + "http-parser-js": ">=0.4.0", + "websocket-extensions": ">=0.1.1" + } + }, + "websocket-extensions": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.3.tgz", + "integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==", + "dev": true + }, + "whatwg-encoding": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "dev": true, + "requires": { + "iconv-lite": "0.4.24" + } + }, + "whatwg-fetch": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-0.9.0.tgz", + "integrity": "sha1-DjaExsuZlbQ+/J3wPkw2XZX9nMA=", + "dev": true + }, + "whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", + "dev": true + }, + "whatwg-url": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz", + "integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==", + "dev": true, + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "win-release": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/win-release/-/win-release-1.1.1.tgz", + "integrity": "sha1-X6VeAr58qTTt/BJmVjLoSbcuUgk=", + "dev": true, + "requires": { + "semver": "^5.0.1" + } + }, + "window-size": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz", + "integrity": "sha1-tDFbtCFKPXBY6+7okuE/ok2YsHU=", + "dev": true + }, + "winston": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.2.1.tgz", + "integrity": "sha512-zU6vgnS9dAWCEKg/QYigd6cgMVVNwyTzKs81XZtTFuRwJOcDdBg7AU0mXVyNbs7O5RH2zdv+BdNZUlx7mXPuOw==", + "dev": true, + "requires": { + "async": "^2.6.1", + "diagnostics": "^1.1.1", + "is-stream": "^1.1.0", + "logform": "^2.1.1", + "one-time": "0.0.4", + "readable-stream": "^3.1.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.3.0" + }, + "dependencies": { + "async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz", + "integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==", + "dev": true, + "requires": { + "lodash": "^4.17.11" + } + }, + "readable-stream": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.2.0.tgz", + "integrity": "sha512-RV20kLjdmpZuTF1INEb9IA3L68Nmi+Ri7ppZqo78wj//Pn62fCoJyV9zalccNzDD/OuJpMG4f+pfMl8+L6QdGw==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "winston-transport": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.3.0.tgz", + "integrity": "sha512-B2wPuwUi3vhzn/51Uukcao4dIduEiPOcOt9HJ3QeaXgkJ5Z7UwpBzxS4ZGNHtrxrUvTwemsQiSys0ihOf8Mp1A==", + "dev": true, + "requires": { + "readable-stream": "^2.3.6", + "triple-beam": "^1.2.0" + } + }, + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "dev": true + }, + "workbox-background-sync": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/workbox-background-sync/-/workbox-background-sync-3.6.3.tgz", + "integrity": "sha512-ypLo0B6dces4gSpaslmDg5wuoUWrHHVJfFWwl1udvSylLdXvnrfhFfriCS42SNEe5lsZtcNZF27W/SMzBlva7Q==", + "dev": true, + "requires": { + "workbox-core": "^3.6.3" + } + }, + "workbox-broadcast-cache-update": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/workbox-broadcast-cache-update/-/workbox-broadcast-cache-update-3.6.3.tgz", + "integrity": "sha512-pJl4lbClQcvp0SyTiEw0zLSsVYE1RDlCPtpKnpMjxFtu8lCFTAEuVyzxp9w7GF4/b3P4h5nyQ+q7V9mIR7YzGg==", + "dev": true, + "requires": { + "workbox-core": "^3.6.3" + } + }, + "workbox-build": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/workbox-build/-/workbox-build-3.6.3.tgz", + "integrity": "sha512-w0clZ/pVjL8VXy6GfthefxpEXs0T8uiRuopZSFVQ8ovfbH6c6kUpEh6DcYwm/Y6dyWPiCucdyAZotgjz+nRz8g==", + "dev": true, + "requires": { + "babel-runtime": "^6.26.0", + "common-tags": "^1.4.0", + "fs-extra": "^4.0.2", + "glob": "^7.1.2", + "joi": "^11.1.1", + "lodash.template": "^4.4.0", + "pretty-bytes": "^4.0.2", + "stringify-object": "^3.2.2", + "strip-comments": "^1.0.2", + "workbox-background-sync": "^3.6.3", + "workbox-broadcast-cache-update": "^3.6.3", + "workbox-cache-expiration": "^3.6.3", + "workbox-cacheable-response": "^3.6.3", + "workbox-core": "^3.6.3", + "workbox-google-analytics": "^3.6.3", + "workbox-navigation-preload": "^3.6.3", + "workbox-precaching": "^3.6.3", + "workbox-range-requests": "^3.6.3", + "workbox-routing": "^3.6.3", + "workbox-strategies": "^3.6.3", + "workbox-streams": "^3.6.3", + "workbox-sw": "^3.6.3" + }, + "dependencies": { + "fs-extra": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", + "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "pretty-bytes": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-4.0.2.tgz", + "integrity": "sha1-sr+C5zUNZcbDOqlaqlpPYyf2HNk=", + "dev": true + } + } + }, + "workbox-cache-expiration": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/workbox-cache-expiration/-/workbox-cache-expiration-3.6.3.tgz", + "integrity": "sha512-+ECNph/6doYx89oopO/UolYdDmQtGUgo8KCgluwBF/RieyA1ZOFKfrSiNjztxOrGJoyBB7raTIOlEEwZ1LaHoA==", + "dev": true, + "requires": { + "workbox-core": "^3.6.3" + } + }, + "workbox-cacheable-response": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/workbox-cacheable-response/-/workbox-cacheable-response-3.6.3.tgz", + "integrity": "sha512-QpmbGA9SLcA7fklBLm06C4zFg577Dt8u3QgLM0eMnnbaVv3rhm4vbmDpBkyTqvgK/Ly8MBDQzlXDtUCswQwqqg==", + "dev": true, + "requires": { + "workbox-core": "^3.6.3" + } + }, + "workbox-core": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-3.6.3.tgz", + "integrity": "sha512-cx9cx0nscPkIWs8Pt98HGrS9/aORuUcSkWjG25GqNWdvD/pSe7/5Oh3BKs0fC+rUshCiyLbxW54q0hA+GqZeSQ==", + "dev": true + }, + "workbox-google-analytics": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/workbox-google-analytics/-/workbox-google-analytics-3.6.3.tgz", + "integrity": "sha512-RQBUo/6SXtIaQTRFj4RQZ9e1gAl7D8oS5S+Hi173Kk70/BgJjzPwXpC5A249Jv5YfkCOLMQCeF9A27BiD0b0ig==", + "dev": true, + "requires": { + "workbox-background-sync": "^3.6.3", + "workbox-core": "^3.6.3", + "workbox-routing": "^3.6.3", + "workbox-strategies": "^3.6.3" + } + }, + "workbox-navigation-preload": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/workbox-navigation-preload/-/workbox-navigation-preload-3.6.3.tgz", + "integrity": "sha512-dd26xTX16DUu0i+MhqZK/jQXgfIitu0yATM4jhRXEmpMqQ4MxEeNvl2CgjDMOHBnCVMax+CFZQWwxMx/X/PqCw==", + "dev": true, + "requires": { + "workbox-core": "^3.6.3" + } + }, + "workbox-precaching": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/workbox-precaching/-/workbox-precaching-3.6.3.tgz", + "integrity": "sha512-aBqT66BuMFviPTW6IpccZZHzpA8xzvZU2OM1AdhmSlYDXOJyb1+Z6blVD7z2Q8VNtV1UVwQIdImIX+hH3C3PIw==", + "dev": true, + "requires": { + "workbox-core": "^3.6.3" + } + }, + "workbox-range-requests": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/workbox-range-requests/-/workbox-range-requests-3.6.3.tgz", + "integrity": "sha512-R+yLWQy7D9aRF9yJ3QzwYnGFnGDhMUij4jVBUVtkl67oaVoP1ymZ81AfCmfZro2kpPRI+vmNMfxxW531cqdx8A==", + "dev": true, + "requires": { + "workbox-core": "^3.6.3" + } + }, + "workbox-routing": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-3.6.3.tgz", + "integrity": "sha512-bX20i95OKXXQovXhFOViOK63HYmXvsIwZXKWbSpVeKToxMrp0G/6LZXnhg82ijj/S5yhKNRf9LeGDzaqxzAwMQ==", + "dev": true, + "requires": { + "workbox-core": "^3.6.3" + } + }, + "workbox-strategies": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-3.6.3.tgz", + "integrity": "sha512-Pg5eulqeKet2y8j73Yw6xTgLdElktcWExGkzDVCGqfV9JCvnGuEpz5eVsCIK70+k4oJcBCin9qEg3g3CwEIH3g==", + "dev": true, + "requires": { + "workbox-core": "^3.6.3" + } + }, + "workbox-streams": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/workbox-streams/-/workbox-streams-3.6.3.tgz", + "integrity": "sha512-rqDuS4duj+3aZUYI1LsrD2t9hHOjwPqnUIfrXSOxSVjVn83W2MisDF2Bj+dFUZv4GalL9xqErcFW++9gH+Z27w==", + "dev": true, + "requires": { + "workbox-core": "^3.6.3" + } + }, + "workbox-sw": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/workbox-sw/-/workbox-sw-3.6.3.tgz", + "integrity": "sha512-IQOUi+RLhvYCiv80RP23KBW/NTtIvzvjex28B8NW1jOm+iV4VIu3VXKXTA6er5/wjjuhmtB28qEAUqADLAyOSg==", + "dev": true + }, + "workbox-webpack-plugin": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/workbox-webpack-plugin/-/workbox-webpack-plugin-3.6.3.tgz", + "integrity": "sha512-RwmKjc7HFHUFHoOlKoZUq9349u0QN3F8W5tZZU0vc1qsBZDINWXRiIBCAKvo/Njgay5sWz7z4I2adnyTo97qIQ==", + "dev": true, + "requires": { + "babel-runtime": "^6.26.0", + "json-stable-stringify": "^1.0.1", + "workbox-build": "^3.6.3" + } + }, + "worker-farm": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.6.0.tgz", + "integrity": "sha512-6w+3tHbM87WnSWnENBUvA2pxJPLhQUg5LKwUQHq3r+XPhIM+Gh2R5ycbwPCyuGbNg+lPgdcnQUhuC02kJCvffQ==", + "dev": true, + "requires": { + "errno": "~0.1.7" + } + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "write-file-atomic": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.2.tgz", + "integrity": "sha512-s0b6vB3xIVRLWywa6X9TOMA7k9zio0TMOsl9ZnDkliA/cfJlpHXAscj0gbHVJiTdIuAYpIyqS5GW91fqm6gG5g==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + }, + "write-file-webpack-plugin": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/write-file-webpack-plugin/-/write-file-webpack-plugin-4.5.0.tgz", + "integrity": "sha512-k46VeERtaezbmjpDcMWATjKUWBrVe/ZEEm0cyvUm8FFP8A/r+dw5x3psRvkUOhqh9bqBLUlGYYbtr6luI+HeAg==", + "dev": true, + "requires": { + "chalk": "^2.4.0", + "debug": "^3.1.0", + "filesize": "^3.6.1", + "lodash": "^4.17.5", + "mkdirp": "^0.5.1", + "moment": "^2.22.1", + "write-file-atomic": "^2.3.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "ws": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.1.4.tgz", + "integrity": "sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0" + } + }, + "xml": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", + "integrity": "sha1-eLpyAgApxbyHuKgaPPzXS0ovweU=", + "dev": true + }, + "xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", + "dev": true + }, + "xml2js": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", + "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", + "dev": true, + "requires": { + "sax": ">=0.6.0", + "xmlbuilder": "~9.0.1" + } + }, + "xmlbuilder": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", + "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=", + "dev": true + }, + "xmlhttprequest-ssl": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", + "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=", + "dev": true + }, + "xregexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-4.0.0.tgz", + "integrity": "sha512-PHyM+sQouu7xspQQwELlGwwd05mXUFqwFYfqPO0cC7x4fxyHnnuetmQr6CjJiafIDoH4MogHb9dOoJzR/Y4rFg==", + "dev": true + }, + "xtend": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", + "dev": true + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + }, + "yallist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", + "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", + "dev": true + }, + "yargs": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-9.0.1.tgz", + "integrity": "sha1-UqzCP+7Kw0BCB47njAwAf1CF20w=", + "dev": true, + "requires": { + "camelcase": "^4.1.0", + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "os-locale": "^2.0.0", + "read-pkg-up": "^2.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^7.0.0" + }, + "dependencies": { + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", + "dev": true + } + } + }, + "yargs-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-7.0.0.tgz", + "integrity": "sha1-jQrELxbqVd69MyyvTEA4s+P139k=", + "dev": true, + "requires": { + "camelcase": "^4.1.0" + } + }, + "yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=", + "dev": true + }, + "yeoman-environment": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/yeoman-environment/-/yeoman-environment-2.3.0.tgz", + "integrity": "sha512-PHSAkVOqYdcR+C+Uht1SGC4eVD/9OhygYFkYaI66xF8vKIeS1RNYay+umj2ZrQeJ50tF5Q/RSO6qGDz9y3Ifug==", + "dev": true, + "requires": { + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^3.1.0", + "diff": "^3.3.1", + "escape-string-regexp": "^1.0.2", + "globby": "^8.0.1", + "grouped-queue": "^0.3.3", + "inquirer": "^5.2.0", + "is-scoped": "^1.0.0", + "lodash": "^4.17.10", + "log-symbols": "^2.1.0", + "mem-fs": "^1.1.0", + "strip-ansi": "^4.0.0", + "text-table": "^0.2.0", + "untildify": "^3.0.2" + }, + "dependencies": { + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true + }, + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "dir-glob": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.0.0.tgz", + "integrity": "sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "path-type": "^3.0.0" + } + }, + "globby": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-8.0.2.tgz", + "integrity": "sha512-yTzMmKygLp8RUpG1Ymu2VXPSJQZjNAZPD4ywgYEaG7e4tBJeUQBO8OpXrf1RCNcEs5alsoJYPAMiIHP0cmeC7w==", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "dir-glob": "2.0.0", + "fast-glob": "^2.0.2", + "glob": "^7.1.2", + "ignore": "^3.3.5", + "pify": "^3.0.0", + "slash": "^1.0.0" + } + }, + "inquirer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-5.2.0.tgz", + "integrity": "sha512-E9BmnJbAKLPGonz0HeWHtbKf+EeSP93paWO3ZYoUpq/aowXvYGjjCSuashhXPpzbArIjBbji39THkxTz9ZeEUQ==", + "dev": true, + "requires": { + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.0", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^2.1.0", + "figures": "^2.0.0", + "lodash": "^4.3.0", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rxjs": "^5.5.2", + "string-width": "^2.1.0", + "strip-ansi": "^4.0.0", + "through": "^2.3.6" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "rxjs": { + "version": "5.5.12", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.12.tgz", + "integrity": "sha512-xx2itnL5sBbqeeiVgNPVuQQ1nC8Jp2WfNJhXWHmElW9YmrpS9UVnNzhP3EH3HFqexO5Tlp8GhYY+WEcqcVMvGw==", + "dev": true, + "requires": { + "symbol-observable": "1.0.1" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "symbol-observable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.1.tgz", + "integrity": "sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ=", + "dev": true + } + } + }, + "yeoman-generator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/yeoman-generator/-/yeoman-generator-3.0.0.tgz", + "integrity": "sha512-aHsNXzkdgAoakZTZsDX7T56wYWYd1O5E/GBIFAVMJLH7TKRr+1MiEJszZQbbCSA+J+lpT743/8L88j35yNdTLQ==", + "dev": true, + "requires": { + "async": "^2.6.0", + "chalk": "^2.3.0", + "cli-table": "^0.3.1", + "cross-spawn": "^6.0.5", + "dargs": "^6.0.0", + "dateformat": "^3.0.3", + "debug": "^3.1.0", + "detect-conflict": "^1.0.0", + "error": "^7.0.2", + "find-up": "^3.0.0", + "github-username": "^4.0.0", + "istextorbinary": "^2.2.1", + "lodash": "^4.17.10", + "make-dir": "^1.1.0", + "mem-fs-editor": "^5.0.0", + "minimist": "^1.2.0", + "pretty-bytes": "^5.1.0", + "read-chunk": "^2.1.0", + "read-pkg-up": "^4.0.0", + "rimraf": "^2.6.2", + "run-async": "^2.0.0", + "shelljs": "^0.8.0", + "text-table": "^0.2.0", + "through2": "^2.0.0", + "yeoman-environment": "^2.0.5" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz", + "integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==", + "dev": true, + "requires": { + "lodash": "^4.17.11" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "p-limit": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", + "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.1.0.tgz", + "integrity": "sha512-H2RyIJ7+A3rjkwKC2l5GGtU4H1vkxKCAGsWasNVd0Set+6i4znxbWy6/j16YDPJDWxhsgZiKAstMEP8wCdSpjA==", + "dev": true + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + } + }, + "read-pkg-up": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", + "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", + "dev": true, + "requires": { + "find-up": "^3.0.0", + "read-pkg": "^3.0.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "yup": { + "version": "0.26.10", + "resolved": "https://registry.npmjs.org/yup/-/yup-0.26.10.tgz", + "integrity": "sha512-keuNEbNSnsOTOuGCt3UJW69jDE3O4P+UHAakO7vSeFMnjaitcmlbij/a3oNb9g1Y1KvSKH/7O1R2PQ4m4TRylw==", + "dev": true, + "requires": { + "@babel/runtime": "7.0.0", + "fn-name": "~2.0.1", + "lodash": "^4.17.10", + "property-expr": "^1.5.0", + "synchronous-promise": "^2.0.5", + "toposort": "^2.0.2" + }, + "dependencies": { + "toposort": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz", + "integrity": "sha1-riF2gXXRVZ1IvvNUILL0li8JwzA=", + "dev": true + } + } + }, + "zone.js": { + "version": "0.8.29", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.8.29.tgz", + "integrity": "sha512-mla2acNCMkWXBD+c+yeUrBUrzOxYMNFdQ6FGfigGGtEVBPJx07BQeJekjt9DmH1FtZek4E9rE1eRR9qQpxACOQ==" + } + } +} diff --git a/jhipster-5/bookstore-monolith/package.json b/jhipster-5/bookstore-monolith/package.json new file mode 100644 index 0000000000..46b920edb3 --- /dev/null +++ b/jhipster-5/bookstore-monolith/package.json @@ -0,0 +1,128 @@ +{ + "name": "bookstore", + "version": "0.0.0", + "description": "Description for Bookstore", + "private": true, + "license": "UNLICENSED", + "cacheDirectories": [ + "node_modules" + ], + "dependencies": { + "@angular/common": "7.2.4", + "@angular/compiler": "7.2.4", + "@angular/core": "7.2.4", + "@angular/forms": "7.2.4", + "@angular/platform-browser": "7.2.4", + "@angular/platform-browser-dynamic": "7.2.4", + "@angular/router": "7.2.4", + "@fortawesome/angular-fontawesome": "0.3.0", + "@fortawesome/fontawesome-svg-core": "1.2.14", + "@fortawesome/free-solid-svg-icons": "5.7.1", + "@ng-bootstrap/ng-bootstrap": "4.0.2", + "@ngx-translate/core": "11.0.1", + "@ngx-translate/http-loader": "4.0.0", + "bootstrap": "4.2.1", + "core-js": "2.6.4", + "moment": "2.24.0", + "ng-jhipster": "0.9.1", + "ngx-cookie": "2.0.1", + "ngx-infinite-scroll": "7.0.1", + "ngx-webstorage": "2.0.1", + "rxjs": "6.4.0", + "swagger-ui": "2.2.10", + "tslib": "1.9.3", + "zone.js": "0.8.29" + }, + "devDependencies": { + "@angular/cli": "7.3.1", + "@angular/compiler-cli": "7.2.4", + "@ngtools/webpack": "7.3.1", + "@types/jest": "24.0.0", + "@types/node": "10.12.24", + "angular-router-loader": "0.8.5", + "angular2-template-loader": "0.6.2", + "autoprefixer": "9.4.7", + "browser-sync": "2.26.3", + "browser-sync-webpack-plugin": "2.2.2", + "cache-loader": "2.0.1", + "codelyzer": "4.5.0", + "copy-webpack-plugin": "4.6.0", + "css-loader": "2.1.0", + "file-loader": "3.0.1", + "fork-ts-checker-webpack-plugin": "0.5.2", + "friendly-errors-webpack-plugin": "1.7.0", + "generator-jhipster": "5.8.2", + "html-loader": "0.5.5", + "html-webpack-plugin": "3.2.0", + "husky": "1.3.1", + "jest": "24.1.0", + "jest-junit": "6.2.1", + "jest-preset-angular": "6.0.2", + "jest-sonar-reporter": "2.0.0", + "lint-staged": "8.1.3", + "mini-css-extract-plugin": "0.5.0", + "moment-locales-webpack-plugin": "1.0.7", + "optimize-css-assets-webpack-plugin": "5.0.1", + "prettier": "1.16.4", + "reflect-metadata": "0.1.13", + "rimraf": "2.6.3", + "simple-progress-webpack-plugin": "1.1.2", + "style-loader": "0.23.1", + "terser-webpack-plugin": "1.2.2", + "thread-loader": "2.1.2", + "to-string-loader": "1.1.5", + "ts-loader": "5.3.3", + "tslint": "5.12.1", + "tslint-config-prettier": "1.18.0", + "tslint-loader": "3.6.0", + "typescript": "3.2.4", + "sass": "1.17.0", + "sass-loader": "7.1.0", + "postcss-loader": "3.0.0", + "xml2js": "0.4.19", + "webpack": "4.29.3", + "webpack-cli": "3.2.3", + "webpack-dev-server": "3.1.14", + "webpack-merge": "4.2.1", + "webpack-notifier": "1.7.0", + "webpack-visualizer-plugin": "0.1.11", + "workbox-webpack-plugin": "3.6.3", + "write-file-webpack-plugin": "4.5.0" + }, + "engines": { + "node": ">=8.9.0" + }, + "lint-staged": { + "{,src/**/}*.{md,json,ts,css,scss}": [ + "prettier --write", + "git add" + ] + }, + "scripts": { + "prettier:format": "prettier --write \"{,src/**/}*.{md,json,ts,css,scss}\"", + "lint": "tslint --project tsconfig.json -e 'node_modules/**'", + "lint:fix": "npm run lint -- --fix", + "ngc": "ngc -p tsconfig-aot.json", + "cleanup": "rimraf target/{aot,www}", + "clean-www": "rimraf target//www/app/{src,target/}", + "start": "npm run webpack:dev", + "start-tls": "npm run webpack:dev -- --env.tls", + "serve": "npm run start", + "build": "npm run webpack:prod", + "test": "npm run lint && jest --coverage --logHeapUsage -w=2 --config src/test/javascript/jest.conf.js", + "test:watch": "npm run test -- --watch", + "webpack:dev": "npm run webpack-dev-server -- --config webpack/webpack.dev.js --inline --hot --port=9060 --watch-content-base --env.stats=minimal", + "webpack:dev-verbose": "npm run webpack-dev-server -- --config webpack/webpack.dev.js --inline --hot --port=9060 --watch-content-base --profile --progress --env.stats=normal", + "webpack:build:main": "npm run webpack -- --config webpack/webpack.dev.js --env.stats=minimal", + "webpack:build": "npm run cleanup && npm run webpack:build:main", + "webpack:prod:main": "npm run webpack -- --config webpack/webpack.prod.js --profile", + "webpack:prod": "npm run cleanup && npm run webpack:prod:main && npm run clean-www", + "webpack:test": "npm run test", + "webpack-dev-server": "node --max_old_space_size=4096 node_modules/webpack-dev-server/bin/webpack-dev-server.js", + "webpack": "node --max_old_space_size=4096 node_modules/webpack/bin/webpack.js" + }, + "jestSonar": { + "reportPath": "target/test-results/jest", + "reportFile": "TESTS-results-sonar.xml" + } +} diff --git a/jhipster-5/bookstore-monolith/pom.xml b/jhipster-5/bookstore-monolith/pom.xml new file mode 100644 index 0000000000..60fc1acf92 --- /dev/null +++ b/jhipster-5/bookstore-monolith/pom.xml @@ -0,0 +1,1085 @@ + + + 4.0.0 + + com.baeldung.jhipster5 + bookstore + 0.0.1-SNAPSHOT + war + Bookstore + + + + + + + + + + + + + + + io.github.jhipster + jhipster-dependencies + ${jhipster-dependencies.version} + pom + import + + + + + + + + io.github.jhipster + jhipster-framework + + + + com.fasterxml.jackson.datatype + jackson-datatype-hibernate5 + + + com.fasterxml.jackson.datatype + jackson-datatype-hppc + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + com.fasterxml.jackson.module + jackson-module-afterburner + + + com.h2database + h2 + test + + + com.jayway.jsonpath + json-path + test + + + + io.springfox + springfox-swagger2 + + + io.springfox + springfox-bean-validators + + + com.mattbertolini + liquibase-slf4j + + + com.zaxxer + HikariCP + + + commons-io + commons-io + + + org.apache.commons + commons-lang3 + + + mysql + mysql-connector-java + + + org.assertj + assertj-core + test + + + org.hibernate + hibernate-jpamodelgen + provided + + + org.hibernate + hibernate-envers + + + org.hibernate.validator + hibernate-validator + + + org.liquibase + liquibase-core + + + net.logstash.logback + logstash-logback-encoder + + + org.mapstruct + mapstruct-jdk8 + + + org.mapstruct + mapstruct-processor + provided + + + org.springframework.boot + spring-boot-configuration-processor + provided + + + org.springframework.boot + spring-boot-loader-tools + + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.boot + spring-boot-starter-aop + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.boot + spring-boot-starter-logging + + + org.springframework.boot + spring-boot-starter-mail + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.boot + spring-boot-test + test + + + org.springframework.security + spring-security-test + test + + + org.zalando + problem-spring-web + + + io.jsonwebtoken + jjwt-api + + + io.jsonwebtoken + jjwt-impl + runtime + + + io.jsonwebtoken + jjwt-jackson + runtime + + + + org.springframework.boot + spring-boot-starter-cloud-connectors + + + + org.springframework.security + spring-security-data + + + io.micrometer + micrometer-registry-prometheus + + + io.dropwizard.metrics + metrics-core + + + + + + spring-boot:run + + + org.apache.maven.plugins + maven-compiler-plugin + + + + org.mapstruct + mapstruct-processor + ${mapstruct.version} + + + + org.hibernate + hibernate-jpamodelgen + ${hibernate.version} + + + + + + + org.apache.maven.plugins + maven-eclipse-plugin + + + org.apache.maven.plugins + maven-enforcer-plugin + + + org.apache.maven.plugins + maven-idea-plugin + + + org.apache.maven.plugins + maven-resources-plugin + + + org.apache.maven.plugins + maven-surefire-plugin + + + org.jacoco + jacoco-maven-plugin + + + org.sonarsource.scanner.maven + sonar-maven-plugin + + + org.liquibase + liquibase-maven-plugin + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + ${start-class} + true + true + + + + + com.google.cloud.tools + jib-maven-plugin + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + + com.github.eirslett + frontend-maven-plugin + ${frontend-maven-plugin.version} + + + pl.project13.maven + git-commit-id-plugin + ${git-commit-id-plugin.version} + + + + revision + + + + + false + true + + ^git.commit.id.abbrev$ + ^git.commit.id.describe$ + ^git.branch$ + + + + + org.jacoco + jacoco-maven-plugin + ${jacoco-maven-plugin.version} + + + pre-unit-tests + + prepare-agent + + + + ${project.testresult.directory}/coverage/jacoco/jacoco.exec + + + + + post-unit-test + test + + report + + + ${project.testresult.directory}/coverage/jacoco/jacoco.exec + ${project.testresult.directory}/coverage/jacoco + + + + + + com.google.cloud.tools + jib-maven-plugin + ${jib-maven-plugin.version} + + + openjdk:8-jre-alpine + + + bookstore:latest + + + + sh + + chmod +x /entrypoint.sh && sync && /entrypoint.sh + + + 8080 + + + ALWAYS + 0 + + true + + + + + org.liquibase + liquibase-maven-plugin + ${liquibase.version} + + ${project.basedir}/src/main/resources/config/liquibase/master.xml + ${project.basedir}/src/main/resources/config/liquibase/changelog/${maven.build.timestamp}_changelog.xml + + + + Bookstore + + hibernate:spring:com.baeldung.jhipster5.domain?dialect=&hibernate.physical_naming_strategy=org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy&hibernate.implicit_naming_strategy=org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy + true + debug + + + + org.javassist + javassist + ${javassist.version} + + + org.liquibase.ext + liquibase-hibernate5 + ${liquibase-hibernate5.version} + + + org.springframework.boot + spring-boot-starter-data-jpa + ${spring-boot.version} + + + javax.validation + validation-api + ${validation-api.version} + + + + + maven-clean-plugin + ${maven-clean-plugin.version} + + + org.apache.maven.plugins + maven-eclipse-plugin + ${maven-eclipse-plugin.version} + + true + true + + + + org.apache.maven.plugins + maven-enforcer-plugin + ${maven-enforcer-plugin.version} + + + enforce-versions + + enforce + + + + + + + You are running an older version of Maven. JHipster requires at least Maven ${maven.version} + [${maven.version},) + + + + You are running an incompatible version of Java. JHipster requires JDK ${java.version} + [1.8,1.9) + + + + + + org.apache.maven.plugins + maven-idea-plugin + ${maven-idea-plugin.version} + + node_modules + + + + org.apache.maven.plugins + maven-resources-plugin + ${maven-resources-plugin.version} + + + default-resources + validate + + copy-resources + + + ${project.build.directory}/classes + false + + # + + + + src/main/resources/ + true + + config/*.yml + + + + src/main/resources/ + false + + config/*.yml + + + + + + + jib-www-resources + verify + + copy-resources + + + ${project.build.directory}/classes/static/ + + + ${project.build.directory}/www + false + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + ${maven-surefire-plugin.version} + + + alphabetical + + + false + ${sonar.junit.reportsPath} + + + + org.apache.maven.plugins + maven-war-plugin + ${maven-war-plugin.version} + + + net.alchim31.maven + scala-maven-plugin + ${scala-maven-plugin.version} + + + compile + compile + + add-source + compile + + + + test-compile + test-compile + + add-source + testCompile + + + + + incremental + true + ${scala.version} + + + + org.sonarsource.scanner.maven + sonar-maven-plugin + ${sonar-maven-plugin.version} + + + org.springframework.boot + spring-boot-maven-plugin + ${spring-boot.version} + + + + + + + no-liquibase + + ,no-liquibase + + + + swagger + + ,swagger + + + + tls + + ,tls + + + + webpack + + + ${basedir}/target/www/app/main.bundle.js + + + + + org.springframework.boot + spring-boot-starter-undertow + + + org.springframework.boot + spring-boot-devtools + true + + + com.h2database + h2 + + + + + + com.github.eirslett + frontend-maven-plugin + + + install node and npm + + install-node-and-npm + + + ${node.version} + ${npm.version} + + + + npm install + + npm + + + + webpack build dev + + npm + + generate-resources + + run webpack:build + false + + + + + + org.apache.maven.plugins + maven-war-plugin + + false + target/www/ + + + src/main/webapp + + WEB-INF/** + + + + + + + + + + dev${profile.no-liquibase} + + + + dev + + true + + + + org.springframework.boot + spring-boot-starter-undertow + + + org.springframework.boot + spring-boot-devtools + true + + + com.h2database + h2 + + + + + + org.apache.maven.plugins + maven-war-plugin + + false + target/www/ + + + src/main/webapp + + WEB-INF/** + + + + + + + + + + dev${profile.tls}${profile.no-liquibase} + + + + prod + + + org.springframework.boot + spring-boot-starter-undertow + + + + + + maven-clean-plugin + + + + target/www/ + + + + + + org.apache.maven.plugins + maven-war-plugin + + false + target/www/ + + + src/main/webapp + + WEB-INF/** + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + ${start-class} + true + + + + + build-info + + + + + + com.github.eirslett + frontend-maven-plugin + + + install node and npm + + install-node-and-npm + + + ${node.version} + ${npm.version} + + + + npm install + + npm + + + install + + + + webpack build test + + npm + + test + + run webpack:test + false + + + + webpack build prod + + npm + + generate-resources + + run webpack:prod + false + + + + + + pl.project13.maven + git-commit-id-plugin + + + + + + prod${profile.swagger}${profile.no-liquibase} + + + + + cc + + + org.springframework.boot + spring-boot-starter-undertow + + + org.springframework.boot + spring-boot-devtools + true + + + + + + org.apache.maven.plugins + maven-war-plugin + + false + src/main/webapp/ + + + + org.springframework.boot + spring-boot-maven-plugin + + ${start-class} + true + true + true + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + default-compile + none + + + default-testCompile + none + + + + + net.alchim31.maven + scala-maven-plugin + + + + + + dev,swagger + + + + + IDE + + + org.mapstruct + mapstruct-processor + + + org.hibernate + hibernate-jpamodelgen + + + + + + eclipse + + + m2e.version + + + + + + + + org.eclipse.m2e + lifecycle-mapping + ${lifecycle-mapping.version} + + + + + + org.jacoco + + jacoco-maven-plugin + + + ${jacoco-maven-plugin.version} + + + prepare-agent + + + + + + + + + com.github.eirslett + frontend-maven-plugin + ${frontend-maven-plugin.version} + + install-node-and-npm + npm + + + + + + + + + + + + + + + + + + + + 3.0.0 + 1.8 + 2.12.6 + v10.15.0 + 6.4.1 + UTF-8 + UTF-8 + ${project.build.directory}/test-results + yyyyMMddHHmmss + ${java.version} + ${java.version} + -Djava.security.egd=file:/dev/./urandom -Xmx256m + jdt_apt + false + + + + + + + 2.1.1 + + 2.0.8.RELEASE + + 5.2.17.Final + + 3.22.0-GA + + 3.5.5 + 3.6 + 2.0.1.Final + 1.2.0.Final + + + 3.1.0 + 3.8.0 + 2.10 + 3.0.0-M2 + 2.2.1 + 3.1.0 + 2.22.1 + 3.2.2 + 0.9.11 + 1.6 + 0.8.2 + 1.0.0 + 3.4.2 + 3.5.0.1254 + 2.2.5 + + + http://localhost:9001 + src/main/webapp/content/**/*.*, src/main/webapp/i18n/*.js, target/www/**/*.* + S3437,S4502,S4684,UndocumentedApi,BoldAndItalicTagsCheck + + src/main/webapp/app/**/*.* + Web:BoldAndItalicTagsCheck + + src/main/java/**/* + squid:S3437 + + src/main/java/**/* + squid:UndocumentedApi + + src/main/java/**/* + squid:S4502 + + src/main/java/**/* + squid:S4684 + ${project.testresult.directory}/coverage/jacoco/jacoco.exec + jacoco + ${project.testresult.directory}/lcov.info + ${project.basedir}/src/main/ + ${project.testresult.directory} + ${project.basedir}/src/test/ + + + + diff --git a/jhipster-5/bookstore-monolith/postcss.config.js b/jhipster-5/bookstore-monolith/postcss.config.js new file mode 100644 index 0000000000..a26de7e9f1 --- /dev/null +++ b/jhipster-5/bookstore-monolith/postcss.config.js @@ -0,0 +1,5 @@ +module.exports = { + plugins: [ + require('autoprefixer') + ] +} diff --git a/jhipster-5/bookstore-monolith/proxy.conf.json b/jhipster-5/bookstore-monolith/proxy.conf.json new file mode 100644 index 0000000000..8b41fdf7fa --- /dev/null +++ b/jhipster-5/bookstore-monolith/proxy.conf.json @@ -0,0 +1,7 @@ +{ + "*": { + "target": "http://localhost:8080", + "secure": false, + "loglevel": "debug" + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/docker/.dockerignore b/jhipster-5/bookstore-monolith/src/main/docker/.dockerignore new file mode 100644 index 0000000000..b03bdc71ee --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/docker/.dockerignore @@ -0,0 +1,14 @@ +# https://docs.docker.com/engine/reference/builder/#dockerignore-file +classes/ +generated-sources/ +generated-test-sources/ +h2db/ +maven-archiver/ +maven-status/ +reports/ +surefire-reports/ +test-classes/ +test-results/ +www/ +!*.jar +!*.war diff --git a/jhipster-5/bookstore-monolith/src/main/docker/Dockerfile b/jhipster-5/bookstore-monolith/src/main/docker/Dockerfile new file mode 100644 index 0000000000..43fadcb6f8 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/docker/Dockerfile @@ -0,0 +1,20 @@ +FROM openjdk:8-jre-alpine + +ENV SPRING_OUTPUT_ANSI_ENABLED=ALWAYS \ + JHIPSTER_SLEEP=0 \ + JAVA_OPTS="" + +# Add a jhipster user to run our application so that it doesn't need to run as root +RUN adduser -D -s /bin/sh jhipster +WORKDIR /home/jhipster + +ADD entrypoint.sh entrypoint.sh +RUN chmod 755 entrypoint.sh && chown jhipster:jhipster entrypoint.sh +USER jhipster + +ENTRYPOINT ["./entrypoint.sh"] + +EXPOSE 8080 + +ADD *.war app.war + diff --git a/jhipster-5/bookstore-monolith/src/main/docker/app.yml b/jhipster-5/bookstore-monolith/src/main/docker/app.yml new file mode 100644 index 0000000000..f60f0f5038 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/docker/app.yml @@ -0,0 +1,15 @@ +version: '2' +services: + bookstore-app: + image: bookstore + environment: + - _JAVA_OPTIONS=-Xmx512m -Xms256m + - SPRING_PROFILES_ACTIVE=prod,swagger + - SPRING_DATASOURCE_URL=jdbc:mysql://bookstore-mysql:3306/bookstore?useUnicode=true&characterEncoding=utf8&useSSL=false + - JHIPSTER_SLEEP=10 # gives time for the database to boot before the application + ports: + - 8080:8080 + bookstore-mysql: + extends: + file: mysql.yml + service: bookstore-mysql diff --git a/jhipster-5/bookstore-monolith/src/main/docker/entrypoint.sh b/jhipster-5/bookstore-monolith/src/main/docker/entrypoint.sh new file mode 100644 index 0000000000..ccffafb5a4 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/docker/entrypoint.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +echo "The application will start in ${JHIPSTER_SLEEP}s..." && sleep ${JHIPSTER_SLEEP} +exec java ${JAVA_OPTS} -Djava.security.egd=file:/dev/./urandom -jar "${HOME}/app.war" "$@" diff --git a/jhipster-5/bookstore-monolith/src/main/docker/mysql.yml b/jhipster-5/bookstore-monolith/src/main/docker/mysql.yml new file mode 100644 index 0000000000..13faba0457 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/docker/mysql.yml @@ -0,0 +1,13 @@ +version: '2' +services: + bookstore-mysql: + image: mysql:5.7.20 + # volumes: + # - ~/volumes/jhipster/Bookstore/mysql/:/var/lib/mysql/ + environment: + - MYSQL_USER=root + - MYSQL_ALLOW_EMPTY_PASSWORD=yes + - MYSQL_DATABASE=bookstore + ports: + - 3306:3306 + command: mysqld --lower_case_table_names=1 --skip-ssl --character_set_server=utf8mb4 --explicit_defaults_for_timestamp diff --git a/jhipster-5/bookstore-monolith/src/main/docker/sonar.yml b/jhipster-5/bookstore-monolith/src/main/docker/sonar.yml new file mode 100644 index 0000000000..756175b7d0 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/docker/sonar.yml @@ -0,0 +1,7 @@ +version: '2' +services: + bookstore-sonar: + image: sonarqube:7.1 + ports: + - 9001:9000 + - 9092:9092 diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/ApplicationWebXml.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/ApplicationWebXml.java new file mode 100644 index 0000000000..ca65727e77 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/ApplicationWebXml.java @@ -0,0 +1,21 @@ +package com.baeldung.jhipster5; + +import com.baeldung.jhipster5.config.DefaultProfileUtil; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; + +/** + * This is a helper Java class that provides an alternative to creating a web.xml. + * This will be invoked only when the application is deployed to a Servlet container like Tomcat, JBoss etc. + */ +public class ApplicationWebXml extends SpringBootServletInitializer { + + @Override + protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { + /** + * set a default to use when no profile is configured. + */ + DefaultProfileUtil.addDefaultProfile(application.application()); + return application.sources(BookstoreApp.class); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/BookstoreApp.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/BookstoreApp.java new file mode 100644 index 0000000000..e7ca925228 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/BookstoreApp.java @@ -0,0 +1,98 @@ +package com.baeldung.jhipster5; + +import com.baeldung.jhipster5.config.ApplicationProperties; +import com.baeldung.jhipster5.config.DefaultProfileUtil; + +import io.github.jhipster.config.JHipsterConstants; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.core.env.Environment; + +import javax.annotation.PostConstruct; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Arrays; +import java.util.Collection; + +@SpringBootApplication +@EnableConfigurationProperties({LiquibaseProperties.class, ApplicationProperties.class}) +public class BookstoreApp { + + private static final Logger log = LoggerFactory.getLogger(BookstoreApp.class); + + private final Environment env; + + public BookstoreApp(Environment env) { + this.env = env; + } + + /** + * Initializes Bookstore. + *

+ * Spring profiles can be configured with a program argument --spring.profiles.active=your-active-profile + *

+ * You can find more information on how profiles work with JHipster on https://www.jhipster.tech/profiles/. + */ + @PostConstruct + public void initApplication() { + Collection activeProfiles = Arrays.asList(env.getActiveProfiles()); + if (activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT) && activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_PRODUCTION)) { + log.error("You have misconfigured your application! It should not run " + + "with both the 'dev' and 'prod' profiles at the same time."); + } + if (activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT) && activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_CLOUD)) { + log.error("You have misconfigured your application! It should not " + + "run with both the 'dev' and 'cloud' profiles at the same time."); + } + } + + /** + * Main method, used to run the application. + * + * @param args the command line arguments + */ + public static void main(String[] args) { + SpringApplication app = new SpringApplication(BookstoreApp.class); + DefaultProfileUtil.addDefaultProfile(app); + Environment env = app.run(args).getEnvironment(); + logApplicationStartup(env); + } + + private static void logApplicationStartup(Environment env) { + String protocol = "http"; + if (env.getProperty("server.ssl.key-store") != null) { + protocol = "https"; + } + String serverPort = env.getProperty("server.port"); + String contextPath = env.getProperty("server.servlet.context-path"); + if (StringUtils.isBlank(contextPath)) { + contextPath = "/"; + } + String hostAddress = "localhost"; + try { + hostAddress = InetAddress.getLocalHost().getHostAddress(); + } catch (UnknownHostException e) { + log.warn("The host name could not be determined, using `localhost` as fallback"); + } + log.info("\n----------------------------------------------------------\n\t" + + "Application '{}' is running! Access URLs:\n\t" + + "Local: \t\t{}://localhost:{}{}\n\t" + + "External: \t{}://{}:{}{}\n\t" + + "Profile(s): \t{}\n----------------------------------------------------------", + env.getProperty("spring.application.name"), + protocol, + serverPort, + contextPath, + protocol, + hostAddress, + serverPort, + contextPath, + env.getActiveProfiles()); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/aop/logging/LoggingAspect.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/aop/logging/LoggingAspect.java new file mode 100644 index 0000000000..0379637061 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/aop/logging/LoggingAspect.java @@ -0,0 +1,98 @@ +package com.baeldung.jhipster5.aop.logging; + +import io.github.jhipster.config.JHipsterConstants; + +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.AfterThrowing; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.env.Environment; + +import java.util.Arrays; + +/** + * Aspect for logging execution of service and repository Spring components. + * + * By default, it only runs with the "dev" profile. + */ +@Aspect +public class LoggingAspect { + + private final Logger log = LoggerFactory.getLogger(this.getClass()); + + private final Environment env; + + public LoggingAspect(Environment env) { + this.env = env; + } + + /** + * Pointcut that matches all repositories, services and Web REST endpoints. + */ + @Pointcut("within(@org.springframework.stereotype.Repository *)" + + " || within(@org.springframework.stereotype.Service *)" + + " || within(@org.springframework.web.bind.annotation.RestController *)") + public void springBeanPointcut() { + // Method is empty as this is just a Pointcut, the implementations are in the advices. + } + + /** + * Pointcut that matches all Spring beans in the application's main packages. + */ + @Pointcut("within(com.baeldung.jhipster5.repository..*)"+ + " || within(com.baeldung.jhipster5.service..*)"+ + " || within(com.baeldung.jhipster5.web.rest..*)") + public void applicationPackagePointcut() { + // Method is empty as this is just a Pointcut, the implementations are in the advices. + } + + /** + * Advice that logs methods throwing exceptions. + * + * @param joinPoint join point for advice + * @param e exception + */ + @AfterThrowing(pointcut = "applicationPackagePointcut() && springBeanPointcut()", throwing = "e") + public void logAfterThrowing(JoinPoint joinPoint, Throwable e) { + if (env.acceptsProfiles(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT)) { + log.error("Exception in {}.{}() with cause = \'{}\' and exception = \'{}\'", joinPoint.getSignature().getDeclaringTypeName(), + joinPoint.getSignature().getName(), e.getCause() != null? e.getCause() : "NULL", e.getMessage(), e); + + } else { + log.error("Exception in {}.{}() with cause = {}", joinPoint.getSignature().getDeclaringTypeName(), + joinPoint.getSignature().getName(), e.getCause() != null? e.getCause() : "NULL"); + } + } + + /** + * Advice that logs when a method is entered and exited. + * + * @param joinPoint join point for advice + * @return result + * @throws Throwable throws IllegalArgumentException + */ + @Around("applicationPackagePointcut() && springBeanPointcut()") + public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable { + if (log.isDebugEnabled()) { + log.debug("Enter: {}.{}() with argument[s] = {}", joinPoint.getSignature().getDeclaringTypeName(), + joinPoint.getSignature().getName(), Arrays.toString(joinPoint.getArgs())); + } + try { + Object result = joinPoint.proceed(); + if (log.isDebugEnabled()) { + log.debug("Exit: {}.{}() with result = {}", joinPoint.getSignature().getDeclaringTypeName(), + joinPoint.getSignature().getName(), result); + } + return result; + } catch (IllegalArgumentException e) { + log.error("Illegal argument: {} in {}.{}()", Arrays.toString(joinPoint.getArgs()), + joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName()); + + throw e; + } + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/ApplicationProperties.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/ApplicationProperties.java new file mode 100644 index 0000000000..4ca3e9bd85 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/ApplicationProperties.java @@ -0,0 +1,14 @@ +package com.baeldung.jhipster5.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * Properties specific to Bookstore. + *

+ * Properties are configured in the application.yml file. + * See {@link io.github.jhipster.config.JHipsterProperties} for a good example. + */ +@ConfigurationProperties(prefix = "application", ignoreUnknownFields = false) +public class ApplicationProperties { + +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/AsyncConfiguration.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/AsyncConfiguration.java new file mode 100644 index 0000000000..414fe152bf --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/AsyncConfiguration.java @@ -0,0 +1,59 @@ +package com.baeldung.jhipster5.config; + +import io.github.jhipster.async.ExceptionHandlingAsyncTaskExecutor; +import io.github.jhipster.config.JHipsterProperties; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; +import org.springframework.aop.interceptor.SimpleAsyncUncaughtExceptionHandler; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.*; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import org.springframework.scheduling.annotation.SchedulingConfigurer; +import org.springframework.scheduling.config.ScheduledTaskRegistrar; + +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; + +@Configuration +@EnableAsync +@EnableScheduling +public class AsyncConfiguration implements AsyncConfigurer, SchedulingConfigurer { + + private final Logger log = LoggerFactory.getLogger(AsyncConfiguration.class); + + private final JHipsterProperties jHipsterProperties; + + public AsyncConfiguration(JHipsterProperties jHipsterProperties) { + this.jHipsterProperties = jHipsterProperties; + } + + @Override + @Bean(name = "taskExecutor") + public Executor getAsyncExecutor() { + log.debug("Creating Async Task Executor"); + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setCorePoolSize(jHipsterProperties.getAsync().getCorePoolSize()); + executor.setMaxPoolSize(jHipsterProperties.getAsync().getMaxPoolSize()); + executor.setQueueCapacity(jHipsterProperties.getAsync().getQueueCapacity()); + executor.setThreadNamePrefix("bookstore-Executor-"); + return new ExceptionHandlingAsyncTaskExecutor(executor); + } + + @Override + public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { + return new SimpleAsyncUncaughtExceptionHandler(); + } + + @Override + public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { + taskRegistrar.setScheduler(scheduledTaskExecutor()); + } + + @Bean + public Executor scheduledTaskExecutor() { + return Executors.newScheduledThreadPool(jHipsterProperties.getAsync().getCorePoolSize()); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/CloudDatabaseConfiguration.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/CloudDatabaseConfiguration.java new file mode 100644 index 0000000000..887a1bae89 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/CloudDatabaseConfiguration.java @@ -0,0 +1,28 @@ +package com.baeldung.jhipster5.config; + +import io.github.jhipster.config.JHipsterConstants; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.cloud.config.java.AbstractCloudConfig; +import org.springframework.context.annotation.*; + +import javax.sql.DataSource; +import org.springframework.boot.context.properties.ConfigurationProperties; + + +@Configuration +@Profile(JHipsterConstants.SPRING_PROFILE_CLOUD) +public class CloudDatabaseConfiguration extends AbstractCloudConfig { + + private final Logger log = LoggerFactory.getLogger(CloudDatabaseConfiguration.class); + + private static final String CLOUD_CONFIGURATION_HIKARI_PREFIX = "spring.datasource.hikari"; + + @Bean + @ConfigurationProperties(CLOUD_CONFIGURATION_HIKARI_PREFIX) + public DataSource dataSource() { + log.info("Configuring JDBC datasource from a cloud provider"); + return connectionFactory().dataSource(); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/Constants.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/Constants.java new file mode 100644 index 0000000000..dd8f717f98 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/Constants.java @@ -0,0 +1,17 @@ +package com.baeldung.jhipster5.config; + +/** + * Application constants. + */ +public final class Constants { + + // Regex for acceptable logins + public static final String LOGIN_REGEX = "^[_.@A-Za-z0-9-]*$"; + + public static final String SYSTEM_ACCOUNT = "system"; + public static final String ANONYMOUS_USER = "anonymoususer"; + public static final String DEFAULT_LANGUAGE = "en"; + + private Constants() { + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/DatabaseConfiguration.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/DatabaseConfiguration.java new file mode 100644 index 0000000000..007b1d6431 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/DatabaseConfiguration.java @@ -0,0 +1,59 @@ +package com.baeldung.jhipster5.config; + +import io.github.jhipster.config.JHipsterConstants; +import io.github.jhipster.config.h2.H2ConfigurationHelper; +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; + +import org.springframework.core.env.Environment; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +import java.sql.SQLException; + +@Configuration +@EnableJpaRepositories("com.baeldung.jhipster5.repository") +@EnableJpaAuditing(auditorAwareRef = "springSecurityAuditorAware") +@EnableTransactionManagement +public class DatabaseConfiguration { + + private final Logger log = LoggerFactory.getLogger(DatabaseConfiguration.class); + + private final Environment env; + + public DatabaseConfiguration(Environment env) { + this.env = env; + } + + /** + * Open the TCP port for the H2 database, so it is available remotely. + * + * @return the H2 database TCP server + * @throws SQLException if the server failed to start + */ + @Bean(initMethod = "start", destroyMethod = "stop") + @Profile(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT) + public Object h2TCPServer() throws SQLException { + String port = getValidPortForH2(); + log.debug("H2 database is available on port {}", port); + return H2ConfigurationHelper.createServer(port); + } + + private String getValidPortForH2() { + int port = Integer.parseInt(env.getProperty("server.port")); + if (port < 10000) { + port = 10000 + port; + } else { + if (port < 63536) { + port = port + 2000; + } else { + port = port - 2000; + } + } + return String.valueOf(port); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/DateTimeFormatConfiguration.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/DateTimeFormatConfiguration.java new file mode 100644 index 0000000000..4415ce0b1e --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/DateTimeFormatConfiguration.java @@ -0,0 +1,20 @@ +package com.baeldung.jhipster5.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.format.FormatterRegistry; +import org.springframework.format.datetime.standard.DateTimeFormatterRegistrar; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +/** + * Configure the converters to use the ISO format for dates by default. + */ +@Configuration +public class DateTimeFormatConfiguration implements WebMvcConfigurer { + + @Override + public void addFormatters(FormatterRegistry registry) { + DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar(); + registrar.setUseIsoFormat(true); + registrar.registerFormatters(registry); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/DefaultProfileUtil.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/DefaultProfileUtil.java new file mode 100644 index 0000000000..2cfe16a1ae --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/DefaultProfileUtil.java @@ -0,0 +1,51 @@ +package com.baeldung.jhipster5.config; + +import io.github.jhipster.config.JHipsterConstants; + +import org.springframework.boot.SpringApplication; +import org.springframework.core.env.Environment; + +import java.util.*; + +/** + * Utility class to load a Spring profile to be used as default + * when there is no spring.profiles.active set in the environment or as command line argument. + * If the value is not available in application.yml then dev profile will be used as default. + */ +public final class DefaultProfileUtil { + + private static final String SPRING_PROFILE_DEFAULT = "spring.profiles.default"; + + private DefaultProfileUtil() { + } + + /** + * Set a default to use when no profile is configured. + * + * @param app the Spring application + */ + public static void addDefaultProfile(SpringApplication app) { + Map defProperties = new HashMap<>(); + /* + * The default profile to use when no other profiles are defined + * This cannot be set in the application.yml file. + * See https://github.com/spring-projects/spring-boot/issues/1219 + */ + defProperties.put(SPRING_PROFILE_DEFAULT, JHipsterConstants.SPRING_PROFILE_DEVELOPMENT); + app.setDefaultProperties(defProperties); + } + + /** + * Get the profiles that are applied else get default profiles. + * + * @param env spring environment + * @return profiles + */ + public static String[] getActiveProfiles(Environment env) { + String[] profiles = env.getActiveProfiles(); + if (profiles.length == 0) { + return env.getDefaultProfiles(); + } + return profiles; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/JacksonConfiguration.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/JacksonConfiguration.java new file mode 100644 index 0000000000..119cd5f0c6 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/JacksonConfiguration.java @@ -0,0 +1,63 @@ +package com.baeldung.jhipster5.config; + +import com.fasterxml.jackson.datatype.hibernate5.Hibernate5Module; +import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import com.fasterxml.jackson.module.afterburner.AfterburnerModule; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.zalando.problem.ProblemModule; +import org.zalando.problem.violations.ConstraintViolationProblemModule; + +@Configuration +public class JacksonConfiguration { + + /** + * Support for Java date and time API. + * @return the corresponding Jackson module. + */ + @Bean + public JavaTimeModule javaTimeModule() { + return new JavaTimeModule(); + } + + @Bean + public Jdk8Module jdk8TimeModule() { + return new Jdk8Module(); + } + + + /* + * Support for Hibernate types in Jackson. + */ + @Bean + public Hibernate5Module hibernate5Module() { + return new Hibernate5Module(); + } + + /* + * Jackson Afterburner module to speed up serialization/deserialization. + */ + @Bean + public AfterburnerModule afterburnerModule() { + return new AfterburnerModule(); + } + + /* + * Module for serialization/deserialization of RFC7807 Problem. + */ + @Bean + ProblemModule problemModule() { + return new ProblemModule(); + } + + /* + * Module for serialization/deserialization of ConstraintViolationProblem. + */ + @Bean + ConstraintViolationProblemModule constraintViolationProblemModule() { + return new ConstraintViolationProblemModule(); + } + +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/LiquibaseConfiguration.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/LiquibaseConfiguration.java new file mode 100644 index 0000000000..4b2a7b1e66 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/LiquibaseConfiguration.java @@ -0,0 +1,50 @@ +package com.baeldung.jhipster5.config; + +import javax.sql.DataSource; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; +import org.springframework.core.task.TaskExecutor; + +import io.github.jhipster.config.JHipsterConstants; +import io.github.jhipster.config.liquibase.AsyncSpringLiquibase; +import liquibase.integration.spring.SpringLiquibase; + +@Configuration +public class LiquibaseConfiguration { + + private final Logger log = LoggerFactory.getLogger(LiquibaseConfiguration.class); + + private final Environment env; + + + public LiquibaseConfiguration(Environment env) { + this.env = env; + } + + @Bean + public SpringLiquibase liquibase(@Qualifier("taskExecutor") TaskExecutor taskExecutor, + DataSource dataSource, LiquibaseProperties liquibaseProperties) { + + // Use liquibase.integration.spring.SpringLiquibase if you don't want Liquibase to start asynchronously + SpringLiquibase liquibase = new AsyncSpringLiquibase(taskExecutor, env); + liquibase.setDataSource(dataSource); + liquibase.setChangeLog("classpath:config/liquibase/master.xml"); + liquibase.setContexts(liquibaseProperties.getContexts()); + liquibase.setDefaultSchema(liquibaseProperties.getDefaultSchema()); + liquibase.setDropFirst(liquibaseProperties.isDropFirst()); + liquibase.setChangeLogParameters(liquibaseProperties.getParameters()); + if (env.acceptsProfiles(JHipsterConstants.SPRING_PROFILE_NO_LIQUIBASE)) { + liquibase.setShouldRun(false); + } else { + liquibase.setShouldRun(liquibaseProperties.isEnabled()); + log.debug("Configuring Liquibase"); + } + return liquibase; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/LocaleConfiguration.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/LocaleConfiguration.java new file mode 100644 index 0000000000..256c6b77b9 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/LocaleConfiguration.java @@ -0,0 +1,27 @@ +package com.baeldung.jhipster5.config; + +import io.github.jhipster.config.locale.AngularCookieLocaleResolver; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.LocaleResolver; +import org.springframework.web.servlet.config.annotation.*; +import org.springframework.web.servlet.i18n.LocaleChangeInterceptor; + +@Configuration +public class LocaleConfiguration implements WebMvcConfigurer { + + @Bean(name = "localeResolver") + public LocaleResolver localeResolver() { + AngularCookieLocaleResolver cookieLocaleResolver = new AngularCookieLocaleResolver(); + cookieLocaleResolver.setCookieName("NG_TRANSLATE_LANG_KEY"); + return cookieLocaleResolver; + } + + @Override + public void addInterceptors(InterceptorRegistry registry) { + LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor(); + localeChangeInterceptor.setParamName("language"); + registry.addInterceptor(localeChangeInterceptor); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/LoggingAspectConfiguration.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/LoggingAspectConfiguration.java new file mode 100644 index 0000000000..25d7ba3792 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/LoggingAspectConfiguration.java @@ -0,0 +1,19 @@ +package com.baeldung.jhipster5.config; + +import com.baeldung.jhipster5.aop.logging.LoggingAspect; + +import io.github.jhipster.config.JHipsterConstants; + +import org.springframework.context.annotation.*; +import org.springframework.core.env.Environment; + +@Configuration +@EnableAspectJAutoProxy +public class LoggingAspectConfiguration { + + @Bean + @Profile(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT) + public LoggingAspect loggingAspect(Environment env) { + return new LoggingAspect(env); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/LoggingConfiguration.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/LoggingConfiguration.java new file mode 100644 index 0000000000..9402a1bc36 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/LoggingConfiguration.java @@ -0,0 +1,154 @@ +package com.baeldung.jhipster5.config; + +import java.net.InetSocketAddress; +import java.util.Iterator; + +import io.github.jhipster.config.JHipsterProperties; + +import ch.qos.logback.classic.AsyncAppender; +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.LoggerContext; +import ch.qos.logback.classic.boolex.OnMarkerEvaluator; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.classic.spi.LoggerContextListener; +import ch.qos.logback.core.Appender; +import ch.qos.logback.core.filter.EvaluatorFilter; +import ch.qos.logback.core.spi.ContextAwareBase; +import ch.qos.logback.core.spi.FilterReply; +import net.logstash.logback.appender.LogstashTcpSocketAppender; +import net.logstash.logback.encoder.LogstashEncoder; +import net.logstash.logback.stacktrace.ShortenedThrowableConverter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class LoggingConfiguration { + + private static final String LOGSTASH_APPENDER_NAME = "LOGSTASH"; + + private static final String ASYNC_LOGSTASH_APPENDER_NAME = "ASYNC_LOGSTASH"; + + private final Logger log = LoggerFactory.getLogger(LoggingConfiguration.class); + + private LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); + + private final String appName; + + private final String serverPort; + + private final JHipsterProperties jHipsterProperties; + + public LoggingConfiguration(@Value("${spring.application.name}") String appName, @Value("${server.port}") String serverPort, + JHipsterProperties jHipsterProperties) { + this.appName = appName; + this.serverPort = serverPort; + this.jHipsterProperties = jHipsterProperties; + if (jHipsterProperties.getLogging().getLogstash().isEnabled()) { + addLogstashAppender(context); + addContextListener(context); + } + if (jHipsterProperties.getMetrics().getLogs().isEnabled()) { + setMetricsMarkerLogbackFilter(context); + } + } + + private void addContextListener(LoggerContext context) { + LogbackLoggerContextListener loggerContextListener = new LogbackLoggerContextListener(); + loggerContextListener.setContext(context); + context.addListener(loggerContextListener); + } + + private void addLogstashAppender(LoggerContext context) { + log.info("Initializing Logstash logging"); + + LogstashTcpSocketAppender logstashAppender = new LogstashTcpSocketAppender(); + logstashAppender.setName(LOGSTASH_APPENDER_NAME); + logstashAppender.setContext(context); + String customFields = "{\"app_name\":\"" + appName + "\",\"app_port\":\"" + serverPort + "\"}"; + + // More documentation is available at: https://github.com/logstash/logstash-logback-encoder + LogstashEncoder logstashEncoder = new LogstashEncoder(); + // Set the Logstash appender config from JHipster properties + logstashAppender.addDestinations(new InetSocketAddress(jHipsterProperties.getLogging().getLogstash().getHost(), jHipsterProperties.getLogging().getLogstash().getPort())); + + ShortenedThrowableConverter throwableConverter = new ShortenedThrowableConverter(); + throwableConverter.setRootCauseFirst(true); + logstashEncoder.setThrowableConverter(throwableConverter); + logstashEncoder.setCustomFields(customFields); + + logstashAppender.setEncoder(logstashEncoder); + logstashAppender.start(); + + // Wrap the appender in an Async appender for performance + AsyncAppender asyncLogstashAppender = new AsyncAppender(); + asyncLogstashAppender.setContext(context); + asyncLogstashAppender.setName(ASYNC_LOGSTASH_APPENDER_NAME); + asyncLogstashAppender.setQueueSize(jHipsterProperties.getLogging().getLogstash().getQueueSize()); + asyncLogstashAppender.addAppender(logstashAppender); + asyncLogstashAppender.start(); + + context.getLogger("ROOT").addAppender(asyncLogstashAppender); + } + + // Configure a log filter to remove "metrics" logs from all appenders except the "LOGSTASH" appender + private void setMetricsMarkerLogbackFilter(LoggerContext context) { + log.info("Filtering metrics logs from all appenders except the {} appender", LOGSTASH_APPENDER_NAME); + OnMarkerEvaluator onMarkerMetricsEvaluator = new OnMarkerEvaluator(); + onMarkerMetricsEvaluator.setContext(context); + onMarkerMetricsEvaluator.addMarker("metrics"); + onMarkerMetricsEvaluator.start(); + EvaluatorFilter metricsFilter = new EvaluatorFilter<>(); + metricsFilter.setContext(context); + metricsFilter.setEvaluator(onMarkerMetricsEvaluator); + metricsFilter.setOnMatch(FilterReply.DENY); + metricsFilter.start(); + + for (ch.qos.logback.classic.Logger logger : context.getLoggerList()) { + for (Iterator> it = logger.iteratorForAppenders(); it.hasNext();) { + Appender appender = it.next(); + if (!appender.getName().equals(ASYNC_LOGSTASH_APPENDER_NAME)) { + log.debug("Filter metrics logs from the {} appender", appender.getName()); + appender.setContext(context); + appender.addFilter(metricsFilter); + appender.start(); + } + } + } + } + + /** + * Logback configuration is achieved by configuration file and API. + * When configuration file change is detected, the configuration is reset. + * This listener ensures that the programmatic configuration is also re-applied after reset. + */ + class LogbackLoggerContextListener extends ContextAwareBase implements LoggerContextListener { + + @Override + public boolean isResetResistant() { + return true; + } + + @Override + public void onStart(LoggerContext context) { + addLogstashAppender(context); + } + + @Override + public void onReset(LoggerContext context) { + addLogstashAppender(context); + } + + @Override + public void onStop(LoggerContext context) { + // Nothing to do. + } + + @Override + public void onLevelChange(ch.qos.logback.classic.Logger logger, Level level) { + // Nothing to do. + } + } + +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/SecurityConfiguration.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/SecurityConfiguration.java new file mode 100644 index 0000000000..f07944271e --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/SecurityConfiguration.java @@ -0,0 +1,122 @@ +package com.baeldung.jhipster5.config; + +import com.baeldung.jhipster5.security.*; +import com.baeldung.jhipster5.security.jwt.*; + +import org.springframework.beans.factory.BeanInitializationException; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.http.HttpMethod; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.builders.WebSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.web.filter.CorsFilter; +import org.zalando.problem.spring.web.advice.security.SecurityProblemSupport; + +import javax.annotation.PostConstruct; + +@Configuration +@EnableWebSecurity +@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true) +@Import(SecurityProblemSupport.class) +public class SecurityConfiguration extends WebSecurityConfigurerAdapter { + + private final AuthenticationManagerBuilder authenticationManagerBuilder; + + private final UserDetailsService userDetailsService; + + private final TokenProvider tokenProvider; + + private final CorsFilter corsFilter; + + private final SecurityProblemSupport problemSupport; + + public SecurityConfiguration(AuthenticationManagerBuilder authenticationManagerBuilder, UserDetailsService userDetailsService, TokenProvider tokenProvider, CorsFilter corsFilter, SecurityProblemSupport problemSupport) { + this.authenticationManagerBuilder = authenticationManagerBuilder; + this.userDetailsService = userDetailsService; + this.tokenProvider = tokenProvider; + this.corsFilter = corsFilter; + this.problemSupport = problemSupport; + } + + @PostConstruct + public void init() { + try { + authenticationManagerBuilder + .userDetailsService(userDetailsService) + .passwordEncoder(passwordEncoder()); + } catch (Exception e) { + throw new BeanInitializationException("Security configuration failed", e); + } + } + + @Override + @Bean + public AuthenticationManager authenticationManagerBean() throws Exception { + return super.authenticationManagerBean(); + } + + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } + + @Override + public void configure(WebSecurity web) throws Exception { + web.ignoring() + .antMatchers(HttpMethod.OPTIONS, "/**") + .antMatchers("/app/**/*.{js,html}") + .antMatchers("/i18n/**") + .antMatchers("/content/**") + .antMatchers("/h2-console/**") + .antMatchers("/swagger-ui/index.html") + .antMatchers("/test/**"); + } + + @Override + public void configure(HttpSecurity http) throws Exception { + http + .csrf() + .disable() + .addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class) + .exceptionHandling() + .authenticationEntryPoint(problemSupport) + .accessDeniedHandler(problemSupport) + .and() + .headers() + .frameOptions() + .disable() + .and() + .sessionManagement() + .sessionCreationPolicy(SessionCreationPolicy.STATELESS) + .and() + .authorizeRequests() + .antMatchers("/api/books/purchase/**").authenticated() + .antMatchers("/api/register").permitAll() + .antMatchers("/api/activate").permitAll() + .antMatchers("/api/authenticate").permitAll() + .antMatchers("/api/account/reset-password/init").permitAll() + .antMatchers("/api/account/reset-password/finish").permitAll() + .antMatchers("/api/**").authenticated() + .antMatchers("/management/health").permitAll() + .antMatchers("/management/info").permitAll() + .antMatchers("/management/**").hasAuthority(AuthoritiesConstants.ADMIN) + .and() + .apply(securityConfigurerAdapter()); + + } + + private JWTConfigurer securityConfigurerAdapter() { + return new JWTConfigurer(tokenProvider); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/WebConfigurer.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/WebConfigurer.java new file mode 100644 index 0000000000..26cfc92487 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/WebConfigurer.java @@ -0,0 +1,170 @@ +package com.baeldung.jhipster5.config; + +import io.github.jhipster.config.JHipsterConstants; +import io.github.jhipster.config.JHipsterProperties; +import io.github.jhipster.config.h2.H2ConfigurationHelper; +import io.github.jhipster.web.filter.CachingHttpHeadersFilter; +import io.undertow.UndertowOptions; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory; +import org.springframework.boot.web.server.*; +import org.springframework.boot.web.servlet.ServletContextInitializer; +import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; +import org.springframework.http.MediaType; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import org.springframework.web.filter.CorsFilter; + +import javax.servlet.*; +import java.io.File; +import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Paths; +import java.util.*; + +import static java.net.URLDecoder.decode; + +/** + * Configuration of web application with Servlet 3.0 APIs. + */ +@Configuration +public class WebConfigurer implements ServletContextInitializer, WebServerFactoryCustomizer { + + private final Logger log = LoggerFactory.getLogger(WebConfigurer.class); + + private final Environment env; + + private final JHipsterProperties jHipsterProperties; + + public WebConfigurer(Environment env, JHipsterProperties jHipsterProperties) { + + this.env = env; + this.jHipsterProperties = jHipsterProperties; + } + + @Override + public void onStartup(ServletContext servletContext) throws ServletException { + if (env.getActiveProfiles().length != 0) { + log.info("Web application configuration, using profiles: {}", (Object[]) env.getActiveProfiles()); + } + EnumSet disps = EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.ASYNC); + if (env.acceptsProfiles(JHipsterConstants.SPRING_PROFILE_PRODUCTION)) { + initCachingHttpHeadersFilter(servletContext, disps); + } + if (env.acceptsProfiles(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT)) { + initH2Console(servletContext); + } + log.info("Web application fully configured"); + } + + /** + * Customize the Servlet engine: Mime types, the document root, the cache. + */ + @Override + public void customize(WebServerFactory server) { + setMimeMappings(server); + // When running in an IDE or with ./mvnw spring-boot:run, set location of the static web assets. + setLocationForStaticAssets(server); + + /* + * Enable HTTP/2 for Undertow - https://twitter.com/ankinson/status/829256167700492288 + * HTTP/2 requires HTTPS, so HTTP requests will fallback to HTTP/1.1. + * See the JHipsterProperties class and your application-*.yml configuration files + * for more information. + */ + if (jHipsterProperties.getHttp().getVersion().equals(JHipsterProperties.Http.Version.V_2_0) && + server instanceof UndertowServletWebServerFactory) { + + ((UndertowServletWebServerFactory) server) + .addBuilderCustomizers(builder -> + builder.setServerOption(UndertowOptions.ENABLE_HTTP2, true)); + } + } + + private void setMimeMappings(WebServerFactory server) { + if (server instanceof ConfigurableServletWebServerFactory) { + MimeMappings mappings = new MimeMappings(MimeMappings.DEFAULT); + // IE issue, see https://github.com/jhipster/generator-jhipster/pull/711 + mappings.add("html", MediaType.TEXT_HTML_VALUE + ";charset=" + StandardCharsets.UTF_8.name().toLowerCase()); + // CloudFoundry issue, see https://github.com/cloudfoundry/gorouter/issues/64 + mappings.add("json", MediaType.TEXT_HTML_VALUE + ";charset=" + StandardCharsets.UTF_8.name().toLowerCase()); + ConfigurableServletWebServerFactory servletWebServer = (ConfigurableServletWebServerFactory) server; + servletWebServer.setMimeMappings(mappings); + } + } + + private void setLocationForStaticAssets(WebServerFactory server) { + if (server instanceof ConfigurableServletWebServerFactory) { + ConfigurableServletWebServerFactory servletWebServer = (ConfigurableServletWebServerFactory) server; + File root; + String prefixPath = resolvePathPrefix(); + root = new File(prefixPath + "target/www/"); + if (root.exists() && root.isDirectory()) { + servletWebServer.setDocumentRoot(root); + } + } + } + + /** + * Resolve path prefix to static resources. + */ + private String resolvePathPrefix() { + String fullExecutablePath; + try { + fullExecutablePath = decode(this.getClass().getResource("").getPath(), StandardCharsets.UTF_8.name()); + } catch (UnsupportedEncodingException e) { + /* try without decoding if this ever happens */ + fullExecutablePath = this.getClass().getResource("").getPath(); + } + String rootPath = Paths.get(".").toUri().normalize().getPath(); + String extractedPath = fullExecutablePath.replace(rootPath, ""); + int extractionEndIndex = extractedPath.indexOf("target/"); + if (extractionEndIndex <= 0) { + return ""; + } + return extractedPath.substring(0, extractionEndIndex); + } + + /** + * Initializes the caching HTTP Headers Filter. + */ + private void initCachingHttpHeadersFilter(ServletContext servletContext, + EnumSet disps) { + log.debug("Registering Caching HTTP Headers Filter"); + FilterRegistration.Dynamic cachingHttpHeadersFilter = + servletContext.addFilter("cachingHttpHeadersFilter", + new CachingHttpHeadersFilter(jHipsterProperties)); + + cachingHttpHeadersFilter.addMappingForUrlPatterns(disps, true, "/i18n/*"); + cachingHttpHeadersFilter.addMappingForUrlPatterns(disps, true, "/content/*"); + cachingHttpHeadersFilter.addMappingForUrlPatterns(disps, true, "/app/*"); + cachingHttpHeadersFilter.setAsyncSupported(true); + } + + @Bean + public CorsFilter corsFilter() { + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + CorsConfiguration config = jHipsterProperties.getCors(); + if (config.getAllowedOrigins() != null && !config.getAllowedOrigins().isEmpty()) { + log.debug("Registering CORS filter"); + source.registerCorsConfiguration("/api/**", config); + source.registerCorsConfiguration("/management/**", config); + source.registerCorsConfiguration("/v2/api-docs", config); + } + return new CorsFilter(source); + } + + /** + * Initializes H2 console. + */ + private void initH2Console(ServletContext servletContext) { + log.debug("Initialize H2 console"); + H2ConfigurationHelper.initH2Console(servletContext); + } + +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/audit/AuditEventConverter.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/audit/AuditEventConverter.java new file mode 100644 index 0000000000..6dd87bb82d --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/audit/AuditEventConverter.java @@ -0,0 +1,86 @@ +package com.baeldung.jhipster5.config.audit; + +import com.baeldung.jhipster5.domain.PersistentAuditEvent; + +import org.springframework.boot.actuate.audit.AuditEvent; +import org.springframework.security.web.authentication.WebAuthenticationDetails; +import org.springframework.stereotype.Component; + +import java.util.*; + +@Component +public class AuditEventConverter { + + /** + * Convert a list of PersistentAuditEvent to a list of AuditEvent + * + * @param persistentAuditEvents the list to convert + * @return the converted list. + */ + public List convertToAuditEvent(Iterable persistentAuditEvents) { + if (persistentAuditEvents == null) { + return Collections.emptyList(); + } + List auditEvents = new ArrayList<>(); + for (PersistentAuditEvent persistentAuditEvent : persistentAuditEvents) { + auditEvents.add(convertToAuditEvent(persistentAuditEvent)); + } + return auditEvents; + } + + /** + * Convert a PersistentAuditEvent to an AuditEvent + * + * @param persistentAuditEvent the event to convert + * @return the converted list. + */ + public AuditEvent convertToAuditEvent(PersistentAuditEvent persistentAuditEvent) { + if (persistentAuditEvent == null) { + return null; + } + return new AuditEvent(persistentAuditEvent.getAuditEventDate(), persistentAuditEvent.getPrincipal(), + persistentAuditEvent.getAuditEventType(), convertDataToObjects(persistentAuditEvent.getData())); + } + + /** + * Internal conversion. This is needed to support the current SpringBoot actuator AuditEventRepository interface + * + * @param data the data to convert + * @return a map of String, Object + */ + public Map convertDataToObjects(Map data) { + Map results = new HashMap<>(); + + if (data != null) { + for (Map.Entry entry : data.entrySet()) { + results.put(entry.getKey(), entry.getValue()); + } + } + return results; + } + + /** + * Internal conversion. This method will allow to save additional data. + * By default, it will save the object as string + * + * @param data the data to convert + * @return a map of String, String + */ + public Map convertDataToStrings(Map data) { + Map results = new HashMap<>(); + + if (data != null) { + for (Map.Entry entry : data.entrySet()) { + // Extract the data that will be saved. + if (entry.getValue() instanceof WebAuthenticationDetails) { + WebAuthenticationDetails authenticationDetails = (WebAuthenticationDetails) entry.getValue(); + results.put("remoteAddress", authenticationDetails.getRemoteAddress()); + results.put("sessionId", authenticationDetails.getSessionId()); + } else { + results.put(entry.getKey(), Objects.toString(entry.getValue())); + } + } + } + return results; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/audit/package-info.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/audit/package-info.java new file mode 100644 index 0000000000..49a2a73a61 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/audit/package-info.java @@ -0,0 +1,4 @@ +/** + * Audit specific code. + */ +package com.baeldung.jhipster5.config.audit; diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/package-info.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/package-info.java new file mode 100644 index 0000000000..868155ce9f --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/package-info.java @@ -0,0 +1,4 @@ +/** + * Spring Framework configuration files. + */ +package com.baeldung.jhipster5.config; diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/domain/AbstractAuditingEntity.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/domain/AbstractAuditingEntity.java new file mode 100644 index 0000000000..861674ccc9 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/domain/AbstractAuditingEntity.java @@ -0,0 +1,79 @@ +package com.baeldung.jhipster5.domain; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import org.hibernate.envers.Audited; +import org.springframework.data.annotation.CreatedBy; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedBy; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +import java.io.Serializable; +import java.time.Instant; +import javax.persistence.Column; +import javax.persistence.EntityListeners; +import javax.persistence.MappedSuperclass; + +/** + * Base abstract class for entities which will hold definitions for created, last modified by and created, + * last modified by date. + */ +@MappedSuperclass +@Audited +@EntityListeners(AuditingEntityListener.class) +public abstract class AbstractAuditingEntity implements Serializable { + + private static final long serialVersionUID = 1L; + + @CreatedBy + @Column(name = "created_by", nullable = false, length = 50, updatable = false) + @JsonIgnore + private String createdBy; + + @CreatedDate + @Column(name = "created_date", updatable = false) + @JsonIgnore + private Instant createdDate = Instant.now(); + + @LastModifiedBy + @Column(name = "last_modified_by", length = 50) + @JsonIgnore + private String lastModifiedBy; + + @LastModifiedDate + @Column(name = "last_modified_date") + @JsonIgnore + private Instant lastModifiedDate = Instant.now(); + + public String getCreatedBy() { + return createdBy; + } + + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + public Instant getCreatedDate() { + return createdDate; + } + + public void setCreatedDate(Instant createdDate) { + this.createdDate = createdDate; + } + + public String getLastModifiedBy() { + return lastModifiedBy; + } + + public void setLastModifiedBy(String lastModifiedBy) { + this.lastModifiedBy = lastModifiedBy; + } + + public Instant getLastModifiedDate() { + return lastModifiedDate; + } + + public void setLastModifiedDate(Instant lastModifiedDate) { + this.lastModifiedDate = lastModifiedDate; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/domain/Authority.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/domain/Authority.java new file mode 100644 index 0000000000..fbd4596fc7 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/domain/Authority.java @@ -0,0 +1,59 @@ +package com.baeldung.jhipster5.domain; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.persistence.Column; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.io.Serializable; + +/** + * An authority (a security role) used by Spring Security. + */ +@Entity +@Table(name = "jhi_authority") +public class Authority implements Serializable { + + private static final long serialVersionUID = 1L; + + @NotNull + @Size(max = 50) + @Id + @Column(length = 50) + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + Authority authority = (Authority) o; + + return !(name != null ? !name.equals(authority.name) : authority.name != null); + } + + @Override + public int hashCode() { + return name != null ? name.hashCode() : 0; + } + + @Override + public String toString() { + return "Authority{" + + "name='" + name + '\'' + + "}"; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/domain/Book.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/domain/Book.java new file mode 100644 index 0000000000..16771d9e09 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/domain/Book.java @@ -0,0 +1,153 @@ +package com.baeldung.jhipster5.domain; + + + +import javax.persistence.*; +import javax.validation.constraints.*; + +import java.io.Serializable; +import java.time.LocalDate; +import java.util.Objects; + +/** + * A Book. + */ +@Entity +@Table(name = "book") +public class Book implements Serializable { + + private static final long serialVersionUID = 1L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @NotNull + @Column(name = "title", nullable = false) + private String title; + + @NotNull + @Column(name = "author", nullable = false) + private String author; + + @NotNull + @Column(name = "published", nullable = false) + private LocalDate published; + + @NotNull + @Min(value = 0) + @Column(name = "quantity", nullable = false) + private Integer quantity; + + @NotNull + @DecimalMin(value = "0") + @Column(name = "price", nullable = false) + private Double price; + + // jhipster-needle-entity-add-field - JHipster will add fields here, do not remove + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public Book title(String title) { + this.title = title; + return this; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getAuthor() { + return author; + } + + public Book author(String author) { + this.author = author; + return this; + } + + public void setAuthor(String author) { + this.author = author; + } + + public LocalDate getPublished() { + return published; + } + + public Book published(LocalDate published) { + this.published = published; + return this; + } + + public void setPublished(LocalDate published) { + this.published = published; + } + + public Integer getQuantity() { + return quantity; + } + + public Book quantity(Integer quantity) { + this.quantity = quantity; + return this; + } + + public void setQuantity(Integer quantity) { + this.quantity = quantity; + } + + public Double getPrice() { + return price; + } + + public Book price(Double price) { + this.price = price; + return this; + } + + public void setPrice(Double price) { + this.price = price; + } + // jhipster-needle-entity-add-getters-setters - JHipster will add getters and setters here, do not remove + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Book book = (Book) o; + if (book.getId() == null || getId() == null) { + return false; + } + return Objects.equals(getId(), book.getId()); + } + + @Override + public int hashCode() { + return Objects.hashCode(getId()); + } + + @Override + public String toString() { + return "Book{" + + "id=" + getId() + + ", title='" + getTitle() + "'" + + ", author='" + getAuthor() + "'" + + ", published='" + getPublished() + "'" + + ", quantity=" + getQuantity() + + ", price=" + getPrice() + + "}"; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/domain/PersistentAuditEvent.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/domain/PersistentAuditEvent.java new file mode 100644 index 0000000000..15e2eeda5a --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/domain/PersistentAuditEvent.java @@ -0,0 +1,109 @@ +package com.baeldung.jhipster5.domain; + +import javax.persistence.*; +import javax.validation.constraints.NotNull; +import java.io.Serializable; +import java.time.Instant; +import java.util.HashMap; +import java.util.Objects; +import java.util.Map; + +/** + * Persist AuditEvent managed by the Spring Boot actuator. + * + * @see org.springframework.boot.actuate.audit.AuditEvent + */ +@Entity +@Table(name = "jhi_persistent_audit_event") +public class PersistentAuditEvent implements Serializable { + + private static final long serialVersionUID = 1L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "event_id") + private Long id; + + @NotNull + @Column(nullable = false) + private String principal; + + @Column(name = "event_date") + private Instant auditEventDate; + + @Column(name = "event_type") + private String auditEventType; + + @ElementCollection + @MapKeyColumn(name = "name") + @Column(name = "value") + @CollectionTable(name = "jhi_persistent_audit_evt_data", joinColumns=@JoinColumn(name="event_id")) + private Map data = new HashMap<>(); + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getPrincipal() { + return principal; + } + + public void setPrincipal(String principal) { + this.principal = principal; + } + + public Instant getAuditEventDate() { + return auditEventDate; + } + + public void setAuditEventDate(Instant auditEventDate) { + this.auditEventDate = auditEventDate; + } + + public String getAuditEventType() { + return auditEventType; + } + + public void setAuditEventType(String auditEventType) { + this.auditEventType = auditEventType; + } + + public Map getData() { + return data; + } + + public void setData(Map data) { + this.data = data; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + PersistentAuditEvent persistentAuditEvent = (PersistentAuditEvent) o; + return !(persistentAuditEvent.getId() == null || getId() == null) && Objects.equals(getId(), persistentAuditEvent.getId()); + } + + @Override + public int hashCode() { + return Objects.hashCode(getId()); + } + + @Override + public String toString() { + return "PersistentAuditEvent{" + + "principal='" + principal + '\'' + + ", auditEventDate=" + auditEventDate + + ", auditEventType='" + auditEventType + '\'' + + '}'; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/domain/User.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/domain/User.java new file mode 100644 index 0000000000..ff12d1ca9c --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/domain/User.java @@ -0,0 +1,231 @@ +package com.baeldung.jhipster5.domain; + +import com.baeldung.jhipster5.config.Constants; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import org.apache.commons.lang3.StringUtils; +import org.hibernate.annotations.BatchSize; +import javax.validation.constraints.Email; + +import javax.persistence.*; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; +import javax.validation.constraints.Size; +import java.io.Serializable; +import java.util.HashSet; +import java.util.Locale; +import java.util.Objects; +import java.util.Set; +import java.time.Instant; + +/** + * A user. + */ +@Entity +@Table(name = "jhi_user") + +public class User extends AbstractAuditingEntity implements Serializable { + + private static final long serialVersionUID = 1L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @NotNull + @Pattern(regexp = Constants.LOGIN_REGEX) + @Size(min = 1, max = 50) + @Column(length = 50, unique = true, nullable = false) + private String login; + + @JsonIgnore + @NotNull + @Size(min = 60, max = 60) + @Column(name = "password_hash", length = 60, nullable = false) + private String password; + + @Size(max = 50) + @Column(name = "first_name", length = 50) + private String firstName; + + @Size(max = 50) + @Column(name = "last_name", length = 50) + private String lastName; + + @Email + @Size(min = 5, max = 254) + @Column(length = 254, unique = true) + private String email; + + @NotNull + @Column(nullable = false) + private boolean activated = false; + + @Size(min = 2, max = 6) + @Column(name = "lang_key", length = 6) + private String langKey; + + @Size(max = 256) + @Column(name = "image_url", length = 256) + private String imageUrl; + + @Size(max = 20) + @Column(name = "activation_key", length = 20) + @JsonIgnore + private String activationKey; + + @Size(max = 20) + @Column(name = "reset_key", length = 20) + @JsonIgnore + private String resetKey; + + @Column(name = "reset_date") + private Instant resetDate = null; + + @JsonIgnore + @ManyToMany + @JoinTable( + name = "jhi_user_authority", + joinColumns = {@JoinColumn(name = "user_id", referencedColumnName = "id")}, + inverseJoinColumns = {@JoinColumn(name = "authority_name", referencedColumnName = "name")}) + + @BatchSize(size = 20) + private Set authorities = new HashSet<>(); + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getLogin() { + return login; + } + + // Lowercase the login before saving it in database + public void setLogin(String login) { + this.login = StringUtils.lowerCase(login, Locale.ENGLISH); + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getImageUrl() { + return imageUrl; + } + + public void setImageUrl(String imageUrl) { + this.imageUrl = imageUrl; + } + + public boolean getActivated() { + return activated; + } + + public void setActivated(boolean activated) { + this.activated = activated; + } + + public String getActivationKey() { + return activationKey; + } + + public void setActivationKey(String activationKey) { + this.activationKey = activationKey; + } + + public String getResetKey() { + return resetKey; + } + + public void setResetKey(String resetKey) { + this.resetKey = resetKey; + } + + public Instant getResetDate() { + return resetDate; + } + + public void setResetDate(Instant resetDate) { + this.resetDate = resetDate; + } + + public String getLangKey() { + return langKey; + } + + public void setLangKey(String langKey) { + this.langKey = langKey; + } + + public Set getAuthorities() { + return authorities; + } + + public void setAuthorities(Set authorities) { + this.authorities = authorities; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + User user = (User) o; + return !(user.getId() == null || getId() == null) && Objects.equals(getId(), user.getId()); + } + + @Override + public int hashCode() { + return Objects.hashCode(getId()); + } + + @Override + public String toString() { + return "User{" + + "login='" + login + '\'' + + ", firstName='" + firstName + '\'' + + ", lastName='" + lastName + '\'' + + ", email='" + email + '\'' + + ", imageUrl='" + imageUrl + '\'' + + ", activated='" + activated + '\'' + + ", langKey='" + langKey + '\'' + + ", activationKey='" + activationKey + '\'' + + "}"; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/domain/package-info.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/domain/package-info.java new file mode 100644 index 0000000000..eba92a598e --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/domain/package-info.java @@ -0,0 +1,4 @@ +/** + * JPA domain objects. + */ +package com.baeldung.jhipster5.domain; diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/repository/AuthorityRepository.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/repository/AuthorityRepository.java new file mode 100644 index 0000000000..310735eb57 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/repository/AuthorityRepository.java @@ -0,0 +1,11 @@ +package com.baeldung.jhipster5.repository; + +import com.baeldung.jhipster5.domain.Authority; + +import org.springframework.data.jpa.repository.JpaRepository; + +/** + * Spring Data JPA repository for the Authority entity. + */ +public interface AuthorityRepository extends JpaRepository { +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/repository/BookRepository.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/repository/BookRepository.java new file mode 100644 index 0000000000..ebd3117e65 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/repository/BookRepository.java @@ -0,0 +1,15 @@ +package com.baeldung.jhipster5.repository; + +import com.baeldung.jhipster5.domain.Book; +import org.springframework.data.jpa.repository.*; +import org.springframework.stereotype.Repository; + + +/** + * Spring Data repository for the Book entity. + */ +@SuppressWarnings("unused") +@Repository +public interface BookRepository extends JpaRepository { + +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/repository/CustomAuditEventRepository.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/repository/CustomAuditEventRepository.java new file mode 100644 index 0000000000..faa788ff5f --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/repository/CustomAuditEventRepository.java @@ -0,0 +1,89 @@ +package com.baeldung.jhipster5.repository; + +import com.baeldung.jhipster5.config.Constants; +import com.baeldung.jhipster5.config.audit.AuditEventConverter; +import com.baeldung.jhipster5.domain.PersistentAuditEvent; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.actuate.audit.AuditEvent; +import org.springframework.boot.actuate.audit.AuditEventRepository; +import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import java.time.Instant; +import java.util.*; + +/** + * An implementation of Spring Boot's AuditEventRepository. + */ +@Repository +public class CustomAuditEventRepository implements AuditEventRepository { + + private static final String AUTHORIZATION_FAILURE = "AUTHORIZATION_FAILURE"; + + /** + * Should be the same as in Liquibase migration. + */ + protected static final int EVENT_DATA_COLUMN_MAX_LENGTH = 255; + + private final PersistenceAuditEventRepository persistenceAuditEventRepository; + + private final AuditEventConverter auditEventConverter; + + private final Logger log = LoggerFactory.getLogger(getClass()); + + public CustomAuditEventRepository(PersistenceAuditEventRepository persistenceAuditEventRepository, + AuditEventConverter auditEventConverter) { + + this.persistenceAuditEventRepository = persistenceAuditEventRepository; + this.auditEventConverter = auditEventConverter; + } + + @Override + public List find(String principal, Instant after, String type) { + Iterable persistentAuditEvents = + persistenceAuditEventRepository.findByPrincipalAndAuditEventDateAfterAndAuditEventType(principal, after, type); + return auditEventConverter.convertToAuditEvent(persistentAuditEvents); + } + + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public void add(AuditEvent event) { + if (!AUTHORIZATION_FAILURE.equals(event.getType()) && + !Constants.ANONYMOUS_USER.equals(event.getPrincipal())) { + + PersistentAuditEvent persistentAuditEvent = new PersistentAuditEvent(); + persistentAuditEvent.setPrincipal(event.getPrincipal()); + persistentAuditEvent.setAuditEventType(event.getType()); + persistentAuditEvent.setAuditEventDate(event.getTimestamp()); + Map eventData = auditEventConverter.convertDataToStrings(event.getData()); + persistentAuditEvent.setData(truncate(eventData)); + persistenceAuditEventRepository.save(persistentAuditEvent); + } + } + + /** + * Truncate event data that might exceed column length. + */ + private Map truncate(Map data) { + Map results = new HashMap<>(); + + if (data != null) { + for (Map.Entry entry : data.entrySet()) { + String value = entry.getValue(); + if (value != null) { + int length = value.length(); + if (length > EVENT_DATA_COLUMN_MAX_LENGTH) { + value = value.substring(0, EVENT_DATA_COLUMN_MAX_LENGTH); + log.warn("Event data for {} too long ({}) has been truncated to {}. Consider increasing column width.", + entry.getKey(), length, EVENT_DATA_COLUMN_MAX_LENGTH); + } + } + results.put(entry.getKey(), value); + } + } + return results; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/repository/PersistenceAuditEventRepository.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/repository/PersistenceAuditEventRepository.java new file mode 100644 index 0000000000..2eb6f3b847 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/repository/PersistenceAuditEventRepository.java @@ -0,0 +1,25 @@ +package com.baeldung.jhipster5.repository; + +import com.baeldung.jhipster5.domain.PersistentAuditEvent; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.time.Instant; +import java.util.List; + +/** + * Spring Data JPA repository for the PersistentAuditEvent entity. + */ +public interface PersistenceAuditEventRepository extends JpaRepository { + + List findByPrincipal(String principal); + + List findByAuditEventDateAfter(Instant after); + + List findByPrincipalAndAuditEventDateAfter(String principal, Instant after); + + List findByPrincipalAndAuditEventDateAfterAndAuditEventType(String principal, Instant after, String type); + + Page findAllByAuditEventDateBetween(Instant fromDate, Instant toDate, Pageable pageable); +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/repository/UserRepository.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/repository/UserRepository.java new file mode 100644 index 0000000000..42a5588b22 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/repository/UserRepository.java @@ -0,0 +1,40 @@ +package com.baeldung.jhipster5.repository; + +import com.baeldung.jhipster5.domain.User; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.EntityGraph; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import java.util.List; +import java.util.Optional; +import java.time.Instant; + +/** + * Spring Data JPA repository for the User entity. + */ +@Repository +public interface UserRepository extends JpaRepository { + + Optional findOneByActivationKey(String activationKey); + + List findAllByActivatedIsFalseAndCreatedDateBefore(Instant dateTime); + + Optional findOneByResetKey(String resetKey); + + Optional findOneByEmailIgnoreCase(String email); + + Optional findOneByLogin(String login); + + @EntityGraph(attributePaths = "authorities") + Optional findOneWithAuthoritiesById(Long id); + + @EntityGraph(attributePaths = "authorities") + Optional findOneWithAuthoritiesByLogin(String login); + + @EntityGraph(attributePaths = "authorities") + Optional findOneWithAuthoritiesByEmail(String email); + + Page findAllByLoginNot(Pageable pageable, String login); +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/repository/package-info.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/repository/package-info.java new file mode 100644 index 0000000000..a5002eb201 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/repository/package-info.java @@ -0,0 +1,4 @@ +/** + * Spring Data JPA repositories. + */ +package com.baeldung.jhipster5.repository; diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/AuthoritiesConstants.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/AuthoritiesConstants.java new file mode 100644 index 0000000000..6ecf44394f --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/AuthoritiesConstants.java @@ -0,0 +1,16 @@ +package com.baeldung.jhipster5.security; + +/** + * Constants for Spring Security authorities. + */ +public final class AuthoritiesConstants { + + public static final String ADMIN = "ROLE_ADMIN"; + + public static final String USER = "ROLE_USER"; + + public static final String ANONYMOUS = "ROLE_ANONYMOUS"; + + private AuthoritiesConstants() { + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/DomainUserDetailsService.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/DomainUserDetailsService.java new file mode 100644 index 0000000000..d0014096df --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/DomainUserDetailsService.java @@ -0,0 +1,62 @@ +package com.baeldung.jhipster5.security; + +import com.baeldung.jhipster5.domain.User; +import com.baeldung.jhipster5.repository.UserRepository; +import org.hibernate.validator.internal.constraintvalidators.hv.EmailValidator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * Authenticate a user from the database. + */ +@Component("userDetailsService") +public class DomainUserDetailsService implements UserDetailsService { + + private final Logger log = LoggerFactory.getLogger(DomainUserDetailsService.class); + + private final UserRepository userRepository; + + public DomainUserDetailsService(UserRepository userRepository) { + this.userRepository = userRepository; + } + + @Override + @Transactional + public UserDetails loadUserByUsername(final String login) { + log.debug("Authenticating {}", login); + + if (new EmailValidator().isValid(login, null)) { + return userRepository.findOneWithAuthoritiesByEmail(login) + .map(user -> createSpringSecurityUser(login, user)) + .orElseThrow(() -> new UsernameNotFoundException("User with email " + login + " was not found in the database")); + } + + String lowercaseLogin = login.toLowerCase(Locale.ENGLISH); + return userRepository.findOneWithAuthoritiesByLogin(lowercaseLogin) + .map(user -> createSpringSecurityUser(lowercaseLogin, user)) + .orElseThrow(() -> new UsernameNotFoundException("User " + lowercaseLogin + " was not found in the database")); + + } + + private org.springframework.security.core.userdetails.User createSpringSecurityUser(String lowercaseLogin, User user) { + if (!user.getActivated()) { + throw new UserNotActivatedException("User " + lowercaseLogin + " was not activated"); + } + List grantedAuthorities = user.getAuthorities().stream() + .map(authority -> new SimpleGrantedAuthority(authority.getName())) + .collect(Collectors.toList()); + return new org.springframework.security.core.userdetails.User(user.getLogin(), + user.getPassword(), + grantedAuthorities); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/SecurityUtils.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/SecurityUtils.java new file mode 100644 index 0000000000..462bb8abc9 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/SecurityUtils.java @@ -0,0 +1,76 @@ +package com.baeldung.jhipster5.security; + +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; + +import java.util.Optional; + +/** + * Utility class for Spring Security. + */ +public final class SecurityUtils { + + private SecurityUtils() { + } + + /** + * Get the login of the current user. + * + * @return the login of the current user + */ + public static Optional getCurrentUserLogin() { + SecurityContext securityContext = SecurityContextHolder.getContext(); + return Optional.ofNullable(securityContext.getAuthentication()) + .map(authentication -> { + if (authentication.getPrincipal() instanceof UserDetails) { + UserDetails springSecurityUser = (UserDetails) authentication.getPrincipal(); + return springSecurityUser.getUsername(); + } else if (authentication.getPrincipal() instanceof String) { + return (String) authentication.getPrincipal(); + } + return null; + }); + } + + /** + * Get the JWT of the current user. + * + * @return the JWT of the current user + */ + public static Optional getCurrentUserJWT() { + SecurityContext securityContext = SecurityContextHolder.getContext(); + return Optional.ofNullable(securityContext.getAuthentication()) + .filter(authentication -> authentication.getCredentials() instanceof String) + .map(authentication -> (String) authentication.getCredentials()); + } + + /** + * Check if a user is authenticated. + * + * @return true if the user is authenticated, false otherwise + */ + public static boolean isAuthenticated() { + SecurityContext securityContext = SecurityContextHolder.getContext(); + return Optional.ofNullable(securityContext.getAuthentication()) + .map(authentication -> authentication.getAuthorities().stream() + .noneMatch(grantedAuthority -> grantedAuthority.getAuthority().equals(AuthoritiesConstants.ANONYMOUS))) + .orElse(false); + } + + /** + * If the current user has a specific authority (security role). + *

+ * The name of this method comes from the isUserInRole() method in the Servlet API + * + * @param authority the authority to check + * @return true if the current user has the authority, false otherwise + */ + public static boolean isCurrentUserInRole(String authority) { + SecurityContext securityContext = SecurityContextHolder.getContext(); + return Optional.ofNullable(securityContext.getAuthentication()) + .map(authentication -> authentication.getAuthorities().stream() + .anyMatch(grantedAuthority -> grantedAuthority.getAuthority().equals(authority))) + .orElse(false); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/SpringSecurityAuditorAware.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/SpringSecurityAuditorAware.java new file mode 100644 index 0000000000..c1d6405ae3 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/SpringSecurityAuditorAware.java @@ -0,0 +1,20 @@ +package com.baeldung.jhipster5.security; + +import com.baeldung.jhipster5.config.Constants; + +import java.util.Optional; + +import org.springframework.data.domain.AuditorAware; +import org.springframework.stereotype.Component; + +/** + * Implementation of AuditorAware based on Spring Security. + */ +@Component +public class SpringSecurityAuditorAware implements AuditorAware { + + @Override + public Optional getCurrentAuditor() { + return Optional.of(SecurityUtils.getCurrentUserLogin().orElse(Constants.SYSTEM_ACCOUNT)); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/UserNotActivatedException.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/UserNotActivatedException.java new file mode 100644 index 0000000000..4b2d91983c --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/UserNotActivatedException.java @@ -0,0 +1,19 @@ +package com.baeldung.jhipster5.security; + +import org.springframework.security.core.AuthenticationException; + +/** + * This exception is thrown in case of a not activated user trying to authenticate. + */ +public class UserNotActivatedException extends AuthenticationException { + + private static final long serialVersionUID = 1L; + + public UserNotActivatedException(String message) { + super(message); + } + + public UserNotActivatedException(String message, Throwable t) { + super(message, t); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/jwt/JWTConfigurer.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/jwt/JWTConfigurer.java new file mode 100644 index 0000000000..944255e37d --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/jwt/JWTConfigurer.java @@ -0,0 +1,21 @@ +package com.baeldung.jhipster5.security.jwt; + +import org.springframework.security.config.annotation.SecurityConfigurerAdapter; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.web.DefaultSecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; + +public class JWTConfigurer extends SecurityConfigurerAdapter { + + private TokenProvider tokenProvider; + + public JWTConfigurer(TokenProvider tokenProvider) { + this.tokenProvider = tokenProvider; + } + + @Override + public void configure(HttpSecurity http) throws Exception { + JWTFilter customFilter = new JWTFilter(tokenProvider); + http.addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter.class); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/jwt/JWTFilter.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/jwt/JWTFilter.java new file mode 100644 index 0000000000..cf1060282c --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/jwt/JWTFilter.java @@ -0,0 +1,48 @@ +package com.baeldung.jhipster5.security.jwt; + +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.util.StringUtils; +import org.springframework.web.filter.GenericFilterBean; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; + +/** + * Filters incoming requests and installs a Spring Security principal if a header corresponding to a valid user is + * found. + */ +public class JWTFilter extends GenericFilterBean { + + public static final String AUTHORIZATION_HEADER = "Authorization"; + + private TokenProvider tokenProvider; + + public JWTFilter(TokenProvider tokenProvider) { + this.tokenProvider = tokenProvider; + } + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) + throws IOException, ServletException { + HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest; + String jwt = resolveToken(httpServletRequest); + if (StringUtils.hasText(jwt) && this.tokenProvider.validateToken(jwt)) { + Authentication authentication = this.tokenProvider.getAuthentication(jwt); + SecurityContextHolder.getContext().setAuthentication(authentication); + } + filterChain.doFilter(servletRequest, servletResponse); + } + + private String resolveToken(HttpServletRequest request){ + String bearerToken = request.getHeader(AUTHORIZATION_HEADER); + if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) { + return bearerToken.substring(7); + } + return null; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/jwt/TokenProvider.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/jwt/TokenProvider.java new file mode 100644 index 0000000000..248d45e050 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/jwt/TokenProvider.java @@ -0,0 +1,119 @@ +package com.baeldung.jhipster5.security.jwt; + +import java.nio.charset.StandardCharsets; +import java.security.Key; +import java.util.*; +import java.util.stream.Collectors; +import javax.annotation.PostConstruct; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.User; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +import io.github.jhipster.config.JHipsterProperties; +import io.jsonwebtoken.*; +import io.jsonwebtoken.io.Decoders; +import io.jsonwebtoken.security.Keys; + +@Component +public class TokenProvider { + + private final Logger log = LoggerFactory.getLogger(TokenProvider.class); + + private static final String AUTHORITIES_KEY = "auth"; + + private Key key; + + private long tokenValidityInMilliseconds; + + private long tokenValidityInMillisecondsForRememberMe; + + private final JHipsterProperties jHipsterProperties; + + public TokenProvider(JHipsterProperties jHipsterProperties) { + this.jHipsterProperties = jHipsterProperties; + } + + @PostConstruct + public void init() { + byte[] keyBytes; + String secret = jHipsterProperties.getSecurity().getAuthentication().getJwt().getSecret(); + if (!StringUtils.isEmpty(secret)) { + log.warn("Warning: the JWT key used is not Base64-encoded. " + + "We recommend using the `jhipster.security.authentication.jwt.base64-secret` key for optimum security."); + keyBytes = secret.getBytes(StandardCharsets.UTF_8); + } else { + log.debug("Using a Base64-encoded JWT secret key"); + keyBytes = Decoders.BASE64.decode(jHipsterProperties.getSecurity().getAuthentication().getJwt().getBase64Secret()); + } + this.key = Keys.hmacShaKeyFor(keyBytes); + this.tokenValidityInMilliseconds = + 1000 * jHipsterProperties.getSecurity().getAuthentication().getJwt().getTokenValidityInSeconds(); + this.tokenValidityInMillisecondsForRememberMe = + 1000 * jHipsterProperties.getSecurity().getAuthentication().getJwt() + .getTokenValidityInSecondsForRememberMe(); + } + + public String createToken(Authentication authentication, boolean rememberMe) { + String authorities = authentication.getAuthorities().stream() + .map(GrantedAuthority::getAuthority) + .collect(Collectors.joining(",")); + + long now = (new Date()).getTime(); + Date validity; + if (rememberMe) { + validity = new Date(now + this.tokenValidityInMillisecondsForRememberMe); + } else { + validity = new Date(now + this.tokenValidityInMilliseconds); + } + + return Jwts.builder() + .setSubject(authentication.getName()) + .claim(AUTHORITIES_KEY, authorities) + .signWith(key, SignatureAlgorithm.HS512) + .setExpiration(validity) + .compact(); + } + + public Authentication getAuthentication(String token) { + Claims claims = Jwts.parser() + .setSigningKey(key) + .parseClaimsJws(token) + .getBody(); + + Collection authorities = + Arrays.stream(claims.get(AUTHORITIES_KEY).toString().split(",")) + .map(SimpleGrantedAuthority::new) + .collect(Collectors.toList()); + + User principal = new User(claims.getSubject(), "", authorities); + + return new UsernamePasswordAuthenticationToken(principal, token, authorities); + } + + public boolean validateToken(String authToken) { + try { + Jwts.parser().setSigningKey(key).parseClaimsJws(authToken); + return true; + } catch (io.jsonwebtoken.security.SecurityException | MalformedJwtException e) { + log.info("Invalid JWT signature."); + log.trace("Invalid JWT signature trace: {}", e); + } catch (ExpiredJwtException e) { + log.info("Expired JWT token."); + log.trace("Expired JWT token trace: {}", e); + } catch (UnsupportedJwtException e) { + log.info("Unsupported JWT token."); + log.trace("Unsupported JWT token trace: {}", e); + } catch (IllegalArgumentException e) { + log.info("JWT token compact of handler are invalid."); + log.trace("JWT token compact of handler are invalid trace: {}", e); + } + return false; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/package-info.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/package-info.java new file mode 100644 index 0000000000..4759050c56 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/package-info.java @@ -0,0 +1,4 @@ +/** + * Spring Security configuration. + */ +package com.baeldung.jhipster5.security; diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/AuditEventService.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/AuditEventService.java new file mode 100644 index 0000000000..852eb951c9 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/AuditEventService.java @@ -0,0 +1,51 @@ +package com.baeldung.jhipster5.service; + +import com.baeldung.jhipster5.config.audit.AuditEventConverter; +import com.baeldung.jhipster5.repository.PersistenceAuditEventRepository; +import org.springframework.boot.actuate.audit.AuditEvent; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.Instant; +import java.util.Optional; + +/** + * Service for managing audit events. + *

+ * This is the default implementation to support SpringBoot Actuator AuditEventRepository + */ +@Service +@Transactional +public class AuditEventService { + + private final PersistenceAuditEventRepository persistenceAuditEventRepository; + + private final AuditEventConverter auditEventConverter; + + public AuditEventService( + PersistenceAuditEventRepository persistenceAuditEventRepository, + AuditEventConverter auditEventConverter) { + + this.persistenceAuditEventRepository = persistenceAuditEventRepository; + this.auditEventConverter = auditEventConverter; + } + + public Page findAll(Pageable pageable) { + return persistenceAuditEventRepository.findAll(pageable) + .map(auditEventConverter::convertToAuditEvent); + } + + public Page findByDates(Instant fromDate, Instant toDate, Pageable pageable) { + return persistenceAuditEventRepository.findAllByAuditEventDateBetween(fromDate, toDate, pageable) + .map(auditEventConverter::convertToAuditEvent); + } + + public Optional find(Long id) { + return Optional.ofNullable(persistenceAuditEventRepository.findById(id)) + .filter(Optional::isPresent) + .map(Optional::get) + .map(auditEventConverter::convertToAuditEvent); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/BookService.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/BookService.java new file mode 100644 index 0000000000..6422d1a424 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/BookService.java @@ -0,0 +1,50 @@ +package com.baeldung.jhipster5.service; + +import com.baeldung.jhipster5.service.dto.BookDTO; + +import java.util.List; +import java.util.Optional; + +/** + * Service Interface for managing Book. + */ +public interface BookService { + + /** + * Save a book. + * + * @param bookDTO the entity to save + * @return the persisted entity + */ + BookDTO save(BookDTO bookDTO); + + /** + * Get all the books. + * + * @return the list of entities + */ + List findAll(); + + + /** + * Get the "id" book. + * + * @param id the id of the entity + * @return the entity + */ + Optional findOne(Long id); + + /** + * Delete the "id" book. + * + * @param id the id of the entity + */ + void delete(Long id); + + /** + * Simulates purchasing a book by reducing the stock of a book by 1. + * @param id the id of the book + * @return Updated BookDTO, empty if not found, or throws exception if an error occurs. + */ + Optional purchase(Long id); +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/MailService.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/MailService.java new file mode 100644 index 0000000000..b15a7faff2 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/MailService.java @@ -0,0 +1,105 @@ +package com.baeldung.jhipster5.service; + +import com.baeldung.jhipster5.domain.User; + +import io.github.jhipster.config.JHipsterProperties; + +import java.nio.charset.StandardCharsets; +import java.util.Locale; +import javax.mail.internet.MimeMessage; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.MessageSource; +import org.springframework.mail.javamail.JavaMailSender; +import org.springframework.mail.javamail.MimeMessageHelper; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; +import org.thymeleaf.context.Context; +import org.thymeleaf.spring5.SpringTemplateEngine; + +/** + * Service for sending emails. + *

+ * We use the @Async annotation to send emails asynchronously. + */ +@Service +public class MailService { + + private final Logger log = LoggerFactory.getLogger(MailService.class); + + private static final String USER = "user"; + + private static final String BASE_URL = "baseUrl"; + + private final JHipsterProperties jHipsterProperties; + + private final JavaMailSender javaMailSender; + + private final MessageSource messageSource; + + private final SpringTemplateEngine templateEngine; + + public MailService(JHipsterProperties jHipsterProperties, JavaMailSender javaMailSender, + MessageSource messageSource, SpringTemplateEngine templateEngine) { + + this.jHipsterProperties = jHipsterProperties; + this.javaMailSender = javaMailSender; + this.messageSource = messageSource; + this.templateEngine = templateEngine; + } + + @Async + public void sendEmail(String to, String subject, String content, boolean isMultipart, boolean isHtml) { + log.debug("Send email[multipart '{}' and html '{}'] to '{}' with subject '{}' and content={}", + isMultipart, isHtml, to, subject, content); + + // Prepare message using a Spring helper + MimeMessage mimeMessage = javaMailSender.createMimeMessage(); + try { + MimeMessageHelper message = new MimeMessageHelper(mimeMessage, isMultipart, StandardCharsets.UTF_8.name()); + message.setTo(to); + message.setFrom(jHipsterProperties.getMail().getFrom()); + message.setSubject(subject); + message.setText(content, isHtml); + javaMailSender.send(mimeMessage); + log.debug("Sent email to User '{}'", to); + } catch (Exception e) { + if (log.isDebugEnabled()) { + log.warn("Email could not be sent to user '{}'", to, e); + } else { + log.warn("Email could not be sent to user '{}': {}", to, e.getMessage()); + } + } + } + + @Async + public void sendEmailFromTemplate(User user, String templateName, String titleKey) { + Locale locale = Locale.forLanguageTag(user.getLangKey()); + Context context = new Context(locale); + context.setVariable(USER, user); + context.setVariable(BASE_URL, jHipsterProperties.getMail().getBaseUrl()); + String content = templateEngine.process(templateName, context); + String subject = messageSource.getMessage(titleKey, null, locale); + sendEmail(user.getEmail(), subject, content, false, true); + + } + + @Async + public void sendActivationEmail(User user) { + log.debug("Sending activation email to '{}'", user.getEmail()); + sendEmailFromTemplate(user, "mail/activationEmail", "email.activation.title"); + } + + @Async + public void sendCreationEmail(User user) { + log.debug("Sending creation email to '{}'", user.getEmail()); + sendEmailFromTemplate(user, "mail/creationEmail", "email.activation.title"); + } + + @Async + public void sendPasswordResetMail(User user) { + log.debug("Sending password reset email to '{}'", user.getEmail()); + sendEmailFromTemplate(user, "mail/passwordResetEmail", "email.reset.title"); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/UserService.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/UserService.java new file mode 100644 index 0000000000..82d028f3ca --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/UserService.java @@ -0,0 +1,273 @@ +package com.baeldung.jhipster5.service; + +import com.baeldung.jhipster5.config.Constants; +import com.baeldung.jhipster5.domain.Authority; +import com.baeldung.jhipster5.domain.User; +import com.baeldung.jhipster5.repository.AuthorityRepository; +import com.baeldung.jhipster5.repository.UserRepository; +import com.baeldung.jhipster5.security.AuthoritiesConstants; +import com.baeldung.jhipster5.security.SecurityUtils; +import com.baeldung.jhipster5.service.dto.UserDTO; +import com.baeldung.jhipster5.service.util.RandomUtil; +import com.baeldung.jhipster5.web.rest.errors.*; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.*; +import java.util.stream.Collectors; + +/** + * Service class for managing users. + */ +@Service +@Transactional +public class UserService { + + private final Logger log = LoggerFactory.getLogger(UserService.class); + + private final UserRepository userRepository; + + private final PasswordEncoder passwordEncoder; + + private final AuthorityRepository authorityRepository; + + public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder, AuthorityRepository authorityRepository) { + this.userRepository = userRepository; + this.passwordEncoder = passwordEncoder; + this.authorityRepository = authorityRepository; + } + + public Optional activateRegistration(String key) { + log.debug("Activating user for activation key {}", key); + return userRepository.findOneByActivationKey(key) + .map(user -> { + // activate given user for the registration key. + user.setActivated(true); + user.setActivationKey(null); + log.debug("Activated user: {}", user); + return user; + }); + } + + public Optional completePasswordReset(String newPassword, String key) { + log.debug("Reset user password for reset key {}", key); + return userRepository.findOneByResetKey(key) + .filter(user -> user.getResetDate().isAfter(Instant.now().minusSeconds(86400))) + .map(user -> { + user.setPassword(passwordEncoder.encode(newPassword)); + user.setResetKey(null); + user.setResetDate(null); + return user; + }); + } + + public Optional requestPasswordReset(String mail) { + return userRepository.findOneByEmailIgnoreCase(mail) + .filter(User::getActivated) + .map(user -> { + user.setResetKey(RandomUtil.generateResetKey()); + user.setResetDate(Instant.now()); + return user; + }); + } + + public User registerUser(UserDTO userDTO, String password) { + userRepository.findOneByLogin(userDTO.getLogin().toLowerCase()).ifPresent(existingUser -> { + boolean removed = removeNonActivatedUser(existingUser); + if (!removed) { + throw new LoginAlreadyUsedException(); + } + }); + userRepository.findOneByEmailIgnoreCase(userDTO.getEmail()).ifPresent(existingUser -> { + boolean removed = removeNonActivatedUser(existingUser); + if (!removed) { + throw new EmailAlreadyUsedException(); + } + }); + User newUser = new User(); + String encryptedPassword = passwordEncoder.encode(password); + newUser.setLogin(userDTO.getLogin().toLowerCase()); + // new user gets initially a generated password + newUser.setPassword(encryptedPassword); + newUser.setFirstName(userDTO.getFirstName()); + newUser.setLastName(userDTO.getLastName()); + newUser.setEmail(userDTO.getEmail().toLowerCase()); + newUser.setImageUrl(userDTO.getImageUrl()); + newUser.setLangKey(userDTO.getLangKey()); + // new user is not active + newUser.setActivated(false); + // new user gets registration key + newUser.setActivationKey(RandomUtil.generateActivationKey()); + Set authorities = new HashSet<>(); + authorityRepository.findById(AuthoritiesConstants.USER).ifPresent(authorities::add); + newUser.setAuthorities(authorities); + userRepository.save(newUser); + log.debug("Created Information for User: {}", newUser); + return newUser; + } + + private boolean removeNonActivatedUser(User existingUser){ + if (existingUser.getActivated()) { + return false; + } + userRepository.delete(existingUser); + userRepository.flush(); + return true; + } + + public User createUser(UserDTO userDTO) { + User user = new User(); + user.setLogin(userDTO.getLogin().toLowerCase()); + user.setFirstName(userDTO.getFirstName()); + user.setLastName(userDTO.getLastName()); + user.setEmail(userDTO.getEmail().toLowerCase()); + user.setImageUrl(userDTO.getImageUrl()); + if (userDTO.getLangKey() == null) { + user.setLangKey(Constants.DEFAULT_LANGUAGE); // default language + } else { + user.setLangKey(userDTO.getLangKey()); + } + String encryptedPassword = passwordEncoder.encode(RandomUtil.generatePassword()); + user.setPassword(encryptedPassword); + user.setResetKey(RandomUtil.generateResetKey()); + user.setResetDate(Instant.now()); + user.setActivated(true); + if (userDTO.getAuthorities() != null) { + Set authorities = userDTO.getAuthorities().stream() + .map(authorityRepository::findById) + .filter(Optional::isPresent) + .map(Optional::get) + .collect(Collectors.toSet()); + user.setAuthorities(authorities); + } + userRepository.save(user); + log.debug("Created Information for User: {}", user); + return user; + } + + /** + * Update basic information (first name, last name, email, language) for the current user. + * + * @param firstName first name of user + * @param lastName last name of user + * @param email email id of user + * @param langKey language key + * @param imageUrl image URL of user + */ + public void updateUser(String firstName, String lastName, String email, String langKey, String imageUrl) { + SecurityUtils.getCurrentUserLogin() + .flatMap(userRepository::findOneByLogin) + .ifPresent(user -> { + user.setFirstName(firstName); + user.setLastName(lastName); + user.setEmail(email.toLowerCase()); + user.setLangKey(langKey); + user.setImageUrl(imageUrl); + log.debug("Changed Information for User: {}", user); + }); + } + + /** + * Update all information for a specific user, and return the modified user. + * + * @param userDTO user to update + * @return updated user + */ + public Optional updateUser(UserDTO userDTO) { + return Optional.of(userRepository + .findById(userDTO.getId())) + .filter(Optional::isPresent) + .map(Optional::get) + .map(user -> { + user.setLogin(userDTO.getLogin().toLowerCase()); + user.setFirstName(userDTO.getFirstName()); + user.setLastName(userDTO.getLastName()); + user.setEmail(userDTO.getEmail().toLowerCase()); + user.setImageUrl(userDTO.getImageUrl()); + user.setActivated(userDTO.isActivated()); + user.setLangKey(userDTO.getLangKey()); + Set managedAuthorities = user.getAuthorities(); + managedAuthorities.clear(); + userDTO.getAuthorities().stream() + .map(authorityRepository::findById) + .filter(Optional::isPresent) + .map(Optional::get) + .forEach(managedAuthorities::add); + log.debug("Changed Information for User: {}", user); + return user; + }) + .map(UserDTO::new); + } + + public void deleteUser(String login) { + userRepository.findOneByLogin(login).ifPresent(user -> { + userRepository.delete(user); + log.debug("Deleted User: {}", user); + }); + } + + public void changePassword(String currentClearTextPassword, String newPassword) { + SecurityUtils.getCurrentUserLogin() + .flatMap(userRepository::findOneByLogin) + .ifPresent(user -> { + String currentEncryptedPassword = user.getPassword(); + if (!passwordEncoder.matches(currentClearTextPassword, currentEncryptedPassword)) { + throw new InvalidPasswordException(); + } + String encryptedPassword = passwordEncoder.encode(newPassword); + user.setPassword(encryptedPassword); + log.debug("Changed password for User: {}", user); + }); + } + + @Transactional(readOnly = true) + public Page getAllManagedUsers(Pageable pageable) { + return userRepository.findAllByLoginNot(pageable, Constants.ANONYMOUS_USER).map(UserDTO::new); + } + + @Transactional(readOnly = true) + public Optional getUserWithAuthoritiesByLogin(String login) { + return userRepository.findOneWithAuthoritiesByLogin(login); + } + + @Transactional(readOnly = true) + public Optional getUserWithAuthorities(Long id) { + return userRepository.findOneWithAuthoritiesById(id); + } + + @Transactional(readOnly = true) + public Optional getUserWithAuthorities() { + return SecurityUtils.getCurrentUserLogin().flatMap(userRepository::findOneWithAuthoritiesByLogin); + } + + /** + * Not activated users should be automatically deleted after 3 days. + *

+ * This is scheduled to get fired everyday, at 01:00 (am). + */ + @Scheduled(cron = "0 0 1 * * ?") + public void removeNotActivatedUsers() { + userRepository + .findAllByActivatedIsFalseAndCreatedDateBefore(Instant.now().minus(3, ChronoUnit.DAYS)) + .forEach(user -> { + log.debug("Deleting not activated user {}", user.getLogin()); + userRepository.delete(user); + }); + } + + /** + * @return a list of all the authorities + */ + public List getAuthorities() { + return authorityRepository.findAll().stream().map(Authority::getName).collect(Collectors.toList()); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/dto/BookDTO.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/dto/BookDTO.java new file mode 100644 index 0000000000..5aa550e989 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/dto/BookDTO.java @@ -0,0 +1,112 @@ +package com.baeldung.jhipster5.service.dto; +import java.time.LocalDate; +import javax.validation.constraints.*; +import java.io.Serializable; +import java.util.Objects; + +/** + * A DTO for the Book entity. + */ +public class BookDTO implements Serializable { + + private Long id; + + @NotNull + private String title; + + @NotNull + private String author; + + @NotNull + private LocalDate published; + + @NotNull + @Min(value = 0) + private Integer quantity; + + @NotNull + @DecimalMin(value = "0") + private Double price; + + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public LocalDate getPublished() { + return published; + } + + public void setPublished(LocalDate published) { + this.published = published; + } + + public Integer getQuantity() { + return quantity; + } + + public void setQuantity(Integer quantity) { + this.quantity = quantity; + } + + public Double getPrice() { + return price; + } + + public void setPrice(Double price) { + this.price = price; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + BookDTO bookDTO = (BookDTO) o; + if (bookDTO.getId() == null || getId() == null) { + return false; + } + return Objects.equals(getId(), bookDTO.getId()); + } + + @Override + public int hashCode() { + return Objects.hashCode(getId()); + } + + @Override + public String toString() { + return "BookDTO{" + + "id=" + getId() + + ", title='" + getTitle() + "'" + + ", author='" + getAuthor() + "'" + + ", published='" + getPublished() + "'" + + ", quantity=" + getQuantity() + + ", price=" + getPrice() + + "}"; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/dto/PasswordChangeDTO.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/dto/PasswordChangeDTO.java new file mode 100644 index 0000000000..0711c97f44 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/dto/PasswordChangeDTO.java @@ -0,0 +1,35 @@ +package com.baeldung.jhipster5.service.dto; + +/** + * A DTO representing a password change required data - current and new password. + */ +public class PasswordChangeDTO { + private String currentPassword; + private String newPassword; + + public PasswordChangeDTO() { + // Empty constructor needed for Jackson. + } + + public PasswordChangeDTO(String currentPassword, String newPassword) { + this.currentPassword = currentPassword; + this.newPassword = newPassword; + } + + public String getCurrentPassword() { + + return currentPassword; + } + + public void setCurrentPassword(String currentPassword) { + this.currentPassword = currentPassword; + } + + public String getNewPassword() { + return newPassword; + } + + public void setNewPassword(String newPassword) { + this.newPassword = newPassword; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/dto/UserDTO.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/dto/UserDTO.java new file mode 100644 index 0000000000..9142b3825e --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/dto/UserDTO.java @@ -0,0 +1,199 @@ +package com.baeldung.jhipster5.service.dto; + +import com.baeldung.jhipster5.config.Constants; + +import com.baeldung.jhipster5.domain.Authority; +import com.baeldung.jhipster5.domain.User; + +import javax.validation.constraints.Email; +import javax.validation.constraints.NotBlank; + +import javax.validation.constraints.*; +import java.time.Instant; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * A DTO representing a user, with his authorities. + */ +public class UserDTO { + + private Long id; + + @NotBlank + @Pattern(regexp = Constants.LOGIN_REGEX) + @Size(min = 1, max = 50) + private String login; + + @Size(max = 50) + private String firstName; + + @Size(max = 50) + private String lastName; + + @Email + @Size(min = 5, max = 254) + private String email; + + @Size(max = 256) + private String imageUrl; + + private boolean activated = false; + + @Size(min = 2, max = 6) + private String langKey; + + private String createdBy; + + private Instant createdDate; + + private String lastModifiedBy; + + private Instant lastModifiedDate; + + private Set authorities; + + public UserDTO() { + // Empty constructor needed for Jackson. + } + + public UserDTO(User user) { + this.id = user.getId(); + this.login = user.getLogin(); + this.firstName = user.getFirstName(); + this.lastName = user.getLastName(); + this.email = user.getEmail(); + this.activated = user.getActivated(); + this.imageUrl = user.getImageUrl(); + this.langKey = user.getLangKey(); + this.createdBy = user.getCreatedBy(); + this.createdDate = user.getCreatedDate(); + this.lastModifiedBy = user.getLastModifiedBy(); + this.lastModifiedDate = user.getLastModifiedDate(); + this.authorities = user.getAuthorities().stream() + .map(Authority::getName) + .collect(Collectors.toSet()); + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getLogin() { + return login; + } + + public void setLogin(String login) { + this.login = login; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getImageUrl() { + return imageUrl; + } + + public void setImageUrl(String imageUrl) { + this.imageUrl = imageUrl; + } + + public boolean isActivated() { + return activated; + } + + public void setActivated(boolean activated) { + this.activated = activated; + } + + public String getLangKey() { + return langKey; + } + + public void setLangKey(String langKey) { + this.langKey = langKey; + } + + public String getCreatedBy() { + return createdBy; + } + + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + public Instant getCreatedDate() { + return createdDate; + } + + public void setCreatedDate(Instant createdDate) { + this.createdDate = createdDate; + } + + public String getLastModifiedBy() { + return lastModifiedBy; + } + + public void setLastModifiedBy(String lastModifiedBy) { + this.lastModifiedBy = lastModifiedBy; + } + + public Instant getLastModifiedDate() { + return lastModifiedDate; + } + + public void setLastModifiedDate(Instant lastModifiedDate) { + this.lastModifiedDate = lastModifiedDate; + } + + public Set getAuthorities() { + return authorities; + } + + public void setAuthorities(Set authorities) { + this.authorities = authorities; + } + + @Override + public String toString() { + return "UserDTO{" + + "login='" + login + '\'' + + ", firstName='" + firstName + '\'' + + ", lastName='" + lastName + '\'' + + ", email='" + email + '\'' + + ", imageUrl='" + imageUrl + '\'' + + ", activated=" + activated + + ", langKey='" + langKey + '\'' + + ", createdBy=" + createdBy + + ", createdDate=" + createdDate + + ", lastModifiedBy='" + lastModifiedBy + '\'' + + ", lastModifiedDate=" + lastModifiedDate + + ", authorities=" + authorities + + "}"; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/dto/package-info.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/dto/package-info.java new file mode 100644 index 0000000000..87951796ea --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/dto/package-info.java @@ -0,0 +1,4 @@ +/** + * Data Transfer Objects. + */ +package com.baeldung.jhipster5.service.dto; diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/impl/BookServiceImpl.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/impl/BookServiceImpl.java new file mode 100644 index 0000000000..23cd59584c --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/impl/BookServiceImpl.java @@ -0,0 +1,109 @@ +package com.baeldung.jhipster5.service.impl; + +import com.baeldung.jhipster5.service.BookService; +import com.baeldung.jhipster5.domain.Book; +import com.baeldung.jhipster5.repository.BookRepository; +import com.baeldung.jhipster5.service.dto.BookDTO; +import com.baeldung.jhipster5.service.mapper.BookMapper; +import com.baeldung.jhipster5.web.rest.errors.BadRequestAlertException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.LinkedList; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +/** + * Service Implementation for managing Book. + */ +@Service +@Transactional +public class BookServiceImpl implements BookService { + + private final Logger log = LoggerFactory.getLogger(BookServiceImpl.class); + + private final BookRepository bookRepository; + + private final BookMapper bookMapper; + + public BookServiceImpl(BookRepository bookRepository, BookMapper bookMapper) { + this.bookRepository = bookRepository; + this.bookMapper = bookMapper; + } + + /** + * Save a book. + * + * @param bookDTO the entity to save + * @return the persisted entity + */ + @Override + public BookDTO save(BookDTO bookDTO) { + log.debug("Request to save Book : {}", bookDTO); + Book book = bookMapper.toEntity(bookDTO); + book = bookRepository.save(book); + return bookMapper.toDto(book); + } + + /** + * Get all the books. + * + * @return the list of entities + */ + @Override + @Transactional(readOnly = true) + public List findAll() { + log.debug("Request to get all Books"); + return bookRepository.findAll().stream() + .map(bookMapper::toDto) + .collect(Collectors.toCollection(LinkedList::new)); + } + + + /** + * Get one book by id. + * + * @param id the id of the entity + * @return the entity + */ + @Override + @Transactional(readOnly = true) + public Optional findOne(Long id) { + log.debug("Request to get Book : {}", id); + return bookRepository.findById(id) + .map(bookMapper::toDto); + } + + /** + * Delete the book by id. + * + * @param id the id of the entity + */ + @Override + public void delete(Long id) { + log.debug("Request to delete Book : {}", id); + bookRepository.deleteById(id); + } + + @Override + public Optional purchase(Long id) { + Optional bookDTO = findOne(id); + if(bookDTO.isPresent()) { + int quantity = bookDTO.get().getQuantity(); + if(quantity > 0) { + bookDTO.get().setQuantity(quantity - 1); + Book book = bookMapper.toEntity(bookDTO.get()); + book = bookRepository.save(book); + return bookDTO; + } + else { + throw new BadRequestAlertException("Book is not in stock", "book", "notinstock"); + } + } + return Optional.empty(); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/mapper/BookMapper.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/mapper/BookMapper.java new file mode 100644 index 0000000000..cd24c7088e --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/mapper/BookMapper.java @@ -0,0 +1,24 @@ +package com.baeldung.jhipster5.service.mapper; + +import com.baeldung.jhipster5.domain.*; +import com.baeldung.jhipster5.service.dto.BookDTO; + +import org.mapstruct.*; + +/** + * Mapper for the entity Book and its DTO BookDTO. + */ +@Mapper(componentModel = "spring", uses = {}) +public interface BookMapper extends EntityMapper { + + + + default Book fromId(Long id) { + if (id == null) { + return null; + } + Book book = new Book(); + book.setId(id); + return book; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/mapper/EntityMapper.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/mapper/EntityMapper.java new file mode 100644 index 0000000000..68af78179d --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/mapper/EntityMapper.java @@ -0,0 +1,21 @@ +package com.baeldung.jhipster5.service.mapper; + +import java.util.List; + +/** + * Contract for a generic dto to entity mapper. + * + * @param - DTO type parameter. + * @param - Entity type parameter. + */ + +public interface EntityMapper { + + E toEntity(D dto); + + D toDto(E entity); + + List toEntity(List dtoList); + + List toDto(List entityList); +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/mapper/UserMapper.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/mapper/UserMapper.java new file mode 100644 index 0000000000..485c03813e --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/mapper/UserMapper.java @@ -0,0 +1,81 @@ +package com.baeldung.jhipster5.service.mapper; + +import com.baeldung.jhipster5.domain.Authority; +import com.baeldung.jhipster5.domain.User; +import com.baeldung.jhipster5.service.dto.UserDTO; + +import org.springframework.stereotype.Service; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * Mapper for the entity User and its DTO called UserDTO. + * + * Normal mappers are generated using MapStruct, this one is hand-coded as MapStruct + * support is still in beta, and requires a manual step with an IDE. + */ +@Service +public class UserMapper { + + public List usersToUserDTOs(List users) { + return users.stream() + .filter(Objects::nonNull) + .map(this::userToUserDTO) + .collect(Collectors.toList()); + } + + public UserDTO userToUserDTO(User user) { + return new UserDTO(user); + } + + public List userDTOsToUsers(List userDTOs) { + return userDTOs.stream() + .filter(Objects::nonNull) + .map(this::userDTOToUser) + .collect(Collectors.toList()); + } + + public User userDTOToUser(UserDTO userDTO) { + if (userDTO == null) { + return null; + } else { + User user = new User(); + user.setId(userDTO.getId()); + user.setLogin(userDTO.getLogin()); + user.setFirstName(userDTO.getFirstName()); + user.setLastName(userDTO.getLastName()); + user.setEmail(userDTO.getEmail()); + user.setImageUrl(userDTO.getImageUrl()); + user.setActivated(userDTO.isActivated()); + user.setLangKey(userDTO.getLangKey()); + Set authorities = this.authoritiesFromStrings(userDTO.getAuthorities()); + user.setAuthorities(authorities); + return user; + } + } + + + private Set authoritiesFromStrings(Set authoritiesAsString) { + Set authorities = new HashSet<>(); + + if(authoritiesAsString != null){ + authorities = authoritiesAsString.stream().map(string -> { + Authority auth = new Authority(); + auth.setName(string); + return auth; + }).collect(Collectors.toSet()); + } + + return authorities; + } + + public User userFromId(Long id) { + if (id == null) { + return null; + } + User user = new User(); + user.setId(id); + return user; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/mapper/package-info.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/mapper/package-info.java new file mode 100644 index 0000000000..7d402321e7 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/mapper/package-info.java @@ -0,0 +1,4 @@ +/** + * MapStruct mappers for mapping domain objects and Data Transfer Objects. + */ +package com.baeldung.jhipster5.service.mapper; diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/package-info.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/package-info.java new file mode 100644 index 0000000000..a54ed5cca0 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/package-info.java @@ -0,0 +1,4 @@ +/** + * Service layer beans. + */ +package com.baeldung.jhipster5.service; diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/util/RandomUtil.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/util/RandomUtil.java new file mode 100644 index 0000000000..97e4d9c672 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/util/RandomUtil.java @@ -0,0 +1,41 @@ +package com.baeldung.jhipster5.service.util; + +import org.apache.commons.lang3.RandomStringUtils; + +/** + * Utility class for generating random Strings. + */ +public final class RandomUtil { + + private static final int DEF_COUNT = 20; + + private RandomUtil() { + } + + /** + * Generate a password. + * + * @return the generated password + */ + public static String generatePassword() { + return RandomStringUtils.randomAlphanumeric(DEF_COUNT); + } + + /** + * Generate an activation key. + * + * @return the generated activation key + */ + public static String generateActivationKey() { + return RandomStringUtils.randomNumeric(DEF_COUNT); + } + + /** + * Generate a reset key. + * + * @return the generated reset key + */ + public static String generateResetKey() { + return RandomStringUtils.randomNumeric(DEF_COUNT); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/AccountResource.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/AccountResource.java new file mode 100644 index 0000000000..2109e93999 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/AccountResource.java @@ -0,0 +1,179 @@ +package com.baeldung.jhipster5.web.rest; + + +import com.baeldung.jhipster5.domain.User; +import com.baeldung.jhipster5.repository.UserRepository; +import com.baeldung.jhipster5.security.SecurityUtils; +import com.baeldung.jhipster5.service.MailService; +import com.baeldung.jhipster5.service.UserService; +import com.baeldung.jhipster5.service.dto.PasswordChangeDTO; +import com.baeldung.jhipster5.service.dto.UserDTO; +import com.baeldung.jhipster5.web.rest.errors.*; +import com.baeldung.jhipster5.web.rest.vm.KeyAndPasswordVM; +import com.baeldung.jhipster5.web.rest.vm.ManagedUserVM; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; +import java.util.*; + +/** + * REST controller for managing the current user's account. + */ +@RestController +@RequestMapping("/api") +public class AccountResource { + + private final Logger log = LoggerFactory.getLogger(AccountResource.class); + + private final UserRepository userRepository; + + private final UserService userService; + + private final MailService mailService; + + public AccountResource(UserRepository userRepository, UserService userService, MailService mailService) { + + this.userRepository = userRepository; + this.userService = userService; + this.mailService = mailService; + } + + /** + * POST /register : register the user. + * + * @param managedUserVM the managed user View Model + * @throws InvalidPasswordException 400 (Bad Request) if the password is incorrect + * @throws EmailAlreadyUsedException 400 (Bad Request) if the email is already used + * @throws LoginAlreadyUsedException 400 (Bad Request) if the login is already used + */ + @PostMapping("/register") + @ResponseStatus(HttpStatus.CREATED) + public void registerAccount(@Valid @RequestBody ManagedUserVM managedUserVM) { + if (!checkPasswordLength(managedUserVM.getPassword())) { + throw new InvalidPasswordException(); + } + User user = userService.registerUser(managedUserVM, managedUserVM.getPassword()); + mailService.sendActivationEmail(user); + } + + /** + * GET /activate : activate the registered user. + * + * @param key the activation key + * @throws RuntimeException 500 (Internal Server Error) if the user couldn't be activated + */ + @GetMapping("/activate") + public void activateAccount(@RequestParam(value = "key") String key) { + Optional user = userService.activateRegistration(key); + if (!user.isPresent()) { + throw new InternalServerErrorException("No user was found for this activation key"); + } + } + + /** + * GET /authenticate : check if the user is authenticated, and return its login. + * + * @param request the HTTP request + * @return the login if the user is authenticated + */ + @GetMapping("/authenticate") + public String isAuthenticated(HttpServletRequest request) { + log.debug("REST request to check if the current user is authenticated"); + return request.getRemoteUser(); + } + + /** + * GET /account : get the current user. + * + * @return the current user + * @throws RuntimeException 500 (Internal Server Error) if the user couldn't be returned + */ + @GetMapping("/account") + public UserDTO getAccount() { + return userService.getUserWithAuthorities() + .map(UserDTO::new) + .orElseThrow(() -> new InternalServerErrorException("User could not be found")); + } + + /** + * POST /account : update the current user information. + * + * @param userDTO the current user information + * @throws EmailAlreadyUsedException 400 (Bad Request) if the email is already used + * @throws RuntimeException 500 (Internal Server Error) if the user login wasn't found + */ + @PostMapping("/account") + public void saveAccount(@Valid @RequestBody UserDTO userDTO) { + String userLogin = SecurityUtils.getCurrentUserLogin().orElseThrow(() -> new InternalServerErrorException("Current user login not found")); + Optional existingUser = userRepository.findOneByEmailIgnoreCase(userDTO.getEmail()); + if (existingUser.isPresent() && (!existingUser.get().getLogin().equalsIgnoreCase(userLogin))) { + throw new EmailAlreadyUsedException(); + } + Optional user = userRepository.findOneByLogin(userLogin); + if (!user.isPresent()) { + throw new InternalServerErrorException("User could not be found"); + } + userService.updateUser(userDTO.getFirstName(), userDTO.getLastName(), userDTO.getEmail(), + userDTO.getLangKey(), userDTO.getImageUrl()); + } + + /** + * POST /account/change-password : changes the current user's password + * + * @param passwordChangeDto current and new password + * @throws InvalidPasswordException 400 (Bad Request) if the new password is incorrect + */ + @PostMapping(path = "/account/change-password") + public void changePassword(@RequestBody PasswordChangeDTO passwordChangeDto) { + if (!checkPasswordLength(passwordChangeDto.getNewPassword())) { + throw new InvalidPasswordException(); + } + userService.changePassword(passwordChangeDto.getCurrentPassword(), passwordChangeDto.getNewPassword()); + } + + /** + * POST /account/reset-password/init : Send an email to reset the password of the user + * + * @param mail the mail of the user + * @throws EmailNotFoundException 400 (Bad Request) if the email address is not registered + */ + @PostMapping(path = "/account/reset-password/init") + public void requestPasswordReset(@RequestBody String mail) { + mailService.sendPasswordResetMail( + userService.requestPasswordReset(mail) + .orElseThrow(EmailNotFoundException::new) + ); + } + + /** + * POST /account/reset-password/finish : Finish to reset the password of the user + * + * @param keyAndPassword the generated key and the new password + * @throws InvalidPasswordException 400 (Bad Request) if the password is incorrect + * @throws RuntimeException 500 (Internal Server Error) if the password could not be reset + */ + @PostMapping(path = "/account/reset-password/finish") + public void finishPasswordReset(@RequestBody KeyAndPasswordVM keyAndPassword) { + if (!checkPasswordLength(keyAndPassword.getNewPassword())) { + throw new InvalidPasswordException(); + } + Optional user = + userService.completePasswordReset(keyAndPassword.getNewPassword(), keyAndPassword.getKey()); + + if (!user.isPresent()) { + throw new InternalServerErrorException("No user was found for this reset key"); + } + } + + private static boolean checkPasswordLength(String password) { + return !StringUtils.isEmpty(password) && + password.length() >= ManagedUserVM.PASSWORD_MIN_LENGTH && + password.length() <= ManagedUserVM.PASSWORD_MAX_LENGTH; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/AuditResource.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/AuditResource.java new file mode 100644 index 0000000000..d0182d5d9d --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/AuditResource.java @@ -0,0 +1,77 @@ +package com.baeldung.jhipster5.web.rest; + +import com.baeldung.jhipster5.service.AuditEventService; +import com.baeldung.jhipster5.web.rest.util.PaginationUtil; + +import io.github.jhipster.web.util.ResponseUtil; +import org.springframework.boot.actuate.audit.AuditEvent; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.time.LocalDate; +import java.time.ZoneId; +import java.util.List; + +/** + * REST controller for getting the audit events. + */ +@RestController +@RequestMapping("/management/audits") +public class AuditResource { + + private final AuditEventService auditEventService; + + public AuditResource(AuditEventService auditEventService) { + this.auditEventService = auditEventService; + } + + /** + * GET /audits : get a page of AuditEvents. + * + * @param pageable the pagination information + * @return the ResponseEntity with status 200 (OK) and the list of AuditEvents in body + */ + @GetMapping + public ResponseEntity> getAll(Pageable pageable) { + Page page = auditEventService.findAll(pageable); + HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/management/audits"); + return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK); + } + + /** + * GET /audits : get a page of AuditEvents between the fromDate and toDate. + * + * @param fromDate the start of the time period of AuditEvents to get + * @param toDate the end of the time period of AuditEvents to get + * @param pageable the pagination information + * @return the ResponseEntity with status 200 (OK) and the list of AuditEvents in body + */ + @GetMapping(params = {"fromDate", "toDate"}) + public ResponseEntity> getByDates( + @RequestParam(value = "fromDate") LocalDate fromDate, + @RequestParam(value = "toDate") LocalDate toDate, + Pageable pageable) { + + Page page = auditEventService.findByDates( + fromDate.atStartOfDay(ZoneId.systemDefault()).toInstant(), + toDate.atStartOfDay(ZoneId.systemDefault()).plusDays(1).toInstant(), + pageable); + HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/management/audits"); + return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK); + } + + /** + * GET /audits/:id : get an AuditEvent by id. + * + * @param id the id of the entity to get + * @return the ResponseEntity with status 200 (OK) and the AuditEvent in body, or status 404 (Not Found) + */ + @GetMapping("/{id:.+}") + public ResponseEntity get(@PathVariable Long id) { + return ResponseUtil.wrapOrNotFound(auditEventService.find(id)); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/BookResource.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/BookResource.java new file mode 100644 index 0000000000..0360ea05ed --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/BookResource.java @@ -0,0 +1,118 @@ +package com.baeldung.jhipster5.web.rest; +import com.baeldung.jhipster5.service.BookService; +import com.baeldung.jhipster5.web.rest.errors.BadRequestAlertException; +import com.baeldung.jhipster5.web.rest.util.HeaderUtil; +import com.baeldung.jhipster5.service.dto.BookDTO; +import io.github.jhipster.web.util.ResponseUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.net.URI; +import java.net.URISyntaxException; + +import java.util.List; +import java.util.Optional; + +/** + * REST controller for managing Book. + */ +@RestController +@RequestMapping("/api") +public class BookResource { + + private final Logger log = LoggerFactory.getLogger(BookResource.class); + + private static final String ENTITY_NAME = "book"; + + private final BookService bookService; + + public BookResource(BookService bookService) { + this.bookService = bookService; + } + + /** + * POST /books : Create a new book. + * + * @param bookDTO the bookDTO to create + * @return the ResponseEntity with status 201 (Created) and with body the new bookDTO, or with status 400 (Bad Request) if the book has already an ID + * @throws URISyntaxException if the Location URI syntax is incorrect + */ + @PostMapping("/books") + public ResponseEntity createBook(@Valid @RequestBody BookDTO bookDTO) throws URISyntaxException { + log.debug("REST request to save Book : {}", bookDTO); + if (bookDTO.getId() != null) { + throw new BadRequestAlertException("A new book cannot already have an ID", ENTITY_NAME, "idexists"); + } + BookDTO result = bookService.save(bookDTO); + return ResponseEntity.created(new URI("/api/books/" + result.getId())) + .headers(HeaderUtil.createEntityCreationAlert(ENTITY_NAME, result.getId().toString())) + .body(result); + } + + /** + * PUT /books : Updates an existing book. + * + * @param bookDTO the bookDTO to update + * @return the ResponseEntity with status 200 (OK) and with body the updated bookDTO, + * or with status 400 (Bad Request) if the bookDTO is not valid, + * or with status 500 (Internal Server Error) if the bookDTO couldn't be updated + * @throws URISyntaxException if the Location URI syntax is incorrect + */ + @PutMapping("/books") + public ResponseEntity updateBook(@Valid @RequestBody BookDTO bookDTO) throws URISyntaxException { + log.debug("REST request to update Book : {}", bookDTO); + if (bookDTO.getId() == null) { + throw new BadRequestAlertException("Invalid id", ENTITY_NAME, "idnull"); + } + BookDTO result = bookService.save(bookDTO); + return ResponseEntity.ok() + .headers(HeaderUtil.createEntityUpdateAlert(ENTITY_NAME, bookDTO.getId().toString())) + .body(result); + } + + /** + * GET /books : get all the books. + * + * @return the ResponseEntity with status 200 (OK) and the list of books in body + */ + @GetMapping("/books") + public List getAllBooks() { + log.debug("REST request to get all Books"); + return bookService.findAll(); + } + + /** + * GET /books/:id : get the "id" book. + * + * @param id the id of the bookDTO to retrieve + * @return the ResponseEntity with status 200 (OK) and with body the bookDTO, or with status 404 (Not Found) + */ + @GetMapping("/books/{id}") + public ResponseEntity getBook(@PathVariable Long id) { + log.debug("REST request to get Book : {}", id); + Optional bookDTO = bookService.findOne(id); + return ResponseUtil.wrapOrNotFound(bookDTO); + } + + /** + * DELETE /books/:id : delete the "id" book. + * + * @param id the id of the bookDTO to delete + * @return the ResponseEntity with status 200 (OK) + */ + @DeleteMapping("/books/{id}") + public ResponseEntity deleteBook(@PathVariable Long id) { + log.debug("REST request to delete Book : {}", id); + bookService.delete(id); + return ResponseEntity.ok().headers(HeaderUtil.createEntityDeletionAlert(ENTITY_NAME, id.toString())).build(); + } + + @GetMapping("/books/purchase/{id}") + public ResponseEntity purchase(@PathVariable Long id) { + Optional bookDTO = bookService.purchase(id); + return ResponseUtil.wrapOrNotFound(bookDTO); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/LogsResource.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/LogsResource.java new file mode 100644 index 0000000000..f35b5f2d5c --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/LogsResource.java @@ -0,0 +1,36 @@ +package com.baeldung.jhipster5.web.rest; + +import com.baeldung.jhipster5.web.rest.vm.LoggerVM; + +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.LoggerContext; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * Controller for view and managing Log Level at runtime. + */ +@RestController +@RequestMapping("/management") +public class LogsResource { + + @GetMapping("/logs") + public List getList() { + LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); + return context.getLoggerList() + .stream() + .map(LoggerVM::new) + .collect(Collectors.toList()); + } + + @PutMapping("/logs") + @ResponseStatus(HttpStatus.NO_CONTENT) + public void changeLevel(@RequestBody LoggerVM jsonLogger) { + LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); + context.getLogger(jsonLogger.getName()).setLevel(Level.valueOf(jsonLogger.getLevel())); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/UserJWTController.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/UserJWTController.java new file mode 100644 index 0000000000..aeea587089 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/UserJWTController.java @@ -0,0 +1,71 @@ +package com.baeldung.jhipster5.web.rest; + +import com.baeldung.jhipster5.security.jwt.JWTFilter; +import com.baeldung.jhipster5.security.jwt.TokenProvider; +import com.baeldung.jhipster5.web.rest.vm.LoginVM; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; + +/** + * Controller to authenticate users. + */ +@RestController +@RequestMapping("/api") +public class UserJWTController { + + private final TokenProvider tokenProvider; + + private final AuthenticationManager authenticationManager; + + public UserJWTController(TokenProvider tokenProvider, AuthenticationManager authenticationManager) { + this.tokenProvider = tokenProvider; + this.authenticationManager = authenticationManager; + } + + @PostMapping("/authenticate") + public ResponseEntity authorize(@Valid @RequestBody LoginVM loginVM) { + + UsernamePasswordAuthenticationToken authenticationToken = + new UsernamePasswordAuthenticationToken(loginVM.getUsername(), loginVM.getPassword()); + + Authentication authentication = this.authenticationManager.authenticate(authenticationToken); + SecurityContextHolder.getContext().setAuthentication(authentication); + boolean rememberMe = (loginVM.isRememberMe() == null) ? false : loginVM.isRememberMe(); + String jwt = tokenProvider.createToken(authentication, rememberMe); + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.add(JWTFilter.AUTHORIZATION_HEADER, "Bearer " + jwt); + return new ResponseEntity<>(new JWTToken(jwt), httpHeaders, HttpStatus.OK); + } + + /** + * Object to return as body in JWT Authentication. + */ + static class JWTToken { + + private String idToken; + + JWTToken(String idToken) { + this.idToken = idToken; + } + + @JsonProperty("id_token") + String getIdToken() { + return idToken; + } + + void setIdToken(String idToken) { + this.idToken = idToken; + } + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/UserResource.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/UserResource.java new file mode 100644 index 0000000000..a95acf6759 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/UserResource.java @@ -0,0 +1,183 @@ +package com.baeldung.jhipster5.web.rest; + +import com.baeldung.jhipster5.config.Constants; +import com.baeldung.jhipster5.domain.User; +import com.baeldung.jhipster5.repository.UserRepository; +import com.baeldung.jhipster5.security.AuthoritiesConstants; +import com.baeldung.jhipster5.service.MailService; +import com.baeldung.jhipster5.service.UserService; +import com.baeldung.jhipster5.service.dto.UserDTO; +import com.baeldung.jhipster5.web.rest.errors.BadRequestAlertException; +import com.baeldung.jhipster5.web.rest.errors.EmailAlreadyUsedException; +import com.baeldung.jhipster5.web.rest.errors.LoginAlreadyUsedException; +import com.baeldung.jhipster5.web.rest.util.HeaderUtil; +import com.baeldung.jhipster5.web.rest.util.PaginationUtil; +import io.github.jhipster.web.util.ResponseUtil; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.*; + +/** + * REST controller for managing users. + *

+ * This class accesses the User entity, and needs to fetch its collection of authorities. + *

+ * For a normal use-case, it would be better to have an eager relationship between User and Authority, + * and send everything to the client side: there would be no View Model and DTO, a lot less code, and an outer-join + * which would be good for performance. + *

+ * We use a View Model and a DTO for 3 reasons: + *

    + *
  • We want to keep a lazy association between the user and the authorities, because people will + * quite often do relationships with the user, and we don't want them to get the authorities all + * the time for nothing (for performance reasons). This is the #1 goal: we should not impact our users' + * application because of this use-case.
  • + *
  • Not having an outer join causes n+1 requests to the database. This is not a real issue as + * we have by default a second-level cache. This means on the first HTTP call we do the n+1 requests, + * but then all authorities come from the cache, so in fact it's much better than doing an outer join + * (which will get lots of data from the database, for each HTTP call).
  • + *
  • As this manages users, for security reasons, we'd rather have a DTO layer.
  • + *
+ *

+ * Another option would be to have a specific JPA entity graph to handle this case. + */ +@RestController +@RequestMapping("/api") +public class UserResource { + + private final Logger log = LoggerFactory.getLogger(UserResource.class); + + private final UserService userService; + + private final UserRepository userRepository; + + private final MailService mailService; + + public UserResource(UserService userService, UserRepository userRepository, MailService mailService) { + + this.userService = userService; + this.userRepository = userRepository; + this.mailService = mailService; + } + + /** + * POST /users : Creates a new user. + *

+ * Creates a new user if the login and email are not already used, and sends an + * mail with an activation link. + * The user needs to be activated on creation. + * + * @param userDTO the user to create + * @return the ResponseEntity with status 201 (Created) and with body the new user, or with status 400 (Bad Request) if the login or email is already in use + * @throws URISyntaxException if the Location URI syntax is incorrect + * @throws BadRequestAlertException 400 (Bad Request) if the login or email is already in use + */ + @PostMapping("/users") + @PreAuthorize("hasRole(\"" + AuthoritiesConstants.ADMIN + "\")") + public ResponseEntity createUser(@Valid @RequestBody UserDTO userDTO) throws URISyntaxException { + log.debug("REST request to save User : {}", userDTO); + + if (userDTO.getId() != null) { + throw new BadRequestAlertException("A new user cannot already have an ID", "userManagement", "idexists"); + // Lowercase the user login before comparing with database + } else if (userRepository.findOneByLogin(userDTO.getLogin().toLowerCase()).isPresent()) { + throw new LoginAlreadyUsedException(); + } else if (userRepository.findOneByEmailIgnoreCase(userDTO.getEmail()).isPresent()) { + throw new EmailAlreadyUsedException(); + } else { + User newUser = userService.createUser(userDTO); + mailService.sendCreationEmail(newUser); + return ResponseEntity.created(new URI("/api/users/" + newUser.getLogin())) + .headers(HeaderUtil.createAlert( "A user is created with identifier " + newUser.getLogin(), newUser.getLogin())) + .body(newUser); + } + } + + /** + * PUT /users : Updates an existing User. + * + * @param userDTO the user to update + * @return the ResponseEntity with status 200 (OK) and with body the updated user + * @throws EmailAlreadyUsedException 400 (Bad Request) if the email is already in use + * @throws LoginAlreadyUsedException 400 (Bad Request) if the login is already in use + */ + @PutMapping("/users") + @PreAuthorize("hasRole(\"" + AuthoritiesConstants.ADMIN + "\")") + public ResponseEntity updateUser(@Valid @RequestBody UserDTO userDTO) { + log.debug("REST request to update User : {}", userDTO); + Optional existingUser = userRepository.findOneByEmailIgnoreCase(userDTO.getEmail()); + if (existingUser.isPresent() && (!existingUser.get().getId().equals(userDTO.getId()))) { + throw new EmailAlreadyUsedException(); + } + existingUser = userRepository.findOneByLogin(userDTO.getLogin().toLowerCase()); + if (existingUser.isPresent() && (!existingUser.get().getId().equals(userDTO.getId()))) { + throw new LoginAlreadyUsedException(); + } + Optional updatedUser = userService.updateUser(userDTO); + + return ResponseUtil.wrapOrNotFound(updatedUser, + HeaderUtil.createAlert("A user is updated with identifier " + userDTO.getLogin(), userDTO.getLogin())); + } + + /** + * GET /users : get all users. + * + * @param pageable the pagination information + * @return the ResponseEntity with status 200 (OK) and with body all users + */ + @GetMapping("/users") + public ResponseEntity> getAllUsers(Pageable pageable) { + final Page page = userService.getAllManagedUsers(pageable); + HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/api/users"); + return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK); + } + + /** + * @return a string list of the all of the roles + */ + @GetMapping("/users/authorities") + @PreAuthorize("hasRole(\"" + AuthoritiesConstants.ADMIN + "\")") + public List getAuthorities() { + return userService.getAuthorities(); + } + + /** + * GET /users/:login : get the "login" user. + * + * @param login the login of the user to find + * @return the ResponseEntity with status 200 (OK) and with body the "login" user, or with status 404 (Not Found) + */ + @GetMapping("/users/{login:" + Constants.LOGIN_REGEX + "}") + public ResponseEntity getUser(@PathVariable String login) { + log.debug("REST request to get User : {}", login); + return ResponseUtil.wrapOrNotFound( + userService.getUserWithAuthoritiesByLogin(login) + .map(UserDTO::new)); + } + + /** + * DELETE /users/:login : delete the "login" User. + * + * @param login the login of the user to delete + * @return the ResponseEntity with status 200 (OK) + */ + @DeleteMapping("/users/{login:" + Constants.LOGIN_REGEX + "}") + @PreAuthorize("hasRole(\"" + AuthoritiesConstants.ADMIN + "\")") + public ResponseEntity deleteUser(@PathVariable String login) { + log.debug("REST request to delete User: {}", login); + userService.deleteUser(login); + return ResponseEntity.ok().headers(HeaderUtil.createAlert( "A user is deleted with identifier " + login, login)).build(); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/BadRequestAlertException.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/BadRequestAlertException.java new file mode 100644 index 0000000000..c4c403351a --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/BadRequestAlertException.java @@ -0,0 +1,42 @@ +package com.baeldung.jhipster5.web.rest.errors; + +import org.zalando.problem.AbstractThrowableProblem; +import org.zalando.problem.Status; + +import java.net.URI; +import java.util.HashMap; +import java.util.Map; + +public class BadRequestAlertException extends AbstractThrowableProblem { + + private static final long serialVersionUID = 1L; + + private final String entityName; + + private final String errorKey; + + public BadRequestAlertException(String defaultMessage, String entityName, String errorKey) { + this(ErrorConstants.DEFAULT_TYPE, defaultMessage, entityName, errorKey); + } + + public BadRequestAlertException(URI type, String defaultMessage, String entityName, String errorKey) { + super(type, defaultMessage, Status.BAD_REQUEST, null, null, null, getAlertParameters(entityName, errorKey)); + this.entityName = entityName; + this.errorKey = errorKey; + } + + public String getEntityName() { + return entityName; + } + + public String getErrorKey() { + return errorKey; + } + + private static Map getAlertParameters(String entityName, String errorKey) { + Map parameters = new HashMap<>(); + parameters.put("message", "error." + errorKey); + parameters.put("params", entityName); + return parameters; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/CustomParameterizedException.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/CustomParameterizedException.java new file mode 100644 index 0000000000..8c3df82b83 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/CustomParameterizedException.java @@ -0,0 +1,54 @@ +package com.baeldung.jhipster5.web.rest.errors; + +import org.zalando.problem.AbstractThrowableProblem; + +import java.util.HashMap; +import java.util.Map; + +import static org.zalando.problem.Status.BAD_REQUEST; + +/** + * Custom, parameterized exception, which can be translated on the client side. + * For example: + * + *

+ * throw new CustomParameterizedException("myCustomError", "hello", "world");
+ * 
+ * + * Can be translated with: + * + *
+ * "error.myCustomError" :  "The server says {{param0}} to {{param1}}"
+ * 
+ */ +public class CustomParameterizedException extends AbstractThrowableProblem { + + private static final long serialVersionUID = 1L; + + private static final String PARAM = "param"; + + public CustomParameterizedException(String message, String... params) { + this(message, toParamMap(params)); + } + + public CustomParameterizedException(String message, Map paramMap) { + super(ErrorConstants.PARAMETERIZED_TYPE, "Parameterized Exception", BAD_REQUEST, null, null, null, toProblemParameters(message, paramMap)); + } + + public static Map toParamMap(String... params) { + Map paramMap = new HashMap<>(); + if (params != null && params.length > 0) { + for (int i = 0; i < params.length; i++) { + paramMap.put(PARAM + i, params[i]); + } + } + return paramMap; + } + + public static Map toProblemParameters(String message, Map paramMap) { + Map parameters = new HashMap<>(); + parameters.put("message", message); + parameters.put("params", paramMap); + return parameters; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/EmailAlreadyUsedException.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/EmailAlreadyUsedException.java new file mode 100644 index 0000000000..b3dcc0279e --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/EmailAlreadyUsedException.java @@ -0,0 +1,10 @@ +package com.baeldung.jhipster5.web.rest.errors; + +public class EmailAlreadyUsedException extends BadRequestAlertException { + + private static final long serialVersionUID = 1L; + + public EmailAlreadyUsedException() { + super(ErrorConstants.EMAIL_ALREADY_USED_TYPE, "Email is already in use!", "userManagement", "emailexists"); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/EmailNotFoundException.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/EmailNotFoundException.java new file mode 100644 index 0000000000..b93081cacb --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/EmailNotFoundException.java @@ -0,0 +1,13 @@ +package com.baeldung.jhipster5.web.rest.errors; + +import org.zalando.problem.AbstractThrowableProblem; +import org.zalando.problem.Status; + +public class EmailNotFoundException extends AbstractThrowableProblem { + + private static final long serialVersionUID = 1L; + + public EmailNotFoundException() { + super(ErrorConstants.EMAIL_NOT_FOUND_TYPE, "Email address not registered", Status.BAD_REQUEST); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/ErrorConstants.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/ErrorConstants.java new file mode 100644 index 0000000000..06be9254a9 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/ErrorConstants.java @@ -0,0 +1,21 @@ +package com.baeldung.jhipster5.web.rest.errors; + +import java.net.URI; + +public final class ErrorConstants { + + public static final String ERR_CONCURRENCY_FAILURE = "error.concurrencyFailure"; + public static final String ERR_VALIDATION = "error.validation"; + public static final String PROBLEM_BASE_URL = "https://www.jhipster.tech/problem"; + public static final URI DEFAULT_TYPE = URI.create(PROBLEM_BASE_URL + "/problem-with-message"); + public static final URI CONSTRAINT_VIOLATION_TYPE = URI.create(PROBLEM_BASE_URL + "/constraint-violation"); + public static final URI PARAMETERIZED_TYPE = URI.create(PROBLEM_BASE_URL + "/parameterized"); + public static final URI ENTITY_NOT_FOUND_TYPE = URI.create(PROBLEM_BASE_URL + "/entity-not-found"); + public static final URI INVALID_PASSWORD_TYPE = URI.create(PROBLEM_BASE_URL + "/invalid-password"); + public static final URI EMAIL_ALREADY_USED_TYPE = URI.create(PROBLEM_BASE_URL + "/email-already-used"); + public static final URI LOGIN_ALREADY_USED_TYPE = URI.create(PROBLEM_BASE_URL + "/login-already-used"); + public static final URI EMAIL_NOT_FOUND_TYPE = URI.create(PROBLEM_BASE_URL + "/email-not-found"); + + private ErrorConstants() { + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/ExceptionTranslator.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/ExceptionTranslator.java new file mode 100644 index 0000000000..3f7cc6b565 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/ExceptionTranslator.java @@ -0,0 +1,112 @@ +package com.baeldung.jhipster5.web.rest.errors; + +import com.baeldung.jhipster5.web.rest.util.HeaderUtil; + +import org.springframework.dao.ConcurrencyFailureException; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.context.request.NativeWebRequest; +import org.zalando.problem.DefaultProblem; +import org.zalando.problem.Problem; +import org.zalando.problem.ProblemBuilder; +import org.zalando.problem.Status; +import org.zalando.problem.spring.web.advice.ProblemHandling; +import org.zalando.problem.violations.ConstraintViolationProblem; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import javax.servlet.http.HttpServletRequest; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.stream.Collectors; + +/** + * Controller advice to translate the server side exceptions to client-friendly json structures. + * The error response follows RFC7807 - Problem Details for HTTP APIs (https://tools.ietf.org/html/rfc7807) + */ +@ControllerAdvice +public class ExceptionTranslator implements ProblemHandling { + + private static final String FIELD_ERRORS_KEY = "fieldErrors"; + private static final String MESSAGE_KEY = "message"; + private static final String PATH_KEY = "path"; + private static final String VIOLATIONS_KEY = "violations"; + + /** + * Post-process the Problem payload to add the message key for the front-end if needed + */ + @Override + public ResponseEntity process(@Nullable ResponseEntity entity, NativeWebRequest request) { + if (entity == null) { + return entity; + } + Problem problem = entity.getBody(); + if (!(problem instanceof ConstraintViolationProblem || problem instanceof DefaultProblem)) { + return entity; + } + ProblemBuilder builder = Problem.builder() + .withType(Problem.DEFAULT_TYPE.equals(problem.getType()) ? ErrorConstants.DEFAULT_TYPE : problem.getType()) + .withStatus(problem.getStatus()) + .withTitle(problem.getTitle()) + .with(PATH_KEY, request.getNativeRequest(HttpServletRequest.class).getRequestURI()); + + if (problem instanceof ConstraintViolationProblem) { + builder + .with(VIOLATIONS_KEY, ((ConstraintViolationProblem) problem).getViolations()) + .with(MESSAGE_KEY, ErrorConstants.ERR_VALIDATION); + } else { + builder + .withCause(((DefaultProblem) problem).getCause()) + .withDetail(problem.getDetail()) + .withInstance(problem.getInstance()); + problem.getParameters().forEach(builder::with); + if (!problem.getParameters().containsKey(MESSAGE_KEY) && problem.getStatus() != null) { + builder.with(MESSAGE_KEY, "error.http." + problem.getStatus().getStatusCode()); + } + } + return new ResponseEntity<>(builder.build(), entity.getHeaders(), entity.getStatusCode()); + } + + @Override + public ResponseEntity handleMethodArgumentNotValid(MethodArgumentNotValidException ex, @Nonnull NativeWebRequest request) { + BindingResult result = ex.getBindingResult(); + List fieldErrors = result.getFieldErrors().stream() + .map(f -> new FieldErrorVM(f.getObjectName(), f.getField(), f.getCode())) + .collect(Collectors.toList()); + + Problem problem = Problem.builder() + .withType(ErrorConstants.CONSTRAINT_VIOLATION_TYPE) + .withTitle("Method argument not valid") + .withStatus(defaultConstraintViolationStatus()) + .with(MESSAGE_KEY, ErrorConstants.ERR_VALIDATION) + .with(FIELD_ERRORS_KEY, fieldErrors) + .build(); + return create(ex, problem, request); + } + + @ExceptionHandler + public ResponseEntity handleNoSuchElementException(NoSuchElementException ex, NativeWebRequest request) { + Problem problem = Problem.builder() + .withStatus(Status.NOT_FOUND) + .with(MESSAGE_KEY, ErrorConstants.ENTITY_NOT_FOUND_TYPE) + .build(); + return create(ex, problem, request); + } + + @ExceptionHandler + public ResponseEntity handleBadRequestAlertException(BadRequestAlertException ex, NativeWebRequest request) { + return create(ex, request, HeaderUtil.createFailureAlert(ex.getEntityName(), ex.getErrorKey(), ex.getMessage())); + } + + @ExceptionHandler + public ResponseEntity handleConcurrencyFailure(ConcurrencyFailureException ex, NativeWebRequest request) { + Problem problem = Problem.builder() + .withStatus(Status.CONFLICT) + .with(MESSAGE_KEY, ErrorConstants.ERR_CONCURRENCY_FAILURE) + .build(); + return create(ex, problem, request); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/FieldErrorVM.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/FieldErrorVM.java new file mode 100644 index 0000000000..349f548850 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/FieldErrorVM.java @@ -0,0 +1,33 @@ +package com.baeldung.jhipster5.web.rest.errors; + +import java.io.Serializable; + +public class FieldErrorVM implements Serializable { + + private static final long serialVersionUID = 1L; + + private final String objectName; + + private final String field; + + private final String message; + + public FieldErrorVM(String dto, String field, String message) { + this.objectName = dto; + this.field = field; + this.message = message; + } + + public String getObjectName() { + return objectName; + } + + public String getField() { + return field; + } + + public String getMessage() { + return message; + } + +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/InternalServerErrorException.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/InternalServerErrorException.java new file mode 100644 index 0000000000..13e128237b --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/InternalServerErrorException.java @@ -0,0 +1,16 @@ +package com.baeldung.jhipster5.web.rest.errors; + +import org.zalando.problem.AbstractThrowableProblem; +import org.zalando.problem.Status; + +/** + * Simple exception with a message, that returns an Internal Server Error code. + */ +public class InternalServerErrorException extends AbstractThrowableProblem { + + private static final long serialVersionUID = 1L; + + public InternalServerErrorException(String message) { + super(ErrorConstants.DEFAULT_TYPE, message, Status.INTERNAL_SERVER_ERROR); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/InvalidPasswordException.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/InvalidPasswordException.java new file mode 100644 index 0000000000..6bb91247ff --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/InvalidPasswordException.java @@ -0,0 +1,13 @@ +package com.baeldung.jhipster5.web.rest.errors; + +import org.zalando.problem.AbstractThrowableProblem; +import org.zalando.problem.Status; + +public class InvalidPasswordException extends AbstractThrowableProblem { + + private static final long serialVersionUID = 1L; + + public InvalidPasswordException() { + super(ErrorConstants.INVALID_PASSWORD_TYPE, "Incorrect password", Status.BAD_REQUEST); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/LoginAlreadyUsedException.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/LoginAlreadyUsedException.java new file mode 100644 index 0000000000..987a94193d --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/LoginAlreadyUsedException.java @@ -0,0 +1,10 @@ +package com.baeldung.jhipster5.web.rest.errors; + +public class LoginAlreadyUsedException extends BadRequestAlertException { + + private static final long serialVersionUID = 1L; + + public LoginAlreadyUsedException() { + super(ErrorConstants.LOGIN_ALREADY_USED_TYPE, "Login name already used!", "userManagement", "userexists"); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/package-info.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/package-info.java new file mode 100644 index 0000000000..7f57af4429 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/package-info.java @@ -0,0 +1,6 @@ +/** + * Specific errors used with Zalando's "problem-spring-web" library. + * + * More information on https://github.com/zalando/problem-spring-web + */ +package com.baeldung.jhipster5.web.rest.errors; diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/package-info.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/package-info.java new file mode 100644 index 0000000000..75bf6840f6 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/package-info.java @@ -0,0 +1,4 @@ +/** + * Spring MVC REST controllers. + */ +package com.baeldung.jhipster5.web.rest; diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/util/HeaderUtil.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/util/HeaderUtil.java new file mode 100644 index 0000000000..91fdd68261 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/util/HeaderUtil.java @@ -0,0 +1,45 @@ +package com.baeldung.jhipster5.web.rest.util; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpHeaders; + +/** + * Utility class for HTTP headers creation. + */ +public final class HeaderUtil { + + private static final Logger log = LoggerFactory.getLogger(HeaderUtil.class); + + private static final String APPLICATION_NAME = "bookstoreApp"; + + private HeaderUtil() { + } + + public static HttpHeaders createAlert(String message, String param) { + HttpHeaders headers = new HttpHeaders(); + headers.add("X-" + APPLICATION_NAME + "-alert", message); + headers.add("X-" + APPLICATION_NAME + "-params", param); + return headers; + } + + public static HttpHeaders createEntityCreationAlert(String entityName, String param) { + return createAlert("A new " + entityName + " is created with identifier " + param, param); + } + + public static HttpHeaders createEntityUpdateAlert(String entityName, String param) { + return createAlert("A " + entityName + " is updated with identifier " + param, param); + } + + public static HttpHeaders createEntityDeletionAlert(String entityName, String param) { + return createAlert("A " + entityName + " is deleted with identifier " + param, param); + } + + public static HttpHeaders createFailureAlert(String entityName, String errorKey, String defaultMessage) { + log.error("Entity processing failed, {}", defaultMessage); + HttpHeaders headers = new HttpHeaders(); + headers.add("X-" + APPLICATION_NAME + "-error", defaultMessage); + headers.add("X-" + APPLICATION_NAME + "-params", entityName); + return headers; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/util/PaginationUtil.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/util/PaginationUtil.java new file mode 100644 index 0000000000..9928dbe171 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/util/PaginationUtil.java @@ -0,0 +1,45 @@ +package com.baeldung.jhipster5.web.rest.util; + +import org.springframework.data.domain.Page; +import org.springframework.http.HttpHeaders; +import org.springframework.web.util.UriComponentsBuilder; + +/** + * Utility class for handling pagination. + * + *

+ * Pagination uses the same principles as the GitHub API, + * and follow RFC 5988 (Link header). + */ +public final class PaginationUtil { + + private PaginationUtil() { + } + + public static HttpHeaders generatePaginationHttpHeaders(Page page, String baseUrl) { + + HttpHeaders headers = new HttpHeaders(); + headers.add("X-Total-Count", Long.toString(page.getTotalElements())); + String link = ""; + if ((page.getNumber() + 1) < page.getTotalPages()) { + link = "<" + generateUri(baseUrl, page.getNumber() + 1, page.getSize()) + ">; rel=\"next\","; + } + // prev link + if ((page.getNumber()) > 0) { + link += "<" + generateUri(baseUrl, page.getNumber() - 1, page.getSize()) + ">; rel=\"prev\","; + } + // last and first link + int lastPage = 0; + if (page.getTotalPages() > 0) { + lastPage = page.getTotalPages() - 1; + } + link += "<" + generateUri(baseUrl, lastPage, page.getSize()) + ">; rel=\"last\","; + link += "<" + generateUri(baseUrl, 0, page.getSize()) + ">; rel=\"first\""; + headers.add(HttpHeaders.LINK, link); + return headers; + } + + private static String generateUri(String baseUrl, int page, int size) { + return UriComponentsBuilder.fromUriString(baseUrl).queryParam("page", page).queryParam("size", size).toUriString(); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/vm/KeyAndPasswordVM.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/vm/KeyAndPasswordVM.java new file mode 100644 index 0000000000..840fa02cfc --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/vm/KeyAndPasswordVM.java @@ -0,0 +1,27 @@ +package com.baeldung.jhipster5.web.rest.vm; + +/** + * View Model object for storing the user's key and password. + */ +public class KeyAndPasswordVM { + + private String key; + + private String newPassword; + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public String getNewPassword() { + return newPassword; + } + + public void setNewPassword(String newPassword) { + this.newPassword = newPassword; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/vm/LoggerVM.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/vm/LoggerVM.java new file mode 100644 index 0000000000..952e7df298 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/vm/LoggerVM.java @@ -0,0 +1,46 @@ +package com.baeldung.jhipster5.web.rest.vm; + +import ch.qos.logback.classic.Logger; + +/** + * View Model object for storing a Logback logger. + */ +public class LoggerVM { + + private String name; + + private String level; + + public LoggerVM(Logger logger) { + this.name = logger.getName(); + this.level = logger.getEffectiveLevel().toString(); + } + + public LoggerVM() { + // Empty public constructor used by Jackson. + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getLevel() { + return level; + } + + public void setLevel(String level) { + this.level = level; + } + + @Override + public String toString() { + return "LoggerVM{" + + "name='" + name + '\'' + + ", level='" + level + '\'' + + '}'; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/vm/LoginVM.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/vm/LoginVM.java new file mode 100644 index 0000000000..8fc119ab69 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/vm/LoginVM.java @@ -0,0 +1,52 @@ +package com.baeldung.jhipster5.web.rest.vm; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +/** + * View Model object for storing a user's credentials. + */ +public class LoginVM { + + @NotNull + @Size(min = 1, max = 50) + private String username; + + @NotNull + @Size(min = ManagedUserVM.PASSWORD_MIN_LENGTH, max = ManagedUserVM.PASSWORD_MAX_LENGTH) + private String password; + + private Boolean rememberMe; + + 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; + } + + public Boolean isRememberMe() { + return rememberMe; + } + + public void setRememberMe(Boolean rememberMe) { + this.rememberMe = rememberMe; + } + + @Override + public String toString() { + return "LoginVM{" + + "username='" + username + '\'' + + ", rememberMe=" + rememberMe + + '}'; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/vm/ManagedUserVM.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/vm/ManagedUserVM.java new file mode 100644 index 0000000000..314577c456 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/vm/ManagedUserVM.java @@ -0,0 +1,35 @@ +package com.baeldung.jhipster5.web.rest.vm; + +import com.baeldung.jhipster5.service.dto.UserDTO; +import javax.validation.constraints.Size; + +/** + * View Model extending the UserDTO, which is meant to be used in the user management UI. + */ +public class ManagedUserVM extends UserDTO { + + public static final int PASSWORD_MIN_LENGTH = 4; + + public static final int PASSWORD_MAX_LENGTH = 100; + + @Size(min = PASSWORD_MIN_LENGTH, max = PASSWORD_MAX_LENGTH) + private String password; + + public ManagedUserVM() { + // Empty constructor needed for Jackson. + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + @Override + public String toString() { + return "ManagedUserVM{" + + "} " + super.toString(); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/vm/package-info.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/vm/package-info.java new file mode 100644 index 0000000000..ff58799037 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/vm/package-info.java @@ -0,0 +1,4 @@ +/** + * View Models used by Spring MVC REST controllers. + */ +package com.baeldung.jhipster5.web.rest.vm; diff --git a/jhipster-5/bookstore-monolith/src/main/jib/entrypoint.sh b/jhipster-5/bookstore-monolith/src/main/jib/entrypoint.sh new file mode 100644 index 0000000000..b3c4541011 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/jib/entrypoint.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +echo "The application will start in ${JHIPSTER_SLEEP}s..." && sleep ${JHIPSTER_SLEEP} +exec java ${JAVA_OPTS} -Djava.security.egd=file:/dev/./urandom -cp /app/resources/:/app/classes/:/app/libs/* "com.baeldung.jhipster5.BookstoreApp" "$@" diff --git a/jhipster-5/bookstore-monolith/src/main/resources/.h2.server.properties b/jhipster-5/bookstore-monolith/src/main/resources/.h2.server.properties new file mode 100644 index 0000000000..99767b3a8a --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/resources/.h2.server.properties @@ -0,0 +1,5 @@ +#H2 Server Properties +0=JHipster H2 (Memory)|org.h2.Driver|jdbc\:h2\:mem\:bookstore|Bookstore +webAllowOthers=true +webPort=8082 +webSSL=false diff --git a/jhipster-5/bookstore-monolith/src/main/resources/banner.txt b/jhipster-5/bookstore-monolith/src/main/resources/banner.txt new file mode 100644 index 0000000000..e0bc55aaff --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/resources/banner.txt @@ -0,0 +1,10 @@ + + ${AnsiColor.GREEN} ██╗${AnsiColor.RED} ██╗ ██╗ ████████╗ ███████╗ ██████╗ ████████╗ ████████╗ ███████╗ + ${AnsiColor.GREEN} ██║${AnsiColor.RED} ██║ ██║ ╚══██╔══╝ ██╔═══██╗ ██╔════╝ ╚══██╔══╝ ██╔═════╝ ██╔═══██╗ + ${AnsiColor.GREEN} ██║${AnsiColor.RED} ████████║ ██║ ███████╔╝ ╚█████╗ ██║ ██████╗ ███████╔╝ + ${AnsiColor.GREEN}██╗ ██║${AnsiColor.RED} ██╔═══██║ ██║ ██╔════╝ ╚═══██╗ ██║ ██╔═══╝ ██╔══██║ + ${AnsiColor.GREEN}╚██████╔╝${AnsiColor.RED} ██║ ██║ ████████╗ ██║ ██████╔╝ ██║ ████████╗ ██║ ╚██╗ + ${AnsiColor.GREEN} ╚═════╝ ${AnsiColor.RED} ╚═╝ ╚═╝ ╚═══════╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══════╝ ╚═╝ ╚═╝ + +${AnsiColor.BRIGHT_BLUE}:: JHipster 🤓 :: Running Spring Boot ${spring-boot.version} :: +:: https://www.jhipster.tech ::${AnsiColor.DEFAULT} diff --git a/jhipster-5/bookstore-monolith/src/main/resources/config/application-dev.yml b/jhipster-5/bookstore-monolith/src/main/resources/config/application-dev.yml new file mode 100644 index 0000000000..64742feb45 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/resources/config/application-dev.yml @@ -0,0 +1,122 @@ +# =================================================================== +# Spring Boot configuration for the "dev" profile. +# +# This configuration overrides the application.yml file. +# +# More information on profiles: https://www.jhipster.tech/profiles/ +# More information on configuration properties: https://www.jhipster.tech/common-application-properties/ +# =================================================================== + +# =================================================================== +# Standard Spring Boot properties. +# Full reference is available at: +# http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html +# =================================================================== + +logging: + level: + ROOT: DEBUG + io.github.jhipster: DEBUG + com.baeldung.jhipster5: DEBUG + +spring: + profiles: + active: dev + include: + - swagger + # Uncomment to activate TLS for the dev profile + #- tls + devtools: + restart: + enabled: true + additional-exclude: .h2.server.properties + livereload: + enabled: false # we use Webpack dev server + BrowserSync for livereload + jackson: + serialization: + indent-output: true + datasource: + type: com.zaxxer.hikari.HikariDataSource + url: jdbc:h2:mem:bookstore;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE + username: Bookstore + password: + hikari: + poolName: Hikari + auto-commit: false + h2: + console: + enabled: false + jpa: + database-platform: io.github.jhipster.domain.util.FixedH2Dialect + database: H2 + show-sql: true + properties: + hibernate.id.new_generator_mappings: true + hibernate.connection.provider_disables_autocommit: true + hibernate.cache.use_second_level_cache: false + hibernate.cache.use_query_cache: false + hibernate.generate_statistics: true + liquibase: + contexts: dev + mail: + host: localhost + port: 25 + username: + password: + messages: + cache-duration: PT1S # 1 second, see the ISO 8601 standard + thymeleaf: + cache: false + +server: + port: 8080 + +# =================================================================== +# JHipster specific properties +# +# Full reference is available at: https://www.jhipster.tech/common-application-properties/ +# =================================================================== + +jhipster: + http: + version: V_1_1 # To use HTTP/2 you will need to activate TLS (see application-tls.yml) + # CORS is only enabled by default with the "dev" profile, so BrowserSync can access the API + cors: + allowed-origins: "*" + allowed-methods: "*" + allowed-headers: "*" + exposed-headers: "Authorization,Link,X-Total-Count" + allow-credentials: true + max-age: 1800 + security: + authentication: + jwt: + # This token must be encoded using Base64 and be at least 256 bits long (you can type `openssl rand -base64 64` on your command line to generate a 512 bits one) + base64-secret: NDJmOTVlZjI2NzhlZDRjNmVkNTM1NDE2NjkyNDljZDJiNzBlMjI5YmZjMjY3MzdjZmZlMjI3NjE4OTRkNzc5MWYzNDNlYWMzYmJjOWRmMjc5ZWQyZTZmOWZkOTMxZWZhNWE1MTVmM2U2NjFmYjhlNDc2Y2Q3NzliMGY0YzFkNmI= + # Token is valid 24 hours + token-validity-in-seconds: 86400 + token-validity-in-seconds-for-remember-me: 2592000 + mail: # specific JHipster mail property, for standard properties see MailProperties + from: Bookstore@localhost + base-url: http://127.0.0.1:8080 + metrics: + logs: # Reports metrics in the logs + enabled: false + report-frequency: 60 # in seconds + logging: + logstash: # Forward logs to logstash over a socket, used by LoggingConfiguration + enabled: false + host: localhost + port: 5000 + queue-size: 512 + +# =================================================================== +# Application specific properties +# Add your own application properties here, see the ApplicationProperties class +# to have type-safe configuration, like in the JHipsterProperties above +# +# More documentation is available at: +# https://www.jhipster.tech/common-application-properties/ +# =================================================================== + +# application: diff --git a/jhipster-5/bookstore-monolith/src/main/resources/config/application-prod.yml b/jhipster-5/bookstore-monolith/src/main/resources/config/application-prod.yml new file mode 100644 index 0000000000..d698099fac --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/resources/config/application-prod.yml @@ -0,0 +1,133 @@ +# =================================================================== +# Spring Boot configuration for the "prod" profile. +# +# This configuration overrides the application.yml file. +# +# More information on profiles: https://www.jhipster.tech/profiles/ +# More information on configuration properties: https://www.jhipster.tech/common-application-properties/ +# =================================================================== + +# =================================================================== +# Standard Spring Boot properties. +# Full reference is available at: +# http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html +# =================================================================== + +logging: + level: + ROOT: INFO + com.baeldung.jhipster5: INFO + io.github.jhipster: INFO + +spring: + devtools: + restart: + enabled: false + livereload: + enabled: false + datasource: + type: com.zaxxer.hikari.HikariDataSource + url: jdbc:mysql://localhost:3306/Bookstore?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&serverTimezone=UTC + username: root + password: + hikari: + poolName: Hikari + auto-commit: false + data-source-properties: + cachePrepStmts: true + prepStmtCacheSize: 250 + prepStmtCacheSqlLimit: 2048 + useServerPrepStmts: true + jpa: + database-platform: org.hibernate.dialect.MySQL5InnoDBDialect + database: MYSQL + show-sql: false + properties: + hibernate.id.new_generator_mappings: true + hibernate.connection.provider_disables_autocommit: true + hibernate.cache.use_second_level_cache: false + hibernate.cache.use_query_cache: false + hibernate.generate_statistics: true + liquibase: + contexts: prod + mail: + host: localhost + port: 25 + username: + password: + thymeleaf: + cache: true + +# =================================================================== +# To enable TLS in production, generate a certificate using: +# keytool -genkey -alias bookstore -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore keystore.p12 -validity 3650 +# +# You can also use Let's Encrypt: +# https://maximilian-boehm.com/hp2121/Create-a-Java-Keystore-JKS-from-Let-s-Encrypt-Certificates.htm +# +# Then, modify the server.ssl properties so your "server" configuration looks like: +# +# server: +# port: 443 +# ssl: +# key-store: classpath:config/tls/keystore.p12 +# key-store-password: password +# key-store-type: PKCS12 +# key-alias: bookstore +# # The ciphers suite enforce the security by deactivating some old and deprecated SSL cipher, this list was tested against SSL Labs (https://www.ssllabs.com/ssltest/) +# ciphers: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 ,TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 ,TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 ,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,TLS_DHE_RSA_WITH_AES_128_CBC_SHA,TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,TLS_DHE_RSA_WITH_AES_256_CBC_SHA,TLS_RSA_WITH_AES_128_GCM_SHA256,TLS_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_256_CBC_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA,TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA,TLS_RSA_WITH_CAMELLIA_256_CBC_SHA,TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA,TLS_RSA_WITH_CAMELLIA_128_CBC_SHA +# =================================================================== +server: + port: 8080 + compression: + enabled: true + mime-types: text/html,text/xml,text/plain,text/css, application/javascript, application/json + min-response-size: 1024 + +# =================================================================== +# JHipster specific properties +# +# Full reference is available at: https://www.jhipster.tech/common-application-properties/ +# =================================================================== + +jhipster: + http: + version: V_1_1 # To use HTTP/2 you will need SSL support (see above the "server.ssl" configuration) + cache: # Used by the CachingHttpHeadersFilter + timeToLiveInDays: 1461 + security: + authentication: + jwt: + # This token must be encoded using Base64 and be at least 256 bits long (you can type `openssl rand -base64 64` on your command line to generate a 512 bits one) + # As this is the PRODUCTION configuration, you MUST change the default key, and store it securely: + # - In the JHipster Registry (which includes a Spring Cloud Config server) + # - In a separate `application-prod.yml` file, in the same folder as your executable WAR file + # - In the `JHIPSTER_SECURITY_AUTHENTICATION_JWT_BASE64_SECRET` environment variable + base64-secret: NDJmOTVlZjI2NzhlZDRjNmVkNTM1NDE2NjkyNDljZDJiNzBlMjI5YmZjMjY3MzdjZmZlMjI3NjE4OTRkNzc5MWYzNDNlYWMzYmJjOWRmMjc5ZWQyZTZmOWZkOTMxZWZhNWE1MTVmM2U2NjFmYjhlNDc2Y2Q3NzliMGY0YzFkNmI= + # Token is valid 24 hours + token-validity-in-seconds: 86400 + token-validity-in-seconds-for-remember-me: 2592000 + mail: # specific JHipster mail property, for standard properties see MailProperties + from: Bookstore@localhost + base-url: http://my-server-url-to-change # Modify according to your server's URL + metrics: + logs: # Reports metrics in the logs + enabled: false + report-frequency: 60 # in seconds + logging: + logstash: # Forward logs to logstash over a socket, used by LoggingConfiguration + enabled: false + host: localhost + port: 5000 + queue-size: 512 + +# =================================================================== +# Application specific properties +# Add your own application properties here, see the ApplicationProperties class +# to have type-safe configuration, like in the JHipsterProperties above +# +# More documentation is available at: +# https://www.jhipster.tech/common-application-properties/ +# =================================================================== + +# application: diff --git a/jhipster-5/bookstore-monolith/src/main/resources/config/application-tls.yml b/jhipster-5/bookstore-monolith/src/main/resources/config/application-tls.yml new file mode 100644 index 0000000000..c4e0565cc7 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/resources/config/application-tls.yml @@ -0,0 +1,20 @@ +# =================================================================== +# Activate this profile to enable TLS and HTTP/2. +# +# JHipster has generated a self-signed certificate, which will be used to encrypt traffic. +# As your browser will not understand this certificate, you will need to import it. +# +# Another (easiest) solution with Chrome is to enable the "allow-insecure-localhost" flag +# at chrome://flags/#allow-insecure-localhost +# =================================================================== +server: + ssl: + key-store: classpath:config/tls/keystore.p12 + key-store-password: password + key-store-type: PKCS12 + key-alias: selfsigned + ciphers: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 + enabled-protocols: TLSv1.2 +jhipster: + http: + version: V_2_0 diff --git a/jhipster-5/bookstore-monolith/src/main/resources/config/application.yml b/jhipster-5/bookstore-monolith/src/main/resources/config/application.yml new file mode 100644 index 0000000000..5b28b7f00d --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/resources/config/application.yml @@ -0,0 +1,140 @@ +# =================================================================== +# Spring Boot configuration. +# +# This configuration will be overridden by the Spring profile you use, +# for example application-dev.yml if you use the "dev" profile. +# +# More information on profiles: https://www.jhipster.tech/profiles/ +# More information on configuration properties: https://www.jhipster.tech/common-application-properties/ +# =================================================================== + +# =================================================================== +# Standard Spring Boot properties. +# Full reference is available at: +# http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html +# =================================================================== + +management: + endpoints: + web: + base-path: /management + exposure: + include: ["configprops", "env", "health", "info", "threaddump", "logfile", "jhi-metrics", "prometheus" ] + endpoint: + health: + show-details: when-authorized + jhi-metrics: + enabled: true + info: + git: + mode: full + health: + mail: + enabled: false # When using the MailService, configure an SMTP server and set this to true + metrics: + export: + # Prometheus is the default metrics backend + prometheus: + enabled: true + step: 60 + binders: + jvm: + enabled: true + processor: + enabled: true + uptime: + enabled: true + logback: + enabled: true + files: + enabled: true + integration: + enabled: true + distribution: + percentiles-histogram: + all: true + percentiles: + all: 0, 0.5, 0.75, 0.95, 0.99, 1.0 + web: + server: + auto-time-requests: true + +spring: + application: + name: Bookstore + profiles: + # The commented value for `active` can be replaced with valid Spring profiles to load. + # Otherwise, it will be filled in by maven when building the WAR file + # Either way, it can be overridden by `--spring.profiles.active` value passed in the commandline or `-Dspring.profiles.active` set in `JAVA_OPTS` + active: #spring.profiles.active# + jpa: + open-in-view: false + properties: + hibernate.jdbc.time_zone: UTC + hibernate: + ddl-auto: none + naming: + physical-strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy + implicit-strategy: org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy + messages: + basename: i18n/messages + mvc: + favicon: + enabled: false + thymeleaf: + mode: HTML + +server: + servlet: + session: + cookie: + http-only: true + +# Properties to be exposed on the /info management endpoint +info: + # Comma separated list of profiles that will trigger the ribbon to show + display-ribbon-on-profiles: "dev" + +# =================================================================== +# JHipster specific properties +# +# Full reference is available at: https://www.jhipster.tech/common-application-properties/ +# =================================================================== + +jhipster: + async: + core-pool-size: 2 + max-pool-size: 50 + queue-capacity: 10000 + # By default CORS is disabled. Uncomment to enable. + #cors: + #allowed-origins: "*" + #allowed-methods: "*" + #allowed-headers: "*" + #exposed-headers: "Authorization,Link,X-Total-Count" + #allow-credentials: true + #max-age: 1800 + mail: + from: Bookstore@localhost + swagger: + default-include-pattern: /api/.* + title: Bookstore API + description: Bookstore API documentation + version: 0.0.1 + terms-of-service-url: + contact-name: + contact-url: + contact-email: + license: + license-url: + +# =================================================================== +# Application specific properties +# Add your own application properties here, see the ApplicationProperties class +# to have type-safe configuration, like in the JHipsterProperties above +# +# More documentation is available at: +# https://www.jhipster.tech/common-application-properties/ +# =================================================================== + +# application: diff --git a/jhipster-5/bookstore-monolith/src/main/resources/config/liquibase/authorities.csv b/jhipster-5/bookstore-monolith/src/main/resources/config/liquibase/authorities.csv new file mode 100644 index 0000000000..af5c6dfa18 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/resources/config/liquibase/authorities.csv @@ -0,0 +1,3 @@ +name +ROLE_ADMIN +ROLE_USER diff --git a/jhipster-5/bookstore-monolith/src/main/resources/config/liquibase/changelog/00000000000000_initial_schema.xml b/jhipster-5/bookstore-monolith/src/main/resources/config/liquibase/changelog/00000000000000_initial_schema.xml new file mode 100644 index 0000000000..dd4b01d487 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/resources/config/liquibase/changelog/00000000000000_initial_schema.xml @@ -0,0 +1,152 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jhipster-5/bookstore-monolith/src/main/resources/config/liquibase/changelog/20190319124041_added_entity_Book.xml b/jhipster-5/bookstore-monolith/src/main/resources/config/liquibase/changelog/20190319124041_added_entity_Book.xml new file mode 100644 index 0000000000..f040387cf1 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/resources/config/liquibase/changelog/20190319124041_added_entity_Book.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jhipster-5/bookstore-monolith/src/main/resources/config/liquibase/master.xml b/jhipster-5/bookstore-monolith/src/main/resources/config/liquibase/master.xml new file mode 100644 index 0000000000..e045ee0100 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/resources/config/liquibase/master.xml @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/jhipster-5/bookstore-monolith/src/main/resources/config/liquibase/users.csv b/jhipster-5/bookstore-monolith/src/main/resources/config/liquibase/users.csv new file mode 100644 index 0000000000..b25922b699 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/resources/config/liquibase/users.csv @@ -0,0 +1,5 @@ +id;login;password_hash;first_name;last_name;email;image_url;activated;lang_key;created_by;last_modified_by +1;system;$2a$10$mE.qmcV0mFU5NcKh73TZx.z4ueI/.bDWbj0T1BYyqP481kGGarKLG;System;System;system@localhost;;true;en;system;system +2;anonymoususer;$2a$10$j8S5d7Sr7.8VTOYNviDPOeWX8KcYILUVJBsYV83Y5NtECayypx9lO;Anonymous;User;anonymous@localhost;;true;en;system;system +3;admin;$2a$10$gSAhZrxMllrbgj/kkK9UceBPpChGWJA7SYIb1Mqo.n5aNLq1/oRrC;Administrator;Administrator;admin@localhost;;true;en;system;system +4;user;$2a$10$VEjxo0jq2YG9Rbk2HmX9S.k1uZBGYUHdUcid3g/vfiEl7lwWgOH/K;User;User;user@localhost;;true;en;system;system diff --git a/jhipster-5/bookstore-monolith/src/main/resources/config/liquibase/users_authorities.csv b/jhipster-5/bookstore-monolith/src/main/resources/config/liquibase/users_authorities.csv new file mode 100644 index 0000000000..06c5feeeea --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/resources/config/liquibase/users_authorities.csv @@ -0,0 +1,6 @@ +user_id;authority_name +1;ROLE_ADMIN +1;ROLE_USER +3;ROLE_ADMIN +3;ROLE_USER +4;ROLE_USER diff --git a/jhipster-5/bookstore-monolith/src/main/resources/config/tls/keystore.p12 b/jhipster-5/bookstore-monolith/src/main/resources/config/tls/keystore.p12 new file mode 100644 index 0000000000..364fad7435 Binary files /dev/null and b/jhipster-5/bookstore-monolith/src/main/resources/config/tls/keystore.p12 differ diff --git a/jhipster-5/bookstore-monolith/src/main/resources/i18n/messages.properties b/jhipster-5/bookstore-monolith/src/main/resources/i18n/messages.properties new file mode 100644 index 0000000000..52a60093c5 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/resources/i18n/messages.properties @@ -0,0 +1,21 @@ +# Error page +error.title=Your request cannot be processed +error.subtitle=Sorry, an error has occurred. +error.status=Status: +error.message=Message: + +# Activation email +email.activation.title=Bookstore account activation +email.activation.greeting=Dear {0} +email.activation.text1=Your Bookstore account has been created, please click on the URL below to activate it: +email.activation.text2=Regards, +email.signature=Bookstore Team. + +# Creation email +email.creation.text1=Your Bookstore account has been created, please click on the URL below to access it: + +# Reset email +email.reset.title=Bookstore password reset +email.reset.greeting=Dear {0} +email.reset.text1=For your Bookstore account a password reset was requested, please click on the URL below to reset it: +email.reset.text2=Regards, diff --git a/jhipster-5/bookstore-monolith/src/main/resources/logback-spring.xml b/jhipster-5/bookstore-monolith/src/main/resources/logback-spring.xml new file mode 100644 index 0000000000..4aa548af35 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/resources/logback-spring.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + + + diff --git a/jhipster-5/bookstore-monolith/src/main/resources/templates/error.html b/jhipster-5/bookstore-monolith/src/main/resources/templates/error.html new file mode 100644 index 0000000000..08616bcf1e --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/resources/templates/error.html @@ -0,0 +1,163 @@ + + + + + + Your request cannot be processed + + + +

+

Your request cannot be processed :(

+ +

Sorry, an error has occurred.

+ + Status:  ()
+ + Message: 
+
+ + + +
+ + diff --git a/jhipster-5/bookstore-monolith/src/main/resources/templates/mail/activationEmail.html b/jhipster-5/bookstore-monolith/src/main/resources/templates/mail/activationEmail.html new file mode 100644 index 0000000000..cb021d8e6a --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/resources/templates/mail/activationEmail.html @@ -0,0 +1,25 @@ + + + + JHipster activation + + + + +

+ Dear +

+

+ Your JHipster account has been created, please click on the URL below to activate it: +

+

+ Activation link +

+

+ Regards, +
+ JHipster. +

+ + diff --git a/jhipster-5/bookstore-monolith/src/main/resources/templates/mail/creationEmail.html b/jhipster-5/bookstore-monolith/src/main/resources/templates/mail/creationEmail.html new file mode 100644 index 0000000000..dc0cff5883 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/resources/templates/mail/creationEmail.html @@ -0,0 +1,25 @@ + + + + JHipster creation + + + + +

+ Dear +

+

+ Your JHipster account has been created, please click on the URL below to access it: +

+

+ Login link +

+

+ Regards, +
+ JHipster. +

+ + diff --git a/jhipster-5/bookstore-monolith/src/main/resources/templates/mail/passwordResetEmail.html b/jhipster-5/bookstore-monolith/src/main/resources/templates/mail/passwordResetEmail.html new file mode 100644 index 0000000000..f44511265b --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/resources/templates/mail/passwordResetEmail.html @@ -0,0 +1,25 @@ + + + + JHipster password reset + + + + +

+ Dear +

+

+ For your JHipster account a password reset was requested, please click on the URL below to reset it: +

+

+ Login link +

+

+ Regards, +
+ JHipster. +

+ + diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/404.html b/jhipster-5/bookstore-monolith/src/main/webapp/404.html new file mode 100644 index 0000000000..3fdc0bee1a --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/404.html @@ -0,0 +1,61 @@ + + + + + Page Not Found + + + + + +

Page Not Found

+

Sorry, but the page you were trying to view does not exist.

+ + + diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/account.module.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/account.module.ts new file mode 100644 index 0000000000..a167cab1c2 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/account.module.ts @@ -0,0 +1,30 @@ +import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; +import { RouterModule } from '@angular/router'; + +import { BookstoreSharedModule } from 'app/shared'; + +import { + PasswordStrengthBarComponent, + RegisterComponent, + ActivateComponent, + PasswordComponent, + PasswordResetInitComponent, + PasswordResetFinishComponent, + SettingsComponent, + accountState +} from './'; + +@NgModule({ + imports: [BookstoreSharedModule, RouterModule.forChild(accountState)], + declarations: [ + ActivateComponent, + RegisterComponent, + PasswordComponent, + PasswordStrengthBarComponent, + PasswordResetInitComponent, + PasswordResetFinishComponent, + SettingsComponent + ], + schemas: [CUSTOM_ELEMENTS_SCHEMA] +}) +export class BookstoreAccountModule {} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/account.route.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/account.route.ts new file mode 100644 index 0000000000..f849342e69 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/account.route.ts @@ -0,0 +1,12 @@ +import { Routes } from '@angular/router'; + +import { activateRoute, passwordRoute, passwordResetFinishRoute, passwordResetInitRoute, registerRoute, settingsRoute } from './'; + +const ACCOUNT_ROUTES = [activateRoute, passwordRoute, passwordResetFinishRoute, passwordResetInitRoute, registerRoute, settingsRoute]; + +export const accountState: Routes = [ + { + path: '', + children: ACCOUNT_ROUTES + } +]; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/activate/activate.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/activate/activate.component.html new file mode 100644 index 0000000000..c7078ede86 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/activate/activate.component.html @@ -0,0 +1,17 @@ +
+
+
+

Activation

+ +
+ Your user account has been activated. Please + sign in. +
+ +
+ Your user could not be activated. Please use the registration form to sign up. +
+ +
+
+
diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/activate/activate.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/activate/activate.component.ts new file mode 100644 index 0000000000..5c398073c3 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/activate/activate.component.ts @@ -0,0 +1,37 @@ +import { Component, OnInit } from '@angular/core'; +import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { ActivatedRoute } from '@angular/router'; + +import { LoginModalService } from 'app/core'; +import { ActivateService } from './activate.service'; + +@Component({ + selector: 'jhi-activate', + templateUrl: './activate.component.html' +}) +export class ActivateComponent implements OnInit { + error: string; + success: string; + modalRef: NgbModalRef; + + constructor(private activateService: ActivateService, private loginModalService: LoginModalService, private route: ActivatedRoute) {} + + ngOnInit() { + this.route.queryParams.subscribe(params => { + this.activateService.get(params['key']).subscribe( + () => { + this.error = null; + this.success = 'OK'; + }, + () => { + this.success = null; + this.error = 'ERROR'; + } + ); + }); + } + + login() { + this.modalRef = this.loginModalService.open(); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/activate/activate.route.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/activate/activate.route.ts new file mode 100644 index 0000000000..b415b17a18 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/activate/activate.route.ts @@ -0,0 +1,12 @@ +import { Route } from '@angular/router'; + +import { ActivateComponent } from './activate.component'; + +export const activateRoute: Route = { + path: 'activate', + component: ActivateComponent, + data: { + authorities: [], + pageTitle: 'Activation' + } +}; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/activate/activate.service.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/activate/activate.service.ts new file mode 100644 index 0000000000..adade9efad --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/activate/activate.service.ts @@ -0,0 +1,16 @@ +import { Injectable } from '@angular/core'; +import { HttpClient, HttpParams } from '@angular/common/http'; +import { Observable } from 'rxjs'; + +import { SERVER_API_URL } from 'app/app.constants'; + +@Injectable({ providedIn: 'root' }) +export class ActivateService { + constructor(private http: HttpClient) {} + + get(key: string): Observable { + return this.http.get(SERVER_API_URL + 'api/activate', { + params: new HttpParams().set('key', key) + }); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/index.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/index.ts new file mode 100644 index 0000000000..aeada0551c --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/index.ts @@ -0,0 +1,19 @@ +export * from './activate/activate.component'; +export * from './activate/activate.service'; +export * from './activate/activate.route'; +export * from './password/password.component'; +export * from './password/password-strength-bar.component'; +export * from './password/password.service'; +export * from './password/password.route'; +export * from './password-reset/finish/password-reset-finish.component'; +export * from './password-reset/finish/password-reset-finish.service'; +export * from './password-reset/finish/password-reset-finish.route'; +export * from './password-reset/init/password-reset-init.component'; +export * from './password-reset/init/password-reset-init.service'; +export * from './password-reset/init/password-reset-init.route'; +export * from './register/register.component'; +export * from './register/register.service'; +export * from './register/register.route'; +export * from './settings/settings.component'; +export * from './settings/settings.route'; +export * from './account.route'; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password-reset/finish/password-reset-finish.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password-reset/finish/password-reset-finish.component.html new file mode 100644 index 0000000000..6d6baea694 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password-reset/finish/password-reset-finish.component.html @@ -0,0 +1,77 @@ +
+
+
+

Reset password

+ +
+ The password reset key is missing. +
+ +
+

Choose a new password

+
+ +
+

Your password couldn't be reset. Remember a password request is only valid for 24 hours.

+
+ +

+ Your password has been reset. Please + sign in. +

+ +
+ The password and its confirmation do not match! +
+ +
+
+
+ + +
+ + Your password is required. + + + Your password is required to be at least 4 characters. + + + Your password cannot be longer than 50 characters. + +
+ +
+ +
+ + +
+ + Your password confirmation is required. + + + Your password confirmation is required to be at least 4 characters. + + + Your password confirmation cannot be longer than 50 characters. + +
+
+ +
+
+ +
+
+
diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password-reset/finish/password-reset-finish.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password-reset/finish/password-reset-finish.component.ts new file mode 100644 index 0000000000..72aac25c96 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password-reset/finish/password-reset-finish.component.ts @@ -0,0 +1,65 @@ +import { Component, OnInit, AfterViewInit, Renderer, ElementRef } from '@angular/core'; +import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { ActivatedRoute } from '@angular/router'; + +import { LoginModalService } from 'app/core'; +import { PasswordResetFinishService } from './password-reset-finish.service'; + +@Component({ + selector: 'jhi-password-reset-finish', + templateUrl: './password-reset-finish.component.html' +}) +export class PasswordResetFinishComponent implements OnInit, AfterViewInit { + confirmPassword: string; + doNotMatch: string; + error: string; + keyMissing: boolean; + resetAccount: any; + success: string; + modalRef: NgbModalRef; + key: string; + + constructor( + private passwordResetFinishService: PasswordResetFinishService, + private loginModalService: LoginModalService, + private route: ActivatedRoute, + private elementRef: ElementRef, + private renderer: Renderer + ) {} + + ngOnInit() { + this.route.queryParams.subscribe(params => { + this.key = params['key']; + }); + this.resetAccount = {}; + this.keyMissing = !this.key; + } + + ngAfterViewInit() { + if (this.elementRef.nativeElement.querySelector('#password') != null) { + this.renderer.invokeElementMethod(this.elementRef.nativeElement.querySelector('#password'), 'focus', []); + } + } + + finishReset() { + this.doNotMatch = null; + this.error = null; + if (this.resetAccount.password !== this.confirmPassword) { + this.doNotMatch = 'ERROR'; + } else { + this.passwordResetFinishService.save({ key: this.key, newPassword: this.resetAccount.password }).subscribe( + () => { + this.success = 'OK'; + }, + () => { + this.success = null; + this.error = 'ERROR'; + } + ); + } + } + + login() { + this.modalRef = this.loginModalService.open(); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password-reset/finish/password-reset-finish.route.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password-reset/finish/password-reset-finish.route.ts new file mode 100644 index 0000000000..a09cba9377 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password-reset/finish/password-reset-finish.route.ts @@ -0,0 +1,12 @@ +import { Route } from '@angular/router'; + +import { PasswordResetFinishComponent } from './password-reset-finish.component'; + +export const passwordResetFinishRoute: Route = { + path: 'reset/finish', + component: PasswordResetFinishComponent, + data: { + authorities: [], + pageTitle: 'Password' + } +}; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password-reset/finish/password-reset-finish.service.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password-reset/finish/password-reset-finish.service.ts new file mode 100644 index 0000000000..706bdaa5b1 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password-reset/finish/password-reset-finish.service.ts @@ -0,0 +1,14 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Observable } from 'rxjs'; + +import { SERVER_API_URL } from 'app/app.constants'; + +@Injectable({ providedIn: 'root' }) +export class PasswordResetFinishService { + constructor(private http: HttpClient) {} + + save(keyAndPassword: any): Observable { + return this.http.post(SERVER_API_URL + 'api/account/reset-password/finish', keyAndPassword); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password-reset/init/password-reset-init.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password-reset/init/password-reset-init.component.html new file mode 100644 index 0000000000..7fe7b0bdec --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password-reset/init/password-reset-init.component.html @@ -0,0 +1,46 @@ +
+
+
+

Reset your password

+ +
+ Email address isn't registered! Please check and try again. +
+ +
+

Enter the email address you used to register.

+
+ +
+

Check your emails for details on how to reset your password.

+
+ +
+
+ + +
+ + Your email is required. + + + Your email is invalid. + + + Your email is required to be at least 5 characters. + + + Your email cannot be longer than 100 characters. + +
+
+ +
+
+
+
diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password-reset/init/password-reset-init.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password-reset/init/password-reset-init.component.ts new file mode 100644 index 0000000000..e32617341c --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password-reset/init/password-reset-init.component.ts @@ -0,0 +1,43 @@ +import { Component, OnInit, AfterViewInit, Renderer, ElementRef } from '@angular/core'; +import { EMAIL_NOT_FOUND_TYPE } from 'app/shared'; +import { PasswordResetInitService } from './password-reset-init.service'; + +@Component({ + selector: 'jhi-password-reset-init', + templateUrl: './password-reset-init.component.html' +}) +export class PasswordResetInitComponent implements OnInit, AfterViewInit { + error: string; + errorEmailNotExists: string; + resetAccount: any; + success: string; + + constructor(private passwordResetInitService: PasswordResetInitService, private elementRef: ElementRef, private renderer: Renderer) {} + + ngOnInit() { + this.resetAccount = {}; + } + + ngAfterViewInit() { + this.renderer.invokeElementMethod(this.elementRef.nativeElement.querySelector('#email'), 'focus', []); + } + + requestReset() { + this.error = null; + this.errorEmailNotExists = null; + + this.passwordResetInitService.save(this.resetAccount.email).subscribe( + () => { + this.success = 'OK'; + }, + response => { + this.success = null; + if (response.status === 400 && response.error.type === EMAIL_NOT_FOUND_TYPE) { + this.errorEmailNotExists = 'ERROR'; + } else { + this.error = 'ERROR'; + } + } + ); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password-reset/init/password-reset-init.route.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password-reset/init/password-reset-init.route.ts new file mode 100644 index 0000000000..a1708c98b3 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password-reset/init/password-reset-init.route.ts @@ -0,0 +1,12 @@ +import { Route } from '@angular/router'; + +import { PasswordResetInitComponent } from './password-reset-init.component'; + +export const passwordResetInitRoute: Route = { + path: 'reset/request', + component: PasswordResetInitComponent, + data: { + authorities: [], + pageTitle: 'Password' + } +}; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password-reset/init/password-reset-init.service.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password-reset/init/password-reset-init.service.ts new file mode 100644 index 0000000000..c24ccf94d2 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password-reset/init/password-reset-init.service.ts @@ -0,0 +1,14 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Observable } from 'rxjs'; + +import { SERVER_API_URL } from 'app/app.constants'; + +@Injectable({ providedIn: 'root' }) +export class PasswordResetInitService { + constructor(private http: HttpClient) {} + + save(mail: string): Observable { + return this.http.post(SERVER_API_URL + 'api/account/reset-password/init', mail); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password/password-strength-bar.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password/password-strength-bar.component.ts new file mode 100644 index 0000000000..4159fde882 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password/password-strength-bar.component.ts @@ -0,0 +1,85 @@ +import { Component, ElementRef, Input, Renderer } from '@angular/core'; + +@Component({ + selector: 'jhi-password-strength-bar', + template: ` +
+ Password strength: +
    +
  • +
  • +
  • +
  • +
  • +
+
+ `, + styleUrls: ['password-strength-bar.scss'] +}) +export class PasswordStrengthBarComponent { + colors = ['#F00', '#F90', '#FF0', '#9F0', '#0F0']; + + constructor(private renderer: Renderer, private elementRef: ElementRef) {} + + measureStrength(p: string): number { + let force = 0; + const regex = /[$-/:-?{-~!"^_`\[\]]/g; // " + const lowerLetters = /[a-z]+/.test(p); + const upperLetters = /[A-Z]+/.test(p); + const numbers = /[0-9]+/.test(p); + const symbols = regex.test(p); + + const flags = [lowerLetters, upperLetters, numbers, symbols]; + const passedMatches = flags.filter((isMatchedFlag: boolean) => { + return isMatchedFlag === true; + }).length; + + force += 2 * p.length + (p.length >= 10 ? 1 : 0); + force += passedMatches * 10; + + // penalty (short password) + force = p.length <= 6 ? Math.min(force, 10) : force; + + // penalty (poor variety of characters) + force = passedMatches === 1 ? Math.min(force, 10) : force; + force = passedMatches === 2 ? Math.min(force, 20) : force; + force = passedMatches === 3 ? Math.min(force, 40) : force; + + return force; + } + + getColor(s: number): any { + let idx = 0; + if (s <= 10) { + idx = 0; + } else if (s <= 20) { + idx = 1; + } else if (s <= 30) { + idx = 2; + } else if (s <= 40) { + idx = 3; + } else { + idx = 4; + } + return { idx: idx + 1, col: this.colors[idx] }; + } + + @Input() + set passwordToCheck(password: string) { + if (password) { + const c = this.getColor(this.measureStrength(password)); + const element = this.elementRef.nativeElement; + if (element.className) { + this.renderer.setElementClass(element, element.className, false); + } + const lis = element.getElementsByTagName('li'); + for (let i = 0; i < lis.length; i++) { + if (i < c.idx) { + this.renderer.setElementStyle(lis[i], 'backgroundColor', c.col); + } else { + this.renderer.setElementStyle(lis[i], 'backgroundColor', '#DDD'); + } + } + } + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password/password-strength-bar.scss b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password/password-strength-bar.scss new file mode 100644 index 0000000000..9744b9b784 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password/password-strength-bar.scss @@ -0,0 +1,23 @@ +/* ========================================================================== +start Password strength bar style +========================================================================== */ +ul#strength { + display: inline; + list-style: none; + margin: 0; + margin-left: 15px; + padding: 0; + vertical-align: 2px; +} + +.point { + background: #ddd; + border-radius: 2px; + display: inline-block; + height: 5px; + margin-right: 1px; + width: 20px; + &:last-child { + margin: 0 !important; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password/password.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password/password.component.html new file mode 100644 index 0000000000..79fb60c3bc --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password/password.component.html @@ -0,0 +1,77 @@ +
+
+
+

Password for [{{account.login}}]

+ +
+ Password changed! +
+
+ An error has occurred! The password could not be changed. +
+ +
+ The password and its confirmation do not match! +
+ +
+ +
+ + +
+ + Your password is required. + +
+
+
+ + +
+ + Your password is required. + + + Your password is required to be at least 4 characters. + + + Your password cannot be longer than 50 characters. + +
+ +
+
+ + +
+ + Your confirmation password is required. + + + Your confirmation password is required to be at least 4 characters. + + + Your confirmation password cannot be longer than 50 characters. + +
+
+ + +
+
+
+
diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password/password.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password/password.component.ts new file mode 100644 index 0000000000..3004effa57 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password/password.component.ts @@ -0,0 +1,46 @@ +import { Component, OnInit } from '@angular/core'; + +import { AccountService } from 'app/core'; +import { PasswordService } from './password.service'; + +@Component({ + selector: 'jhi-password', + templateUrl: './password.component.html' +}) +export class PasswordComponent implements OnInit { + doNotMatch: string; + error: string; + success: string; + account: any; + currentPassword: string; + newPassword: string; + confirmPassword: string; + + constructor(private passwordService: PasswordService, private accountService: AccountService) {} + + ngOnInit() { + this.accountService.identity().then(account => { + this.account = account; + }); + } + + changePassword() { + if (this.newPassword !== this.confirmPassword) { + this.error = null; + this.success = null; + this.doNotMatch = 'ERROR'; + } else { + this.doNotMatch = null; + this.passwordService.save(this.newPassword, this.currentPassword).subscribe( + () => { + this.error = null; + this.success = 'OK'; + }, + () => { + this.success = null; + this.error = 'ERROR'; + } + ); + } + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password/password.route.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password/password.route.ts new file mode 100644 index 0000000000..4bb115fd44 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password/password.route.ts @@ -0,0 +1,14 @@ +import { Route } from '@angular/router'; + +import { UserRouteAccessService } from 'app/core'; +import { PasswordComponent } from './password.component'; + +export const passwordRoute: Route = { + path: 'password', + component: PasswordComponent, + data: { + authorities: ['ROLE_USER'], + pageTitle: 'Password' + }, + canActivate: [UserRouteAccessService] +}; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password/password.service.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password/password.service.ts new file mode 100644 index 0000000000..028df7b0e4 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password/password.service.ts @@ -0,0 +1,14 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Observable } from 'rxjs'; + +import { SERVER_API_URL } from 'app/app.constants'; + +@Injectable({ providedIn: 'root' }) +export class PasswordService { + constructor(private http: HttpClient) {} + + save(newPassword: string, currentPassword: string): Observable { + return this.http.post(SERVER_API_URL + 'api/account/change-password', { currentPassword, newPassword }); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/register/register.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/register/register.component.html new file mode 100644 index 0000000000..596f782828 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/register/register.component.html @@ -0,0 +1,124 @@ +
+
+
+

Registration

+ +
+ Registration saved! Please check your email for confirmation. +
+ +
+ Registration failed! Please try again later. +
+ +
+ Login name already registered! Please choose another one. +
+ +
+ Email is already in use! Please choose another one. +
+ +
+ The password and its confirmation do not match! +
+
+
+
+
+
+
+ + +
+ + Your username is required. + + + Your username is required to be at least 1 character. + + + Your username cannot be longer than 50 characters. + + + Your username can only contain letters and digits. + +
+
+
+ + +
+ + Your email is required. + + + Your email is invalid. + + + Your email is required to be at least 5 characters. + + + Your email cannot be longer than 100 characters. + +
+
+
+ + +
+ + Your password is required. + + + Your password is required to be at least 4 characters. + + + Your password cannot be longer than 50 characters. + +
+ +
+
+ + +
+ + Your confirmation password is required. + + + Your confirmation password is required to be at least 4 characters. + + + Your confirmation password cannot be longer than 50 characters. + +
+
+ + +
+

+
+ If you want to + sign in, you can try the default accounts:
- Administrator (login="admin" and password="admin")
- User (login="user" and password="user").
+
+
+
+
diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/register/register.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/register/register.component.ts new file mode 100644 index 0000000000..85244d2970 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/register/register.component.ts @@ -0,0 +1,71 @@ +import { Component, OnInit, AfterViewInit, Renderer, ElementRef } from '@angular/core'; +import { HttpErrorResponse } from '@angular/common/http'; +import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; + +import { EMAIL_ALREADY_USED_TYPE, LOGIN_ALREADY_USED_TYPE } from 'app/shared'; +import { LoginModalService } from 'app/core'; +import { Register } from './register.service'; + +@Component({ + selector: 'jhi-register', + templateUrl: './register.component.html' +}) +export class RegisterComponent implements OnInit, AfterViewInit { + confirmPassword: string; + doNotMatch: string; + error: string; + errorEmailExists: string; + errorUserExists: string; + registerAccount: any; + success: boolean; + modalRef: NgbModalRef; + + constructor( + private loginModalService: LoginModalService, + private registerService: Register, + private elementRef: ElementRef, + private renderer: Renderer + ) {} + + ngOnInit() { + this.success = false; + this.registerAccount = {}; + } + + ngAfterViewInit() { + this.renderer.invokeElementMethod(this.elementRef.nativeElement.querySelector('#login'), 'focus', []); + } + + register() { + if (this.registerAccount.password !== this.confirmPassword) { + this.doNotMatch = 'ERROR'; + } else { + this.doNotMatch = null; + this.error = null; + this.errorUserExists = null; + this.errorEmailExists = null; + this.registerAccount.langKey = 'en'; + this.registerService.save(this.registerAccount).subscribe( + () => { + this.success = true; + }, + response => this.processError(response) + ); + } + } + + openLogin() { + this.modalRef = this.loginModalService.open(); + } + + private processError(response: HttpErrorResponse) { + this.success = null; + if (response.status === 400 && response.error.type === LOGIN_ALREADY_USED_TYPE) { + this.errorUserExists = 'ERROR'; + } else if (response.status === 400 && response.error.type === EMAIL_ALREADY_USED_TYPE) { + this.errorEmailExists = 'ERROR'; + } else { + this.error = 'ERROR'; + } + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/register/register.route.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/register/register.route.ts new file mode 100644 index 0000000000..626cd32ff9 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/register/register.route.ts @@ -0,0 +1,12 @@ +import { Route } from '@angular/router'; + +import { RegisterComponent } from './register.component'; + +export const registerRoute: Route = { + path: 'register', + component: RegisterComponent, + data: { + authorities: [], + pageTitle: 'Registration' + } +}; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/register/register.service.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/register/register.service.ts new file mode 100644 index 0000000000..dfe6f1da6a --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/register/register.service.ts @@ -0,0 +1,14 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Observable } from 'rxjs'; + +import { SERVER_API_URL } from 'app/app.constants'; + +@Injectable({ providedIn: 'root' }) +export class Register { + constructor(private http: HttpClient) {} + + save(account: any): Observable { + return this.http.post(SERVER_API_URL + 'api/register', account); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/settings/settings.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/settings/settings.component.html new file mode 100644 index 0000000000..bae1bb67e6 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/settings/settings.component.html @@ -0,0 +1,80 @@ +
+
+
+

User settings for [{{settingsAccount.login}}]

+ +
+ Settings saved! +
+ + + +
+ +
+ + +
+ + Your first name is required. + + + Your first name is required to be at least 1 character. + + + Your first name cannot be longer than 50 characters. + +
+
+
+ + +
+ + Your last name is required. + + + Your last name is required to be at least 1 character. + + + Your last name cannot be longer than 50 characters. + +
+
+
+ + +
+ + Your email is required. + + + Your email is invalid. + + + Your email is required to be at least 5 characters. + + + Your email cannot be longer than 100 characters. + +
+
+ +
+
+
+ +
diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/settings/settings.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/settings/settings.component.ts new file mode 100644 index 0000000000..92afaca793 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/settings/settings.component.ts @@ -0,0 +1,50 @@ +import { Component, OnInit } from '@angular/core'; + +import { AccountService } from 'app/core'; + +@Component({ + selector: 'jhi-settings', + templateUrl: './settings.component.html' +}) +export class SettingsComponent implements OnInit { + error: string; + success: string; + settingsAccount: any; + languages: any[]; + + constructor(private accountService: AccountService) {} + + ngOnInit() { + this.accountService.identity().then(account => { + this.settingsAccount = this.copyAccount(account); + }); + } + + save() { + this.accountService.save(this.settingsAccount).subscribe( + () => { + this.error = null; + this.success = 'OK'; + this.accountService.identity(true).then(account => { + this.settingsAccount = this.copyAccount(account); + }); + }, + () => { + this.success = null; + this.error = 'ERROR'; + } + ); + } + + copyAccount(account) { + return { + activated: account.activated, + email: account.email, + firstName: account.firstName, + langKey: account.langKey, + lastName: account.lastName, + login: account.login, + imageUrl: account.imageUrl + }; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/settings/settings.route.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/settings/settings.route.ts new file mode 100644 index 0000000000..3c9cf18e15 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/settings/settings.route.ts @@ -0,0 +1,14 @@ +import { Route } from '@angular/router'; + +import { UserRouteAccessService } from 'app/core'; +import { SettingsComponent } from './settings.component'; + +export const settingsRoute: Route = { + path: 'settings', + component: SettingsComponent, + data: { + authorities: ['ROLE_USER'], + pageTitle: 'Settings' + }, + canActivate: [UserRouteAccessService] +}; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/admin.module.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/admin.module.ts new file mode 100644 index 0000000000..4e46e0fe13 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/admin.module.ts @@ -0,0 +1,43 @@ +import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; +import { RouterModule } from '@angular/router'; +import { BookstoreSharedModule } from 'app/shared'; +/* jhipster-needle-add-admin-module-import - JHipster will add admin modules imports here */ + +import { + adminState, + AuditsComponent, + UserMgmtComponent, + UserMgmtDetailComponent, + UserMgmtUpdateComponent, + UserMgmtDeleteDialogComponent, + LogsComponent, + JhiMetricsMonitoringComponent, + JhiHealthModalComponent, + JhiHealthCheckComponent, + JhiConfigurationComponent, + JhiDocsComponent +} from './'; + +@NgModule({ + imports: [ + BookstoreSharedModule, + RouterModule.forChild(adminState) + /* jhipster-needle-add-admin-module - JHipster will add admin modules here */ + ], + declarations: [ + AuditsComponent, + UserMgmtComponent, + UserMgmtDetailComponent, + UserMgmtUpdateComponent, + UserMgmtDeleteDialogComponent, + LogsComponent, + JhiConfigurationComponent, + JhiHealthCheckComponent, + JhiHealthModalComponent, + JhiDocsComponent, + JhiMetricsMonitoringComponent + ], + entryComponents: [UserMgmtDeleteDialogComponent, JhiHealthModalComponent], + schemas: [CUSTOM_ELEMENTS_SCHEMA] +}) +export class BookstoreAdminModule {} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/admin.route.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/admin.route.ts new file mode 100644 index 0000000000..88c7e575f0 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/admin.route.ts @@ -0,0 +1,18 @@ +import { Routes } from '@angular/router'; + +import { auditsRoute, configurationRoute, docsRoute, healthRoute, logsRoute, metricsRoute, userMgmtRoute } from './'; + +import { UserRouteAccessService } from 'app/core'; + +const ADMIN_ROUTES = [auditsRoute, configurationRoute, docsRoute, healthRoute, logsRoute, ...userMgmtRoute, metricsRoute]; + +export const adminState: Routes = [ + { + path: '', + data: { + authorities: ['ROLE_ADMIN'] + }, + canActivate: [UserRouteAccessService], + children: ADMIN_ROUTES + } +]; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/audits/audit-data.model.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/audits/audit-data.model.ts new file mode 100644 index 0000000000..a2506c4090 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/audits/audit-data.model.ts @@ -0,0 +1,3 @@ +export class AuditData { + constructor(public remoteAddress: string, public sessionId: string) {} +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/audits/audit.model.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/audits/audit.model.ts new file mode 100644 index 0000000000..6497fb444e --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/audits/audit.model.ts @@ -0,0 +1,5 @@ +import { AuditData } from './audit-data.model'; + +export class Audit { + constructor(public data: AuditData, public principal: string, public timestamp: string, public type: string) {} +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/audits/audits.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/audits/audits.component.html new file mode 100644 index 0000000000..38af44044a --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/audits/audits.component.html @@ -0,0 +1,52 @@ +
+

Audits

+ +
+
+

Filter by date

+
+
+ from +
+ + +
+ To +
+ +
+
+
+ +
+ + + + + + + + + + + + + + + + + +
DateUserStateExtra data
{{audit.timestamp| date:'medium'}}{{audit.principal}}{{audit.type}} + {{audit.data.message}} + Remote Address {{audit.data.remoteAddress}} +
+
+
+
+ +
+
+ +
+
+
diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/audits/audits.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/audits/audits.component.ts new file mode 100644 index 0000000000..21739275f2 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/audits/audits.component.ts @@ -0,0 +1,126 @@ +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { HttpResponse } from '@angular/common/http'; +import { DatePipe } from '@angular/common'; +import { ActivatedRoute, Router } from '@angular/router'; +import { JhiParseLinks, JhiAlertService } from 'ng-jhipster'; + +import { ITEMS_PER_PAGE } from 'app/shared'; +import { Audit } from './audit.model'; +import { AuditsService } from './audits.service'; + +@Component({ + selector: 'jhi-audit', + templateUrl: './audits.component.html' +}) +export class AuditsComponent implements OnInit, OnDestroy { + audits: Audit[]; + fromDate: string; + itemsPerPage: any; + links: any; + page: number; + routeData: any; + predicate: any; + previousPage: any; + reverse: boolean; + toDate: string; + totalItems: number; + + constructor( + private auditsService: AuditsService, + private alertService: JhiAlertService, + private parseLinks: JhiParseLinks, + private activatedRoute: ActivatedRoute, + private datePipe: DatePipe, + private router: Router + ) { + this.itemsPerPage = ITEMS_PER_PAGE; + this.routeData = this.activatedRoute.data.subscribe(data => { + this.page = data['pagingParams'].page; + this.previousPage = data['pagingParams'].page; + this.reverse = data['pagingParams'].ascending; + this.predicate = data['pagingParams'].predicate; + }); + } + + ngOnInit() { + this.today(); + this.previousMonth(); + this.loadAll(); + } + + ngOnDestroy() { + this.routeData.unsubscribe(); + } + + previousMonth() { + const dateFormat = 'yyyy-MM-dd'; + let fromDate: Date = new Date(); + + if (fromDate.getMonth() === 0) { + fromDate = new Date(fromDate.getFullYear() - 1, 11, fromDate.getDate()); + } else { + fromDate = new Date(fromDate.getFullYear(), fromDate.getMonth() - 1, fromDate.getDate()); + } + + this.fromDate = this.datePipe.transform(fromDate, dateFormat); + } + + today() { + const dateFormat = 'yyyy-MM-dd'; + // Today + 1 day - needed if the current day must be included + const today: Date = new Date(); + today.setDate(today.getDate() + 1); + const date = new Date(today.getFullYear(), today.getMonth(), today.getDate()); + this.toDate = this.datePipe.transform(date, dateFormat); + } + + loadAll() { + this.auditsService + .query({ + page: this.page - 1, + size: this.itemsPerPage, + sort: this.sort(), + fromDate: this.fromDate, + toDate: this.toDate + }) + .subscribe( + (res: HttpResponse) => this.onSuccess(res.body, res.headers), + (res: HttpResponse) => this.onError(res.body) + ); + } + + sort() { + const result = [this.predicate + ',' + (this.reverse ? 'asc' : 'desc')]; + if (this.predicate !== 'id') { + result.push('id'); + } + return result; + } + + loadPage(page: number) { + if (page !== this.previousPage) { + this.previousPage = page; + this.transition(); + } + } + + transition() { + this.router.navigate(['/admin/audits'], { + queryParams: { + page: this.page, + sort: this.predicate + ',' + (this.reverse ? 'asc' : 'desc') + } + }); + this.loadAll(); + } + + private onSuccess(data, headers) { + this.links = this.parseLinks.parse(headers.get('link')); + this.totalItems = headers.get('X-Total-Count'); + this.audits = data; + } + + private onError(error) { + this.alertService.error(error.error, error.message, null); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/audits/audits.route.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/audits/audits.route.ts new file mode 100644 index 0000000000..87af5c6e8c --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/audits/audits.route.ts @@ -0,0 +1,17 @@ +import { Injectable } from '@angular/core'; +import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot, Route } from '@angular/router'; +import { JhiPaginationUtil, JhiResolvePagingParams } from 'ng-jhipster'; + +import { AuditsComponent } from './audits.component'; + +export const auditsRoute: Route = { + path: 'audits', + component: AuditsComponent, + resolve: { + pagingParams: JhiResolvePagingParams + }, + data: { + pageTitle: 'Audits', + defaultSort: 'auditEventDate,desc' + } +}; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/audits/audits.service.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/audits/audits.service.ts new file mode 100644 index 0000000000..78e8cca7e2 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/audits/audits.service.ts @@ -0,0 +1,25 @@ +import { Injectable } from '@angular/core'; +import { HttpClient, HttpParams, HttpResponse } from '@angular/common/http'; +import { Observable } from 'rxjs'; + +import { createRequestOption } from 'app/shared'; +import { SERVER_API_URL } from 'app/app.constants'; +import { Audit } from './audit.model'; + +@Injectable({ providedIn: 'root' }) +export class AuditsService { + constructor(private http: HttpClient) {} + + query(req: any): Observable> { + const params: HttpParams = createRequestOption(req); + params.set('fromDate', req.fromDate); + params.set('toDate', req.toDate); + + const requestURL = SERVER_API_URL + 'management/audits'; + + return this.http.get(requestURL, { + params, + observe: 'response' + }); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/configuration/configuration.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/configuration/configuration.component.html new file mode 100644 index 0000000000..02a4a96433 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/configuration/configuration.component.html @@ -0,0 +1,46 @@ +
+

Configuration

+ + Filter (by prefix) +

Spring configuration

+ + + + + + + + + + + + + +
PrefixProperties
{{entry.prefix}} +
+
{{key}}
+
+ {{entry.properties[key] | json}} +
+
+
+
+

{{key}}

+ + + + + + + + + + + + + +
PropertyValue
{{item.key}} + {{item.val}} +
+
+
diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/configuration/configuration.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/configuration/configuration.component.ts new file mode 100644 index 0000000000..6867210c91 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/configuration/configuration.component.ts @@ -0,0 +1,43 @@ +import { Component, OnInit } from '@angular/core'; + +import { JhiConfigurationService } from './configuration.service'; + +@Component({ + selector: 'jhi-configuration', + templateUrl: './configuration.component.html' +}) +export class JhiConfigurationComponent implements OnInit { + allConfiguration: any = null; + configuration: any = null; + configKeys: any[]; + filter: string; + orderProp: string; + reverse: boolean; + + constructor(private configurationService: JhiConfigurationService) { + this.configKeys = []; + this.filter = ''; + this.orderProp = 'prefix'; + this.reverse = false; + } + + keys(dict): Array { + return dict === undefined ? [] : Object.keys(dict); + } + + ngOnInit() { + this.configurationService.get().subscribe(configuration => { + this.configuration = configuration; + + for (const config of configuration) { + if (config.properties !== undefined) { + this.configKeys.push(Object.keys(config.properties)); + } + } + }); + + this.configurationService.getEnv().subscribe(configuration => { + this.allConfiguration = configuration; + }); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/configuration/configuration.route.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/configuration/configuration.route.ts new file mode 100644 index 0000000000..f4ad9c3688 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/configuration/configuration.route.ts @@ -0,0 +1,11 @@ +import { Route } from '@angular/router'; + +import { JhiConfigurationComponent } from './configuration.component'; + +export const configurationRoute: Route = { + path: 'jhi-configuration', + component: JhiConfigurationComponent, + data: { + pageTitle: 'Configuration' + } +}; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/configuration/configuration.service.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/configuration/configuration.service.ts new file mode 100644 index 0000000000..5f9dfd491c --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/configuration/configuration.service.ts @@ -0,0 +1,67 @@ +import { Injectable } from '@angular/core'; +import { HttpClient, HttpResponse } from '@angular/common/http'; +import { Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; + +import { SERVER_API_URL } from 'app/app.constants'; + +@Injectable({ providedIn: 'root' }) +export class JhiConfigurationService { + constructor(private http: HttpClient) {} + + get(): Observable { + return this.http.get(SERVER_API_URL + 'management/configprops', { observe: 'response' }).pipe( + map((res: HttpResponse) => { + const properties: any[] = []; + const propertiesObject = this.getConfigPropertiesObjects(res.body); + for (const key in propertiesObject) { + if (propertiesObject.hasOwnProperty(key)) { + properties.push(propertiesObject[key]); + } + } + + return properties.sort((propertyA, propertyB) => { + return propertyA.prefix === propertyB.prefix ? 0 : propertyA.prefix < propertyB.prefix ? -1 : 1; + }); + }) + ); + } + + getConfigPropertiesObjects(res: Object) { + // This code is for Spring Boot 2 + if (res['contexts'] !== undefined) { + for (const key in res['contexts']) { + // If the key is not bootstrap, it will be the ApplicationContext Id + // For default app, it is baseName + // For microservice, it is baseName-1 + if (!key.startsWith('bootstrap')) { + return res['contexts'][key]['beans']; + } + } + } + // by default, use the default ApplicationContext Id + return res['contexts']['Bookstore']['beans']; + } + + getEnv(): Observable { + return this.http.get(SERVER_API_URL + 'management/env', { observe: 'response' }).pipe( + map((res: HttpResponse) => { + const properties: any = {}; + const propertySources = res.body['propertySources']; + + for (const propertyObject of propertySources) { + const name = propertyObject['name']; + const detailProperties = propertyObject['properties']; + const vals: any[] = []; + for (const keyDetail in detailProperties) { + if (detailProperties.hasOwnProperty(keyDetail)) { + vals.push({ key: keyDetail, val: detailProperties[keyDetail]['value'] }); + } + } + properties[name] = vals; + } + return properties; + }) + ); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/docs/docs.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/docs/docs.component.html new file mode 100644 index 0000000000..30efbbb93e --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/docs/docs.component.html @@ -0,0 +1,2 @@ + diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/docs/docs.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/docs/docs.component.ts new file mode 100644 index 0000000000..b338e7c3a6 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/docs/docs.component.ts @@ -0,0 +1,9 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'jhi-docs', + templateUrl: './docs.component.html' +}) +export class JhiDocsComponent { + constructor() {} +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/docs/docs.route.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/docs/docs.route.ts new file mode 100644 index 0000000000..d7df51b935 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/docs/docs.route.ts @@ -0,0 +1,11 @@ +import { Route } from '@angular/router'; + +import { JhiDocsComponent } from './docs.component'; + +export const docsRoute: Route = { + path: 'docs', + component: JhiDocsComponent, + data: { + pageTitle: 'API' + } +}; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/health/health-modal.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/health/health-modal.component.html new file mode 100644 index 0000000000..efc125e3a0 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/health/health-modal.component.html @@ -0,0 +1,35 @@ + + + diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/health/health-modal.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/health/health-modal.component.ts new file mode 100644 index 0000000000..28128bf321 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/health/health-modal.component.ts @@ -0,0 +1,41 @@ +import { Component } from '@angular/core'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; + +import { JhiHealthService } from './health.service'; + +@Component({ + selector: 'jhi-health-modal', + templateUrl: './health-modal.component.html' +}) +export class JhiHealthModalComponent { + currentHealth: any; + + constructor(private healthService: JhiHealthService, public activeModal: NgbActiveModal) {} + + baseName(name) { + return this.healthService.getBaseName(name); + } + + subSystemName(name) { + return this.healthService.getSubSystemName(name); + } + + readableValue(value: number) { + if (this.currentHealth.name === 'diskSpace') { + // Should display storage space in an human readable unit + const val = value / 1073741824; + if (val > 1) { + // Value + return val.toFixed(2) + ' GB'; + } else { + return (value / 1048576).toFixed(2) + ' MB'; + } + } + + if (typeof value === 'object') { + return JSON.stringify(value); + } else { + return value.toString(); + } + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/health/health.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/health/health.component.html new file mode 100644 index 0000000000..b314daa0ba --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/health/health.component.html @@ -0,0 +1,34 @@ +
+

+ Health Checks + +

+
+ + + + + + + + + + + + + + + +
Service NameStatusDetails
{{ baseName(health.name) }} {{subSystemName(health.name)}} + + {{health.status}} + + + + + +
+
+
diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/health/health.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/health/health.component.ts new file mode 100644 index 0000000000..ada3ef62f4 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/health/health.component.ts @@ -0,0 +1,66 @@ +import { Component, OnInit } from '@angular/core'; +import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; + +import { JhiHealthService } from './health.service'; +import { JhiHealthModalComponent } from './health-modal.component'; + +@Component({ + selector: 'jhi-health', + templateUrl: './health.component.html' +}) +export class JhiHealthCheckComponent implements OnInit { + healthData: any; + updatingHealth: boolean; + + constructor(private modalService: NgbModal, private healthService: JhiHealthService) {} + + ngOnInit() { + this.refresh(); + } + + baseName(name: string) { + return this.healthService.getBaseName(name); + } + + getBadgeClass(statusState) { + if (statusState === 'UP') { + return 'badge-success'; + } else { + return 'badge-danger'; + } + } + + refresh() { + this.updatingHealth = true; + + this.healthService.checkHealth().subscribe( + health => { + this.healthData = this.healthService.transformHealthData(health); + this.updatingHealth = false; + }, + error => { + if (error.status === 503) { + this.healthData = this.healthService.transformHealthData(error.error); + this.updatingHealth = false; + } + } + ); + } + + showHealth(health: any) { + const modalRef = this.modalService.open(JhiHealthModalComponent); + modalRef.componentInstance.currentHealth = health; + modalRef.result.then( + result => { + // Left blank intentionally, nothing to do here + }, + reason => { + // Left blank intentionally, nothing to do here + } + ); + } + + subSystemName(name: string) { + return this.healthService.getSubSystemName(name); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/health/health.route.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/health/health.route.ts new file mode 100644 index 0000000000..0b67775651 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/health/health.route.ts @@ -0,0 +1,11 @@ +import { Route } from '@angular/router'; + +import { JhiHealthCheckComponent } from './health.component'; + +export const healthRoute: Route = { + path: 'jhi-health', + component: JhiHealthCheckComponent, + data: { + pageTitle: 'Health Checks' + } +}; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/health/health.service.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/health/health.service.ts new file mode 100644 index 0000000000..4c1b0e5ec8 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/health/health.service.ts @@ -0,0 +1,133 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Observable } from 'rxjs'; + +import { SERVER_API_URL } from 'app/app.constants'; + +@Injectable({ providedIn: 'root' }) +export class JhiHealthService { + separator: string; + + constructor(private http: HttpClient) { + this.separator = '.'; + } + + checkHealth(): Observable { + return this.http.get(SERVER_API_URL + 'management/health'); + } + + transformHealthData(data): any { + const response = []; + this.flattenHealthData(response, null, data.details); + return response; + } + + getBaseName(name): string { + if (name) { + const split = name.split('.'); + return split[0]; + } + } + + getSubSystemName(name): string { + if (name) { + const split = name.split('.'); + split.splice(0, 1); + const remainder = split.join('.'); + return remainder ? ' - ' + remainder : ''; + } + } + + /* private methods */ + private addHealthObject(result, isLeaf, healthObject, name): any { + const healthData: any = { + name + }; + + const details = {}; + let hasDetails = false; + + for (const key in healthObject) { + if (healthObject.hasOwnProperty(key)) { + const value = healthObject[key]; + if (key === 'status' || key === 'error') { + healthData[key] = value; + } else { + if (!this.isHealthObject(value)) { + details[key] = value; + hasDetails = true; + } + } + } + } + + // Add the details + if (hasDetails) { + healthData.details = details; + } + + // Only add nodes if they provide additional information + if (isLeaf || hasDetails || healthData.error) { + result.push(healthData); + } + return healthData; + } + + private flattenHealthData(result, path, data): any { + for (const key in data) { + if (data.hasOwnProperty(key)) { + const value = data[key]; + if (this.isHealthObject(value)) { + if (this.hasSubSystem(value)) { + this.addHealthObject(result, false, value, this.getModuleName(path, key)); + this.flattenHealthData(result, this.getModuleName(path, key), value); + } else { + this.addHealthObject(result, true, value, this.getModuleName(path, key)); + } + } + } + } + return result; + } + + private getModuleName(path, name): string { + let result; + if (path && name) { + result = path + this.separator + name; + } else if (path) { + result = path; + } else if (name) { + result = name; + } else { + result = ''; + } + return result; + } + + private hasSubSystem(healthObject): boolean { + let result = false; + + for (const key in healthObject) { + if (healthObject.hasOwnProperty(key)) { + const value = healthObject[key]; + if (value && value.status) { + result = true; + } + } + } + return result; + } + + private isHealthObject(healthObject): boolean { + let result = false; + + for (const key in healthObject) { + if (healthObject.hasOwnProperty(key)) { + if (key === 'status') { + result = true; + } + } + } + return result; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/index.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/index.ts new file mode 100644 index 0000000000..7f631ffb9b --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/index.ts @@ -0,0 +1,27 @@ +export * from './audits/audits.component'; +export * from './audits/audits.service'; +export * from './audits/audits.route'; +export * from './audits/audit.model'; +export * from './audits/audit-data.model'; +export * from './configuration/configuration.component'; +export * from './configuration/configuration.service'; +export * from './configuration/configuration.route'; +export * from './docs/docs.component'; +export * from './docs/docs.route'; +export * from './health/health.component'; +export * from './health/health-modal.component'; +export * from './health/health.service'; +export * from './health/health.route'; +export * from './logs/logs.component'; +export * from './logs/logs.service'; +export * from './logs/logs.route'; +export * from './logs/log.model'; +export * from './metrics/metrics.component'; +export * from './metrics/metrics.service'; +export * from './metrics/metrics.route'; +export * from './user-management/user-management-update.component'; +export * from './user-management/user-management-delete-dialog.component'; +export * from './user-management/user-management-detail.component'; +export * from './user-management/user-management.component'; +export * from './user-management/user-management.route'; +export * from './admin.route'; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/logs/log.model.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/logs/log.model.ts new file mode 100644 index 0000000000..3f27b6728c --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/logs/log.model.ts @@ -0,0 +1,3 @@ +export class Log { + constructor(public name: string, public level: string) {} +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/logs/logs.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/logs/logs.component.html new file mode 100644 index 0000000000..cf5d6a046f --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/logs/logs.component.html @@ -0,0 +1,28 @@ +
+

Logs

+ +

There are {{ loggers.length }} loggers.

+ + Filter + + + + + + + + + + + + + +
NameLevel
{{logger.name | slice:0:140}} + + + + + + +
+
diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/logs/logs.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/logs/logs.component.ts new file mode 100644 index 0000000000..28547f9ae6 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/logs/logs.component.ts @@ -0,0 +1,32 @@ +import { Component, OnInit } from '@angular/core'; + +import { Log } from './log.model'; +import { LogsService } from './logs.service'; + +@Component({ + selector: 'jhi-logs', + templateUrl: './logs.component.html' +}) +export class LogsComponent implements OnInit { + loggers: Log[]; + filter: string; + orderProp: string; + reverse: boolean; + + constructor(private logsService: LogsService) { + this.filter = ''; + this.orderProp = 'name'; + this.reverse = false; + } + + ngOnInit() { + this.logsService.findAll().subscribe(response => (this.loggers = response.body)); + } + + changeLevel(name: string, level: string) { + const log = new Log(name, level); + this.logsService.changeLevel(log).subscribe(() => { + this.logsService.findAll().subscribe(response => (this.loggers = response.body)); + }); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/logs/logs.route.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/logs/logs.route.ts new file mode 100644 index 0000000000..cfa87715d8 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/logs/logs.route.ts @@ -0,0 +1,11 @@ +import { Route } from '@angular/router'; + +import { LogsComponent } from './logs.component'; + +export const logsRoute: Route = { + path: 'logs', + component: LogsComponent, + data: { + pageTitle: 'Logs' + } +}; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/logs/logs.service.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/logs/logs.service.ts new file mode 100644 index 0000000000..71a596b0ab --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/logs/logs.service.ts @@ -0,0 +1,19 @@ +import { Injectable } from '@angular/core'; +import { HttpClient, HttpResponse } from '@angular/common/http'; +import { Observable } from 'rxjs'; + +import { SERVER_API_URL } from 'app/app.constants'; +import { Log } from './log.model'; + +@Injectable({ providedIn: 'root' }) +export class LogsService { + constructor(private http: HttpClient) {} + + changeLevel(log: Log): Observable> { + return this.http.put(SERVER_API_URL + 'management/logs', log, { observe: 'response' }); + } + + findAll(): Observable> { + return this.http.get(SERVER_API_URL + 'management/logs', { observe: 'response' }); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/metrics/metrics.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/metrics/metrics.component.html new file mode 100644 index 0000000000..75902d8fb3 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/metrics/metrics.component.html @@ -0,0 +1,56 @@ +
+

+ Application Metrics + +

+ +

JVM Metrics

+
+ + + + + +
+ +
+

Garbage collector statistics

+ +
+ +
Updating...
+ + + + +
+ + + + + + + + + +
diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/metrics/metrics.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/metrics/metrics.component.ts new file mode 100644 index 0000000000..ed508c8187 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/metrics/metrics.component.ts @@ -0,0 +1,42 @@ +import { Component, OnInit } from '@angular/core'; +import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; + +import { JhiMetricsService } from './metrics.service'; + +@Component({ + selector: 'jhi-metrics', + templateUrl: './metrics.component.html' +}) +export class JhiMetricsMonitoringComponent implements OnInit { + metrics: any = {}; + threadData: any = {}; + updatingMetrics = true; + JCACHE_KEY: string; + + constructor(private modalService: NgbModal, private metricsService: JhiMetricsService) { + this.JCACHE_KEY = 'jcache.statistics'; + } + + ngOnInit() { + this.refresh(); + } + + refresh() { + this.updatingMetrics = true; + this.metricsService.getMetrics().subscribe(metrics => { + this.metrics = metrics; + this.metricsService.threadDump().subscribe(data => { + this.threadData = data.threads; + this.updatingMetrics = false; + }); + }); + } + + isObjectExisting(metrics: any, key: string) { + return metrics && metrics[key]; + } + + isObjectExistingAndNotEmpty(metrics: any, key: string) { + return this.isObjectExisting(metrics, key) && JSON.stringify(metrics[key]) !== '{}'; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/metrics/metrics.route.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/metrics/metrics.route.ts new file mode 100644 index 0000000000..abc18b8254 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/metrics/metrics.route.ts @@ -0,0 +1,11 @@ +import { Route } from '@angular/router'; + +import { JhiMetricsMonitoringComponent } from './metrics.component'; + +export const metricsRoute: Route = { + path: 'jhi-metrics', + component: JhiMetricsMonitoringComponent, + data: { + pageTitle: 'Application Metrics' + } +}; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/metrics/metrics.service.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/metrics/metrics.service.ts new file mode 100644 index 0000000000..15cfe3536c --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/metrics/metrics.service.ts @@ -0,0 +1,18 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Observable } from 'rxjs'; + +import { SERVER_API_URL } from 'app/app.constants'; + +@Injectable({ providedIn: 'root' }) +export class JhiMetricsService { + constructor(private http: HttpClient) {} + + getMetrics(): Observable { + return this.http.get(SERVER_API_URL + 'management/jhi-metrics'); + } + + threadDump(): Observable { + return this.http.get(SERVER_API_URL + 'management/threaddump'); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management-delete-dialog.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management-delete-dialog.component.html new file mode 100644 index 0000000000..adb1a908da --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management-delete-dialog.component.html @@ -0,0 +1,19 @@ +
+ + + +
diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management-delete-dialog.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management-delete-dialog.component.ts new file mode 100644 index 0000000000..d7674f6cd9 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management-delete-dialog.component.ts @@ -0,0 +1,29 @@ +import { Component } from '@angular/core'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { JhiEventManager } from 'ng-jhipster'; + +import { User, UserService } from 'app/core'; + +@Component({ + selector: 'jhi-user-mgmt-delete-dialog', + templateUrl: './user-management-delete-dialog.component.html' +}) +export class UserMgmtDeleteDialogComponent { + user: User; + + constructor(private userService: UserService, public activeModal: NgbActiveModal, private eventManager: JhiEventManager) {} + + clear() { + this.activeModal.dismiss('cancel'); + } + + confirmDelete(login) { + this.userService.delete(login).subscribe(response => { + this.eventManager.broadcast({ + name: 'userListModification', + content: 'Deleted a user' + }); + this.activeModal.dismiss(true); + }); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management-detail.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management-detail.component.html new file mode 100644 index 0000000000..051f335ded --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management-detail.component.html @@ -0,0 +1,47 @@ +
+
+
+

+ User [{{user.login}}] +

+
+
Login
+
+ {{user.login}} + + +
+
First Name
+
{{user.firstName}}
+
Last Name
+
{{user.lastName}}
+
Email
+
{{user.email}}
+
Created By
+
{{user.createdBy}}
+
Created Date
+
{{user.createdDate | date:'dd/MM/yy HH:mm' }}
+
Last Modified By
+
{{user.lastModifiedBy}}
+
Last Modified Date
+
{{user.lastModifiedDate | date:'dd/MM/yy HH:mm'}}
+
Profiles
+
+
    +
  • + {{authority}} +
  • +
+
+
+ +
+
+
diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management-detail.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management-detail.component.ts new file mode 100644 index 0000000000..0b323d89a0 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management-detail.component.ts @@ -0,0 +1,20 @@ +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; + +import { User } from 'app/core'; + +@Component({ + selector: 'jhi-user-mgmt-detail', + templateUrl: './user-management-detail.component.html' +}) +export class UserMgmtDetailComponent implements OnInit { + user: User; + + constructor(private route: ActivatedRoute) {} + + ngOnInit() { + this.route.data.subscribe(({ user }) => { + this.user = user.body ? user.body : user; + }); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management-update.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management-update.component.html new file mode 100644 index 0000000000..b2d04b4227 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management-update.component.html @@ -0,0 +1,118 @@ +
+
+
+

+ Create or edit a User +

+
+ +
+ + +
+ +
+ + + +
+ + This field is required. + + + + This field cannot be longer than 50 characters. + + + + This field can only contain letters, digits and e-mail addresses. + +
+
+
+ + + +
+ + This field cannot be longer than 50 characters. + +
+
+
+ + + +
+ + This field cannot be longer than 50 characters. + +
+
+
+ + + +
+ + This field is required. + + + + This field cannot be longer than 100 characters. + + + + This field is required to be at least 5 characters. + + + + Your email is invalid. + +
+
+
+ +
+ +
+ + +
+
+
+ + +
+
+
+
diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management-update.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management-update.component.ts new file mode 100644 index 0000000000..e51e4f4a33 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management-update.component.ts @@ -0,0 +1,51 @@ +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; + +import { User, UserService } from 'app/core'; + +@Component({ + selector: 'jhi-user-mgmt-update', + templateUrl: './user-management-update.component.html' +}) +export class UserMgmtUpdateComponent implements OnInit { + user: User; + languages: any[]; + authorities: any[]; + isSaving: boolean; + + constructor(private userService: UserService, private route: ActivatedRoute, private router: Router) {} + + ngOnInit() { + this.isSaving = false; + this.route.data.subscribe(({ user }) => { + this.user = user.body ? user.body : user; + }); + this.authorities = []; + this.userService.authorities().subscribe(authorities => { + this.authorities = authorities; + }); + } + + previousState() { + window.history.back(); + } + + save() { + this.isSaving = true; + if (this.user.id !== null) { + this.userService.update(this.user).subscribe(response => this.onSaveSuccess(response), () => this.onSaveError()); + } else { + this.user.langKey = 'en'; + this.userService.create(this.user).subscribe(response => this.onSaveSuccess(response), () => this.onSaveError()); + } + } + + private onSaveSuccess(result) { + this.isSaving = false; + this.previousState(); + } + + private onSaveError() { + this.isSaving = false; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management.component.html new file mode 100644 index 0000000000..4592998c1f --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management.component.html @@ -0,0 +1,78 @@ +
+

+ Users + +

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ID Login Email ProfilesCreated Date Last Modified By Last Modified Date
{{user.id}}{{user.login}}{{user.email}} + + + +
+ {{ authority }} +
+
{{user.createdDate | date:'dd/MM/yy HH:mm'}}{{user.lastModifiedBy}}{{user.lastModifiedDate | date:'dd/MM/yy HH:mm'}} +
+ + + +
+
+
+
+
+ +
+
+ +
+
+
diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management.component.ts new file mode 100644 index 0000000000..439442e3b6 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management.component.ts @@ -0,0 +1,144 @@ +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { HttpResponse } from '@angular/common/http'; +import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; + +import { ActivatedRoute, Router } from '@angular/router'; +import { JhiEventManager, JhiParseLinks, JhiAlertService } from 'ng-jhipster'; + +import { ITEMS_PER_PAGE } from 'app/shared'; +import { AccountService, UserService, User } from 'app/core'; +import { UserMgmtDeleteDialogComponent } from 'app/admin'; + +@Component({ + selector: 'jhi-user-mgmt', + templateUrl: './user-management.component.html' +}) +export class UserMgmtComponent implements OnInit, OnDestroy { + currentAccount: any; + users: User[]; + error: any; + success: any; + routeData: any; + links: any; + totalItems: any; + itemsPerPage: any; + page: any; + predicate: any; + previousPage: any; + reverse: any; + + constructor( + private userService: UserService, + private alertService: JhiAlertService, + private accountService: AccountService, + private parseLinks: JhiParseLinks, + private activatedRoute: ActivatedRoute, + private router: Router, + private eventManager: JhiEventManager, + private modalService: NgbModal + ) { + this.itemsPerPage = ITEMS_PER_PAGE; + this.routeData = this.activatedRoute.data.subscribe(data => { + this.page = data['pagingParams'].page; + this.previousPage = data['pagingParams'].page; + this.reverse = data['pagingParams'].ascending; + this.predicate = data['pagingParams'].predicate; + }); + } + + ngOnInit() { + this.accountService.identity().then(account => { + this.currentAccount = account; + this.loadAll(); + this.registerChangeInUsers(); + }); + } + + ngOnDestroy() { + this.routeData.unsubscribe(); + } + + registerChangeInUsers() { + this.eventManager.subscribe('userListModification', response => this.loadAll()); + } + + setActive(user, isActivated) { + user.activated = isActivated; + + this.userService.update(user).subscribe(response => { + if (response.status === 200) { + this.error = null; + this.success = 'OK'; + this.loadAll(); + } else { + this.success = null; + this.error = 'ERROR'; + } + }); + } + + loadAll() { + this.userService + .query({ + page: this.page - 1, + size: this.itemsPerPage, + sort: this.sort() + }) + .subscribe( + (res: HttpResponse) => this.onSuccess(res.body, res.headers), + (res: HttpResponse) => this.onError(res.body) + ); + } + + trackIdentity(index, item: User) { + return item.id; + } + + sort() { + const result = [this.predicate + ',' + (this.reverse ? 'asc' : 'desc')]; + if (this.predicate !== 'id') { + result.push('id'); + } + return result; + } + + loadPage(page: number) { + if (page !== this.previousPage) { + this.previousPage = page; + this.transition(); + } + } + + transition() { + this.router.navigate(['/admin/user-management'], { + queryParams: { + page: this.page, + sort: this.predicate + ',' + (this.reverse ? 'asc' : 'desc') + } + }); + this.loadAll(); + } + + deleteUser(user: User) { + const modalRef = this.modalService.open(UserMgmtDeleteDialogComponent, { size: 'lg', backdrop: 'static' }); + modalRef.componentInstance.user = user; + modalRef.result.then( + result => { + // Left blank intentionally, nothing to do here + }, + reason => { + // Left blank intentionally, nothing to do here + } + ); + } + + private onSuccess(data, headers) { + this.links = this.parseLinks.parse(headers.get('link')); + this.totalItems = headers.get('X-Total-Count'); + this.users = data; + } + + private onError(error) { + this.alertService.error(error.error, error.message, null); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management.route.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management.route.ts new file mode 100644 index 0000000000..bf1115516f --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management.route.ts @@ -0,0 +1,68 @@ +import { Injectable } from '@angular/core'; +import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot, Routes, CanActivate } from '@angular/router'; +import { JhiPaginationUtil, JhiResolvePagingParams } from 'ng-jhipster'; + +import { AccountService, User, UserService } from 'app/core'; +import { UserMgmtComponent } from './user-management.component'; +import { UserMgmtDetailComponent } from './user-management-detail.component'; +import { UserMgmtUpdateComponent } from './user-management-update.component'; + +@Injectable({ providedIn: 'root' }) +export class UserResolve implements CanActivate { + constructor(private accountService: AccountService) {} + + canActivate() { + return this.accountService.identity().then(account => this.accountService.hasAnyAuthority(['ROLE_ADMIN'])); + } +} + +@Injectable({ providedIn: 'root' }) +export class UserMgmtResolve implements Resolve { + constructor(private service: UserService) {} + + resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { + const id = route.params['login'] ? route.params['login'] : null; + if (id) { + return this.service.find(id); + } + return new User(); + } +} + +export const userMgmtRoute: Routes = [ + { + path: 'user-management', + component: UserMgmtComponent, + resolve: { + pagingParams: JhiResolvePagingParams + }, + data: { + pageTitle: 'Users', + defaultSort: 'id,asc' + } + }, + { + path: 'user-management/:login/view', + component: UserMgmtDetailComponent, + resolve: { + user: UserMgmtResolve + }, + data: { + pageTitle: 'Users' + } + }, + { + path: 'user-management/new', + component: UserMgmtUpdateComponent, + resolve: { + user: UserMgmtResolve + } + }, + { + path: 'user-management/:login/edit', + component: UserMgmtUpdateComponent, + resolve: { + user: UserMgmtResolve + } + } +]; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/app-routing.module.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/app-routing.module.ts new file mode 100644 index 0000000000..c40d4df774 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/app-routing.module.ts @@ -0,0 +1,23 @@ +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; +import { errorRoute, navbarRoute } from './layouts'; +import { DEBUG_INFO_ENABLED } from 'app/app.constants'; + +const LAYOUT_ROUTES = [navbarRoute, ...errorRoute]; + +@NgModule({ + imports: [ + RouterModule.forRoot( + [ + { + path: 'admin', + loadChildren: './admin/admin.module#BookstoreAdminModule' + }, + ...LAYOUT_ROUTES + ], + { useHash: true, enableTracing: DEBUG_INFO_ENABLED } + ) + ], + exports: [RouterModule] +}) +export class BookstoreAppRoutingModule {} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/app.constants.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/app.constants.ts new file mode 100644 index 0000000000..9760a49a91 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/app.constants.ts @@ -0,0 +1,8 @@ +// These constants are injected via webpack environment variables. +// You can add more variables in webpack.common.js or in profile specific webpack..js files. +// If you change the values in the webpack config files, you need to re run webpack to update the application + +export const VERSION = process.env.VERSION; +export const DEBUG_INFO_ENABLED: boolean = !!process.env.DEBUG_INFO_ENABLED; +export const SERVER_API_URL = process.env.SERVER_API_URL; +export const BUILD_TIMESTAMP = process.env.BUILD_TIMESTAMP; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/app.main.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/app.main.ts new file mode 100644 index 0000000000..7695bb8571 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/app.main.ts @@ -0,0 +1,14 @@ +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { ProdConfig } from './blocks/config/prod.config'; +import { BookstoreAppModule } from './app.module'; + +ProdConfig(); + +if (module['hot']) { + module['hot'].accept(); +} + +platformBrowserDynamic() + .bootstrapModule(BookstoreAppModule, { preserveWhitespaces: true }) + .then(success => console.log(`Application started`)) + .catch(err => console.error(err)); diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/app.module.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/app.module.ts new file mode 100644 index 0000000000..5fb96ed8c5 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/app.module.ts @@ -0,0 +1,70 @@ +import './vendor.ts'; + +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { HTTP_INTERCEPTORS } from '@angular/common/http'; +import { NgbDatepickerConfig } from '@ng-bootstrap/ng-bootstrap'; +import { Ng2Webstorage } from 'ngx-webstorage'; +import { NgJhipsterModule } from 'ng-jhipster'; + +import { AuthInterceptor } from './blocks/interceptor/auth.interceptor'; +import { AuthExpiredInterceptor } from './blocks/interceptor/auth-expired.interceptor'; +import { ErrorHandlerInterceptor } from './blocks/interceptor/errorhandler.interceptor'; +import { NotificationInterceptor } from './blocks/interceptor/notification.interceptor'; +import { BookstoreSharedModule } from 'app/shared'; +import { BookstoreCoreModule } from 'app/core'; +import { BookstoreAppRoutingModule } from './app-routing.module'; +import { BookstoreHomeModule } from './home/home.module'; +import { BookstoreAccountModule } from './account/account.module'; +import { BookstoreEntityModule } from './entities/entity.module'; +import * as moment from 'moment'; +// jhipster-needle-angular-add-module-import JHipster will add new module here +import { JhiMainComponent, NavbarComponent, FooterComponent, PageRibbonComponent, ErrorComponent } from './layouts'; + +@NgModule({ + imports: [ + BrowserModule, + Ng2Webstorage.forRoot({ prefix: 'jhi', separator: '-' }), + NgJhipsterModule.forRoot({ + // set below to true to make alerts look like toast + alertAsToast: false, + alertTimeout: 5000 + }), + BookstoreSharedModule.forRoot(), + BookstoreCoreModule, + BookstoreHomeModule, + BookstoreAccountModule, + // jhipster-needle-angular-add-module JHipster will add new module here + BookstoreEntityModule, + BookstoreAppRoutingModule + ], + declarations: [JhiMainComponent, NavbarComponent, ErrorComponent, PageRibbonComponent, FooterComponent], + providers: [ + { + provide: HTTP_INTERCEPTORS, + useClass: AuthInterceptor, + multi: true + }, + { + provide: HTTP_INTERCEPTORS, + useClass: AuthExpiredInterceptor, + multi: true + }, + { + provide: HTTP_INTERCEPTORS, + useClass: ErrorHandlerInterceptor, + multi: true + }, + { + provide: HTTP_INTERCEPTORS, + useClass: NotificationInterceptor, + multi: true + } + ], + bootstrap: [JhiMainComponent] +}) +export class BookstoreAppModule { + constructor(private dpConfig: NgbDatepickerConfig) { + this.dpConfig.minDate = { year: moment().year() - 100, month: 1, day: 1 }; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/blocks/config/prod.config.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/blocks/config/prod.config.ts new file mode 100644 index 0000000000..c6221c1eaf --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/blocks/config/prod.config.ts @@ -0,0 +1,9 @@ +import { enableProdMode } from '@angular/core'; +import { DEBUG_INFO_ENABLED } from 'app/app.constants'; + +export function ProdConfig() { + // disable debug data on prod profile to improve performance + if (!DEBUG_INFO_ENABLED) { + enableProdMode(); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/blocks/config/uib-pagination.config.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/blocks/config/uib-pagination.config.ts new file mode 100644 index 0000000000..0c2ea94808 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/blocks/config/uib-pagination.config.ts @@ -0,0 +1,14 @@ +import { Injectable } from '@angular/core'; +import { NgbPaginationConfig } from '@ng-bootstrap/ng-bootstrap'; +import { ITEMS_PER_PAGE } from 'app/shared'; + +@Injectable({ providedIn: 'root' }) +export class PaginationConfig { + // tslint:disable-next-line: no-unused-variable + constructor(private config: NgbPaginationConfig) { + config.boundaryLinks = true; + config.maxSize = 5; + config.pageSize = ITEMS_PER_PAGE; + config.size = 'sm'; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/blocks/interceptor/auth-expired.interceptor.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/blocks/interceptor/auth-expired.interceptor.ts new file mode 100644 index 0000000000..bc1b70cfef --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/blocks/interceptor/auth-expired.interceptor.ts @@ -0,0 +1,25 @@ +import { Injectable } from '@angular/core'; +import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpErrorResponse } from '@angular/common/http'; +import { Observable } from 'rxjs'; +import { tap } from 'rxjs/operators'; +import { LoginService } from 'app/core/login/login.service'; + +@Injectable() +export class AuthExpiredInterceptor implements HttpInterceptor { + constructor(private loginService: LoginService) {} + + intercept(request: HttpRequest, next: HttpHandler): Observable> { + return next.handle(request).pipe( + tap( + (event: HttpEvent) => {}, + (err: any) => { + if (err instanceof HttpErrorResponse) { + if (err.status === 401) { + this.loginService.logout(); + } + } + } + ) + ); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/blocks/interceptor/auth.interceptor.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/blocks/interceptor/auth.interceptor.ts new file mode 100644 index 0000000000..23cdeaf66b --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/blocks/interceptor/auth.interceptor.ts @@ -0,0 +1,27 @@ +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; +import { LocalStorageService, SessionStorageService } from 'ngx-webstorage'; +import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http'; + +import { SERVER_API_URL } from 'app/app.constants'; + +@Injectable() +export class AuthInterceptor implements HttpInterceptor { + constructor(private localStorage: LocalStorageService, private sessionStorage: SessionStorageService) {} + + intercept(request: HttpRequest, next: HttpHandler): Observable> { + if (!request || !request.url || (/^http/.test(request.url) && !(SERVER_API_URL && request.url.startsWith(SERVER_API_URL)))) { + return next.handle(request); + } + + const token = this.localStorage.retrieve('authenticationToken') || this.sessionStorage.retrieve('authenticationToken'); + if (!!token) { + request = request.clone({ + setHeaders: { + Authorization: 'Bearer ' + token + } + }); + } + return next.handle(request); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/blocks/interceptor/errorhandler.interceptor.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/blocks/interceptor/errorhandler.interceptor.ts new file mode 100644 index 0000000000..e464f66cd3 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/blocks/interceptor/errorhandler.interceptor.ts @@ -0,0 +1,25 @@ +import { Injectable } from '@angular/core'; +import { JhiEventManager } from 'ng-jhipster'; +import { HttpInterceptor, HttpRequest, HttpErrorResponse, HttpHandler, HttpEvent } from '@angular/common/http'; +import { Observable } from 'rxjs'; +import { tap } from 'rxjs/operators'; + +@Injectable() +export class ErrorHandlerInterceptor implements HttpInterceptor { + constructor(private eventManager: JhiEventManager) {} + + intercept(request: HttpRequest, next: HttpHandler): Observable> { + return next.handle(request).pipe( + tap( + (event: HttpEvent) => {}, + (err: any) => { + if (err instanceof HttpErrorResponse) { + if (!(err.status === 401 && (err.message === '' || (err.url && err.url.includes('/api/account'))))) { + this.eventManager.broadcast({ name: 'bookstoreApp.httpError', content: err }); + } + } + } + ) + ); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/blocks/interceptor/notification.interceptor.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/blocks/interceptor/notification.interceptor.ts new file mode 100644 index 0000000000..34af81d482 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/blocks/interceptor/notification.interceptor.ts @@ -0,0 +1,34 @@ +import { JhiAlertService } from 'ng-jhipster'; +import { HttpInterceptor, HttpRequest, HttpResponse, HttpHandler, HttpEvent } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; +import { tap } from 'rxjs/operators'; + +@Injectable() +export class NotificationInterceptor implements HttpInterceptor { + constructor(private alertService: JhiAlertService) {} + + intercept(request: HttpRequest, next: HttpHandler): Observable> { + return next.handle(request).pipe( + tap( + (event: HttpEvent) => { + if (event instanceof HttpResponse) { + const arr = event.headers.keys(); + let alert = null; + arr.forEach(entry => { + if (entry.toLowerCase().endsWith('app-alert')) { + alert = event.headers.get(entry); + } + }); + if (alert) { + if (typeof alert === 'string') { + this.alertService.success(alert, null, null); + } + } + } + }, + (err: any) => {} + ) + ); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/core/auth/account.service.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/core/auth/account.service.ts new file mode 100644 index 0000000000..a6548f6dd9 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/core/auth/account.service.ts @@ -0,0 +1,108 @@ +import { Injectable } from '@angular/core'; +import { HttpClient, HttpResponse } from '@angular/common/http'; +import { Observable, Subject } from 'rxjs'; + +import { SERVER_API_URL } from 'app/app.constants'; +import { Account } from 'app/core/user/account.model'; + +@Injectable({ providedIn: 'root' }) +export class AccountService { + private userIdentity: any; + private authenticated = false; + private authenticationState = new Subject(); + + constructor(private http: HttpClient) {} + + fetch(): Observable> { + return this.http.get(SERVER_API_URL + 'api/account', { observe: 'response' }); + } + + save(account: any): Observable> { + return this.http.post(SERVER_API_URL + 'api/account', account, { observe: 'response' }); + } + + authenticate(identity) { + this.userIdentity = identity; + this.authenticated = identity !== null; + this.authenticationState.next(this.userIdentity); + } + + hasAnyAuthority(authorities: string[]): boolean { + if (!this.authenticated || !this.userIdentity || !this.userIdentity.authorities) { + return false; + } + + for (let i = 0; i < authorities.length; i++) { + if (this.userIdentity.authorities.includes(authorities[i])) { + return true; + } + } + + return false; + } + + hasAuthority(authority: string): Promise { + if (!this.authenticated) { + return Promise.resolve(false); + } + + return this.identity().then( + id => { + return Promise.resolve(id.authorities && id.authorities.includes(authority)); + }, + () => { + return Promise.resolve(false); + } + ); + } + + identity(force?: boolean): Promise { + if (force) { + this.userIdentity = undefined; + } + + // check and see if we have retrieved the userIdentity data from the server. + // if we have, reuse it by immediately resolving + if (this.userIdentity) { + return Promise.resolve(this.userIdentity); + } + + // retrieve the userIdentity data from the server, update the identity object, and then resolve. + return this.fetch() + .toPromise() + .then(response => { + const account = response.body; + if (account) { + this.userIdentity = account; + this.authenticated = true; + } else { + this.userIdentity = null; + this.authenticated = false; + } + this.authenticationState.next(this.userIdentity); + return this.userIdentity; + }) + .catch(err => { + this.userIdentity = null; + this.authenticated = false; + this.authenticationState.next(this.userIdentity); + return null; + }); + } + + isAuthenticated(): boolean { + return this.authenticated; + } + + isIdentityResolved(): boolean { + return this.userIdentity !== undefined; + } + + getAuthenticationState(): Observable { + return this.authenticationState.asObservable(); + } + + getImageUrl(): string { + return this.isIdentityResolved() ? this.userIdentity.imageUrl : null; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/core/auth/auth-jwt.service.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/core/auth/auth-jwt.service.ts new file mode 100644 index 0000000000..5ad53e3dfe --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/core/auth/auth-jwt.service.ts @@ -0,0 +1,59 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; +import { LocalStorageService, SessionStorageService } from 'ngx-webstorage'; + +import { SERVER_API_URL } from 'app/app.constants'; + +@Injectable({ providedIn: 'root' }) +export class AuthServerProvider { + constructor(private http: HttpClient, private $localStorage: LocalStorageService, private $sessionStorage: SessionStorageService) {} + + getToken() { + return this.$localStorage.retrieve('authenticationToken') || this.$sessionStorage.retrieve('authenticationToken'); + } + + login(credentials): Observable { + const data = { + username: credentials.username, + password: credentials.password, + rememberMe: credentials.rememberMe + }; + return this.http.post(SERVER_API_URL + 'api/authenticate', data, { observe: 'response' }).pipe(map(authenticateSuccess.bind(this))); + + function authenticateSuccess(resp) { + const bearerToken = resp.headers.get('Authorization'); + if (bearerToken && bearerToken.slice(0, 7) === 'Bearer ') { + const jwt = bearerToken.slice(7, bearerToken.length); + this.storeAuthenticationToken(jwt, credentials.rememberMe); + return jwt; + } + } + } + + loginWithToken(jwt, rememberMe) { + if (jwt) { + this.storeAuthenticationToken(jwt, rememberMe); + return Promise.resolve(jwt); + } else { + return Promise.reject('auth-jwt-service Promise reject'); // Put appropriate error message here + } + } + + storeAuthenticationToken(jwt, rememberMe) { + if (rememberMe) { + this.$localStorage.store('authenticationToken', jwt); + } else { + this.$sessionStorage.store('authenticationToken', jwt); + } + } + + logout(): Observable { + return new Observable(observer => { + this.$localStorage.clear('authenticationToken'); + this.$sessionStorage.clear('authenticationToken'); + observer.complete(); + }); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/core/auth/csrf.service.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/core/auth/csrf.service.ts new file mode 100644 index 0000000000..01fdccb02a --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/core/auth/csrf.service.ts @@ -0,0 +1,11 @@ +import { Injectable } from '@angular/core'; +import { CookieService } from 'ngx-cookie'; + +@Injectable({ providedIn: 'root' }) +export class CSRFService { + constructor(private cookieService: CookieService) {} + + getCSRF(name = 'XSRF-TOKEN') { + return this.cookieService.get(name); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/core/auth/state-storage.service.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/core/auth/state-storage.service.ts new file mode 100644 index 0000000000..0e5befbfc3 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/core/auth/state-storage.service.ts @@ -0,0 +1,46 @@ +import { Injectable } from '@angular/core'; +import { SessionStorageService } from 'ngx-webstorage'; + +@Injectable({ providedIn: 'root' }) +export class StateStorageService { + constructor(private $sessionStorage: SessionStorageService) {} + + getPreviousState() { + return this.$sessionStorage.retrieve('previousState'); + } + + resetPreviousState() { + this.$sessionStorage.clear('previousState'); + } + + storePreviousState(previousStateName, previousStateParams) { + const previousState = { name: previousStateName, params: previousStateParams }; + this.$sessionStorage.store('previousState', previousState); + } + + getDestinationState() { + return this.$sessionStorage.retrieve('destinationState'); + } + + storeUrl(url: string) { + this.$sessionStorage.store('previousUrl', url); + } + + getUrl() { + return this.$sessionStorage.retrieve('previousUrl'); + } + + storeDestinationState(destinationState, destinationStateParams, fromState) { + const destinationInfo = { + destination: { + name: destinationState.name, + data: destinationState.data + }, + params: destinationStateParams, + from: { + name: fromState.name + } + }; + this.$sessionStorage.store('destinationState', destinationInfo); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/core/auth/user-route-access-service.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/core/auth/user-route-access-service.ts new file mode 100644 index 0000000000..a55b0bc035 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/core/auth/user-route-access-service.ts @@ -0,0 +1,52 @@ +import { Injectable, isDevMode } from '@angular/core'; +import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router'; + +import { AccountService } from '../'; +import { LoginModalService } from '../login/login-modal.service'; +import { StateStorageService } from './state-storage.service'; + +@Injectable({ providedIn: 'root' }) +export class UserRouteAccessService implements CanActivate { + constructor( + private router: Router, + private loginModalService: LoginModalService, + private accountService: AccountService, + private stateStorageService: StateStorageService + ) {} + + canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean | Promise { + const authorities = route.data['authorities']; + // We need to call the checkLogin / and so the accountService.identity() function, to ensure, + // that the client has a principal too, if they already logged in by the server. + // This could happen on a page refresh. + return this.checkLogin(authorities, state.url); + } + + checkLogin(authorities: string[], url: string): Promise { + return this.accountService.identity().then(account => { + if (!authorities || authorities.length === 0) { + return true; + } + + if (account) { + const hasAnyAuthority = this.accountService.hasAnyAuthority(authorities); + if (hasAnyAuthority) { + return true; + } + if (isDevMode()) { + console.error('User has not any of required authorities: ', authorities); + } + return false; + } + + this.stateStorageService.storeUrl(url); + this.router.navigate(['accessdenied']).then(() => { + // only show the login dialog, if the user hasn't logged in yet + if (!account) { + this.loginModalService.open(); + } + }); + return false; + }); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/core/core.module.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/core/core.module.ts new file mode 100644 index 0000000000..7569b8f59e --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/core/core.module.ts @@ -0,0 +1,24 @@ +import { NgModule, LOCALE_ID } from '@angular/core'; +import { DatePipe, registerLocaleData } from '@angular/common'; +import { HttpClientModule } from '@angular/common/http'; +import { Title } from '@angular/platform-browser'; +import locale from '@angular/common/locales/en'; + +@NgModule({ + imports: [HttpClientModule], + exports: [], + declarations: [], + providers: [ + Title, + { + provide: LOCALE_ID, + useValue: 'en' + }, + DatePipe + ] +}) +export class BookstoreCoreModule { + constructor() { + registerLocaleData(locale); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/core/index.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/core/index.ts new file mode 100644 index 0000000000..38827443a5 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/core/index.ts @@ -0,0 +1,11 @@ +export * from './auth/csrf.service'; +export * from './auth/state-storage.service'; +export * from './auth/account.service'; +export * from './auth/auth-jwt.service'; +export * from './user/account.model'; +export * from './user/user.model'; +export * from './auth/user-route-access-service'; +export * from './login/login-modal.service'; +export * from './login/login.service'; +export * from './user/user.service'; +export * from './core.module'; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/core/login/login-modal.service.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/core/login/login-modal.service.ts new file mode 100644 index 0000000000..a0002aa56b --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/core/login/login-modal.service.ts @@ -0,0 +1,27 @@ +import { Injectable } from '@angular/core'; +import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; + +import { JhiLoginModalComponent } from 'app/shared/login/login.component'; + +@Injectable({ providedIn: 'root' }) +export class LoginModalService { + private isOpen = false; + constructor(private modalService: NgbModal) {} + + open(): NgbModalRef { + if (this.isOpen) { + return; + } + this.isOpen = true; + const modalRef = this.modalService.open(JhiLoginModalComponent); + modalRef.result.then( + result => { + this.isOpen = false; + }, + reason => { + this.isOpen = false; + } + ); + return modalRef; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/core/login/login.service.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/core/login/login.service.ts new file mode 100644 index 0000000000..e91508ff44 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/core/login/login.service.ts @@ -0,0 +1,38 @@ +import { Injectable } from '@angular/core'; + +import { AccountService } from 'app/core/auth/account.service'; +import { AuthServerProvider } from 'app/core/auth/auth-jwt.service'; + +@Injectable({ providedIn: 'root' }) +export class LoginService { + constructor(private accountService: AccountService, private authServerProvider: AuthServerProvider) {} + + login(credentials, callback?) { + const cb = callback || function() {}; + + return new Promise((resolve, reject) => { + this.authServerProvider.login(credentials).subscribe( + data => { + this.accountService.identity(true).then(account => { + resolve(data); + }); + return cb(); + }, + err => { + this.logout(); + reject(err); + return cb(err); + } + ); + }); + } + + loginWithToken(jwt, rememberMe) { + return this.authServerProvider.loginWithToken(jwt, rememberMe); + } + + logout() { + this.authServerProvider.logout().subscribe(); + this.accountService.authenticate(null); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/core/user/account.model.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/core/user/account.model.ts new file mode 100644 index 0000000000..35679657e3 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/core/user/account.model.ts @@ -0,0 +1,12 @@ +export class Account { + constructor( + public activated: boolean, + public authorities: string[], + public email: string, + public firstName: string, + public langKey: string, + public lastName: string, + public login: string, + public imageUrl: string + ) {} +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/core/user/user.model.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/core/user/user.model.ts new file mode 100644 index 0000000000..e82da11ac5 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/core/user/user.model.ts @@ -0,0 +1,47 @@ +export interface IUser { + id?: any; + login?: string; + firstName?: string; + lastName?: string; + email?: string; + activated?: boolean; + langKey?: string; + authorities?: any[]; + createdBy?: string; + createdDate?: Date; + lastModifiedBy?: string; + lastModifiedDate?: Date; + password?: string; +} + +export class User implements IUser { + constructor( + public id?: any, + public login?: string, + public firstName?: string, + public lastName?: string, + public email?: string, + public activated?: boolean, + public langKey?: string, + public authorities?: any[], + public createdBy?: string, + public createdDate?: Date, + public lastModifiedBy?: string, + public lastModifiedDate?: Date, + public password?: string + ) { + this.id = id ? id : null; + this.login = login ? login : null; + this.firstName = firstName ? firstName : null; + this.lastName = lastName ? lastName : null; + this.email = email ? email : null; + this.activated = activated ? activated : false; + this.langKey = langKey ? langKey : null; + this.authorities = authorities ? authorities : null; + this.createdBy = createdBy ? createdBy : null; + this.createdDate = createdDate ? createdDate : null; + this.lastModifiedBy = lastModifiedBy ? lastModifiedBy : null; + this.lastModifiedDate = lastModifiedDate ? lastModifiedDate : null; + this.password = password ? password : null; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/core/user/user.service.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/core/user/user.service.ts new file mode 100644 index 0000000000..5c8065bedd --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/core/user/user.service.ts @@ -0,0 +1,39 @@ +import { Injectable } from '@angular/core'; +import { HttpClient, HttpResponse } from '@angular/common/http'; +import { Observable } from 'rxjs'; + +import { SERVER_API_URL } from 'app/app.constants'; +import { createRequestOption } from 'app/shared/util/request-util'; +import { IUser } from './user.model'; + +@Injectable({ providedIn: 'root' }) +export class UserService { + public resourceUrl = SERVER_API_URL + 'api/users'; + + constructor(private http: HttpClient) {} + + create(user: IUser): Observable> { + return this.http.post(this.resourceUrl, user, { observe: 'response' }); + } + + update(user: IUser): Observable> { + return this.http.put(this.resourceUrl, user, { observe: 'response' }); + } + + find(login: string): Observable> { + return this.http.get(`${this.resourceUrl}/${login}`, { observe: 'response' }); + } + + query(req?: any): Observable> { + const options = createRequestOption(req); + return this.http.get(this.resourceUrl, { params: options, observe: 'response' }); + } + + delete(login: string): Observable> { + return this.http.delete(`${this.resourceUrl}/${login}`, { observe: 'response' }); + } + + authorities(): Observable { + return this.http.get(SERVER_API_URL + 'api/users/authorities'); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book-delete-dialog.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book-delete-dialog.component.html new file mode 100644 index 0000000000..be3647e9df --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book-delete-dialog.component.html @@ -0,0 +1,19 @@ +
+ + + +
diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book-delete-dialog.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book-delete-dialog.component.ts new file mode 100644 index 0000000000..7992a5d26d --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book-delete-dialog.component.ts @@ -0,0 +1,65 @@ +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; + +import { NgbActiveModal, NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { JhiEventManager } from 'ng-jhipster'; + +import { IBook } from 'app/shared/model/book.model'; +import { BookService } from './book.service'; + +@Component({ + selector: 'jhi-book-delete-dialog', + templateUrl: './book-delete-dialog.component.html' +}) +export class BookDeleteDialogComponent { + book: IBook; + + constructor(protected bookService: BookService, public activeModal: NgbActiveModal, protected eventManager: JhiEventManager) {} + + clear() { + this.activeModal.dismiss('cancel'); + } + + confirmDelete(id: number) { + this.bookService.delete(id).subscribe(response => { + this.eventManager.broadcast({ + name: 'bookListModification', + content: 'Deleted an book' + }); + this.activeModal.dismiss(true); + }); + } +} + +@Component({ + selector: 'jhi-book-delete-popup', + template: '' +}) +export class BookDeletePopupComponent implements OnInit, OnDestroy { + protected ngbModalRef: NgbModalRef; + + constructor(protected activatedRoute: ActivatedRoute, protected router: Router, protected modalService: NgbModal) {} + + ngOnInit() { + this.activatedRoute.data.subscribe(({ book }) => { + setTimeout(() => { + this.ngbModalRef = this.modalService.open(BookDeleteDialogComponent as Component, { size: 'lg', backdrop: 'static' }); + this.ngbModalRef.componentInstance.book = book; + this.ngbModalRef.result.then( + result => { + this.router.navigate(['/book', { outlets: { popup: null } }]); + this.ngbModalRef = null; + }, + reason => { + this.router.navigate(['/book', { outlets: { popup: null } }]); + this.ngbModalRef = null; + } + ); + }, 0); + }); + } + + ngOnDestroy() { + this.ngbModalRef = null; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book-detail.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book-detail.component.html new file mode 100644 index 0000000000..4a3c20e841 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book-detail.component.html @@ -0,0 +1,49 @@ +
+
+
+

Book {{book.id}}

+
+ +
+
Title
+
+ {{book.title}} +
+
Author
+
+ {{book.author}} +
+
Published
+
+ {{book.published}} +
+
Quantity
+
+ {{book.quantity}} +
+
Price
+
+ {{book.price}} +
+
+ + + + + + +
+
+
diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book-detail.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book-detail.component.ts new file mode 100644 index 0000000000..6b84c0ba73 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book-detail.component.ts @@ -0,0 +1,36 @@ +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; + +import { IBook } from 'app/shared/model/book.model'; +import { BookService } from 'app/entities/book/book.service'; +import { HttpErrorResponse, HttpResponse } from '@angular/common/http'; + +@Component({ + selector: 'jhi-book-detail', + templateUrl: './book-detail.component.html' +}) +export class BookDetailComponent implements OnInit { + book: IBook; + + constructor(protected activatedRoute: ActivatedRoute, protected bookService: BookService) {} + + ngOnInit() { + this.activatedRoute.data.subscribe(({ book }) => { + this.book = book; + }); + } + + previousState() { + window.history.back(); + } + + purchase(id: number) { + console.log('Purchasing book ' + id); + this.bookService.purchase(id).subscribe( + (res: HttpResponse) => { + this.book = res.body; + }, + (res: HttpErrorResponse) => console.log(res.message) + ); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book-update.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book-update.component.html new file mode 100644 index 0000000000..3b41c6e1e0 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book-update.component.html @@ -0,0 +1,100 @@ +
+
+
+

Create or edit a Book

+
+ +
+ + +
+
+ + +
+ + This field is required. + +
+
+
+ + +
+ + This field is required. + +
+
+
+ +
+ + + + +
+
+ + This field is required. + +
+
+
+ + +
+ + This field is required. + + + This field should be at least 0. + + + This field should be a number. + +
+
+
+ + +
+ + This field is required. + + + This field should be at least 0. + + + This field should be a number. + +
+
+ +
+
+ + +
+
+
+
diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book-update.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book-update.component.ts new file mode 100644 index 0000000000..67f46a67c2 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book-update.component.ts @@ -0,0 +1,53 @@ +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { HttpResponse, HttpErrorResponse } from '@angular/common/http'; +import { Observable } from 'rxjs'; +import { filter, map } from 'rxjs/operators'; +import * as moment from 'moment'; +import { IBook } from 'app/shared/model/book.model'; +import { BookService } from './book.service'; + +@Component({ + selector: 'jhi-book-update', + templateUrl: './book-update.component.html' +}) +export class BookUpdateComponent implements OnInit { + book: IBook; + isSaving: boolean; + publishedDp: any; + + constructor(protected bookService: BookService, protected activatedRoute: ActivatedRoute) {} + + ngOnInit() { + this.isSaving = false; + this.activatedRoute.data.subscribe(({ book }) => { + this.book = book; + }); + } + + previousState() { + window.history.back(); + } + + save() { + this.isSaving = true; + if (this.book.id !== undefined) { + this.subscribeToSaveResponse(this.bookService.update(this.book)); + } else { + this.subscribeToSaveResponse(this.bookService.create(this.book)); + } + } + + protected subscribeToSaveResponse(result: Observable>) { + result.subscribe((res: HttpResponse) => this.onSaveSuccess(), (res: HttpErrorResponse) => this.onSaveError()); + } + + protected onSaveSuccess() { + this.isSaving = false; + this.previousState(); + } + + protected onSaveError() { + this.isSaving = false; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book.component.html new file mode 100644 index 0000000000..74ad02a8e3 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book.component.html @@ -0,0 +1,62 @@ +
+

+ Books + +

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + +
IDTitleAuthorPublishedQuantityPrice
{{book.id}}{{book.title}}{{book.author}}{{book.published | date:'mediumDate'}}{{book.quantity}}{{book.price}} +
+ + + +
+
+
+
diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book.component.ts new file mode 100644 index 0000000000..91a71c2f5c --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book.component.ts @@ -0,0 +1,65 @@ +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { HttpErrorResponse, HttpResponse } from '@angular/common/http'; +import { Subscription } from 'rxjs'; +import { filter, map } from 'rxjs/operators'; +import { JhiEventManager, JhiAlertService } from 'ng-jhipster'; + +import { IBook } from 'app/shared/model/book.model'; +import { AccountService } from 'app/core'; +import { BookService } from './book.service'; + +@Component({ + selector: 'jhi-book', + templateUrl: './book.component.html' +}) +export class BookComponent implements OnInit, OnDestroy { + books: IBook[]; + currentAccount: any; + eventSubscriber: Subscription; + + constructor( + protected bookService: BookService, + protected jhiAlertService: JhiAlertService, + protected eventManager: JhiEventManager, + protected accountService: AccountService + ) {} + + loadAll() { + this.bookService + .query() + .pipe( + filter((res: HttpResponse) => res.ok), + map((res: HttpResponse) => res.body) + ) + .subscribe( + (res: IBook[]) => { + this.books = res; + }, + (res: HttpErrorResponse) => this.onError(res.message) + ); + } + + ngOnInit() { + this.loadAll(); + this.accountService.identity().then(account => { + this.currentAccount = account; + }); + this.registerChangeInBooks(); + } + + ngOnDestroy() { + this.eventManager.destroy(this.eventSubscriber); + } + + trackId(index: number, item: IBook) { + return item.id; + } + + registerChangeInBooks() { + this.eventSubscriber = this.eventManager.subscribe('bookListModification', response => this.loadAll()); + } + + protected onError(errorMessage: string) { + this.jhiAlertService.error(errorMessage, null, null); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book.module.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book.module.ts new file mode 100644 index 0000000000..fe221a0eb9 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book.module.ts @@ -0,0 +1,23 @@ +import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; +import { RouterModule } from '@angular/router'; + +import { BookstoreSharedModule } from 'app/shared'; +import { + BookComponent, + BookDetailComponent, + BookUpdateComponent, + BookDeletePopupComponent, + BookDeleteDialogComponent, + bookRoute, + bookPopupRoute +} from './'; + +const ENTITY_STATES = [...bookRoute, ...bookPopupRoute]; + +@NgModule({ + imports: [BookstoreSharedModule, RouterModule.forChild(ENTITY_STATES)], + declarations: [BookComponent, BookDetailComponent, BookUpdateComponent, BookDeleteDialogComponent, BookDeletePopupComponent], + entryComponents: [BookComponent, BookUpdateComponent, BookDeleteDialogComponent, BookDeletePopupComponent], + schemas: [CUSTOM_ELEMENTS_SCHEMA] +}) +export class BookstoreBookModule {} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book.route.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book.route.ts new file mode 100644 index 0000000000..154fa89a5c --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book.route.ts @@ -0,0 +1,93 @@ +import { Injectable } from '@angular/core'; +import { HttpResponse } from '@angular/common/http'; +import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot, Routes } from '@angular/router'; +import { UserRouteAccessService } from 'app/core'; +import { Observable, of } from 'rxjs'; +import { filter, map } from 'rxjs/operators'; +import { Book } from 'app/shared/model/book.model'; +import { BookService } from './book.service'; +import { BookComponent } from './book.component'; +import { BookDetailComponent } from './book-detail.component'; +import { BookUpdateComponent } from './book-update.component'; +import { BookDeletePopupComponent } from './book-delete-dialog.component'; +import { IBook } from 'app/shared/model/book.model'; + +@Injectable({ providedIn: 'root' }) +export class BookResolve implements Resolve { + constructor(private service: BookService) {} + + resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { + const id = route.params['id'] ? route.params['id'] : null; + if (id) { + return this.service.find(id).pipe( + filter((response: HttpResponse) => response.ok), + map((book: HttpResponse) => book.body) + ); + } + return of(new Book()); + } +} + +export const bookRoute: Routes = [ + { + path: '', + component: BookComponent, + data: { + authorities: ['ROLE_USER'], + pageTitle: 'Books' + }, + canActivate: [UserRouteAccessService] + }, + { + path: ':id/view', + component: BookDetailComponent, + resolve: { + book: BookResolve + }, + data: { + authorities: ['ROLE_USER'], + pageTitle: 'Books' + }, + canActivate: [UserRouteAccessService] + }, + { + path: 'new', + component: BookUpdateComponent, + resolve: { + book: BookResolve + }, + data: { + authorities: ['ROLE_USER'], + pageTitle: 'Books' + }, + canActivate: [UserRouteAccessService] + }, + { + path: ':id/edit', + component: BookUpdateComponent, + resolve: { + book: BookResolve + }, + data: { + authorities: ['ROLE_USER'], + pageTitle: 'Books' + }, + canActivate: [UserRouteAccessService] + } +]; + +export const bookPopupRoute: Routes = [ + { + path: ':id/delete', + component: BookDeletePopupComponent, + resolve: { + book: BookResolve + }, + data: { + authorities: ['ROLE_USER'], + pageTitle: 'Books' + }, + canActivate: [UserRouteAccessService], + outlet: 'popup' + } +]; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book.service.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book.service.ts new file mode 100644 index 0000000000..bff511f7e6 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book.service.ts @@ -0,0 +1,81 @@ +import { Injectable } from '@angular/core'; +import { HttpClient, HttpResponse } from '@angular/common/http'; +import { Observable } from 'rxjs'; +import * as moment from 'moment'; +import { DATE_FORMAT } from 'app/shared/constants/input.constants'; +import { map } from 'rxjs/operators'; + +import { SERVER_API_URL } from 'app/app.constants'; +import { createRequestOption } from 'app/shared'; +import { IBook } from 'app/shared/model/book.model'; + +type EntityResponseType = HttpResponse; +type EntityArrayResponseType = HttpResponse; + +@Injectable({ providedIn: 'root' }) +export class BookService { + public resourceUrl = SERVER_API_URL + 'api/books'; + + constructor(protected http: HttpClient) {} + + create(book: IBook): Observable { + const copy = this.convertDateFromClient(book); + return this.http + .post(this.resourceUrl, copy, { observe: 'response' }) + .pipe(map((res: EntityResponseType) => this.convertDateFromServer(res))); + } + + update(book: IBook): Observable { + const copy = this.convertDateFromClient(book); + return this.http + .put(this.resourceUrl, copy, { observe: 'response' }) + .pipe(map((res: EntityResponseType) => this.convertDateFromServer(res))); + } + + find(id: number): Observable { + return this.http + .get(`${this.resourceUrl}/${id}`, { observe: 'response' }) + .pipe(map((res: EntityResponseType) => this.convertDateFromServer(res))); + } + + purchase(id: number): Observable { + console.log('Calling /api/books/purchase/ ' + id); + return this.http + .get(`${this.resourceUrl}/purchase/${id}`, { observe: 'response' }) + .pipe(map((res: EntityResponseType) => this.convertDateFromServer(res))); + } + + query(req?: any): Observable { + const options = createRequestOption(req); + return this.http + .get(this.resourceUrl, { params: options, observe: 'response' }) + .pipe(map((res: EntityArrayResponseType) => this.convertDateArrayFromServer(res))); + } + + delete(id: number): Observable> { + return this.http.delete(`${this.resourceUrl}/${id}`, { observe: 'response' }); + } + + protected convertDateFromClient(book: IBook): IBook { + const copy: IBook = Object.assign({}, book, { + published: book.published != null && book.published.isValid() ? book.published.format(DATE_FORMAT) : null + }); + return copy; + } + + protected convertDateFromServer(res: EntityResponseType): EntityResponseType { + if (res.body) { + res.body.published = res.body.published != null ? moment(res.body.published) : null; + } + return res; + } + + protected convertDateArrayFromServer(res: EntityArrayResponseType): EntityArrayResponseType { + if (res.body) { + res.body.forEach((book: IBook) => { + book.published = book.published != null ? moment(book.published) : null; + }); + } + return res; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/index.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/index.ts new file mode 100644 index 0000000000..603cf68f9f --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/index.ts @@ -0,0 +1,6 @@ +export * from './book.service'; +export * from './book-update.component'; +export * from './book-delete-dialog.component'; +export * from './book-detail.component'; +export * from './book.component'; +export * from './book.route'; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/entity.module.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/entity.module.ts new file mode 100644 index 0000000000..fba1f55ef7 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/entity.module.ts @@ -0,0 +1,19 @@ +import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; +import { RouterModule } from '@angular/router'; + +@NgModule({ + imports: [ + RouterModule.forChild([ + { + path: 'book', + loadChildren: './book/book.module#BookstoreBookModule' + } + /* jhipster-needle-add-entity-route - JHipster will add entity modules routes here */ + ]) + ], + declarations: [], + entryComponents: [], + providers: [], + schemas: [CUSTOM_ELEMENTS_SCHEMA] +}) +export class BookstoreEntityModule {} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/home/home.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/home/home.component.html new file mode 100644 index 0000000000..0c595b9d74 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/home/home.component.html @@ -0,0 +1,41 @@ +
+
+ +
+
+

Welcome, Java Hipster!

+

This is your homepage

+ +
+
+ You are logged in as user "{{account.login}}". +
+ +
+ If you want to + sign in, you can try the default accounts:
- Administrator (login="admin" and password="admin")
- User (login="user" and password="user").
+
+
+ You don't have an account yet?  + Register a new account +
+
+ +

+ If you have any question on JHipster: +

+ + + +

+ If you like JHipster, don't forget to give us a star on GitHub! +

+
+
diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/home/home.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/home/home.component.ts new file mode 100644 index 0000000000..f1410c2cf5 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/home/home.component.ts @@ -0,0 +1,44 @@ +import { Component, OnInit } from '@angular/core'; +import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { JhiEventManager } from 'ng-jhipster'; + +import { LoginModalService, AccountService, Account } from 'app/core'; + +@Component({ + selector: 'jhi-home', + templateUrl: './home.component.html', + styleUrls: ['home.scss'] +}) +export class HomeComponent implements OnInit { + account: Account; + modalRef: NgbModalRef; + + constructor( + private accountService: AccountService, + private loginModalService: LoginModalService, + private eventManager: JhiEventManager + ) {} + + ngOnInit() { + this.accountService.identity().then((account: Account) => { + this.account = account; + }); + this.registerAuthenticationSuccess(); + } + + registerAuthenticationSuccess() { + this.eventManager.subscribe('authenticationSuccess', message => { + this.accountService.identity().then(account => { + this.account = account; + }); + }); + } + + isAuthenticated() { + return this.accountService.isAuthenticated(); + } + + login() { + this.modalRef = this.loginModalService.open(); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/home/home.module.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/home/home.module.ts new file mode 100644 index 0000000000..c1004a6dd9 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/home/home.module.ts @@ -0,0 +1,12 @@ +import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; +import { RouterModule } from '@angular/router'; + +import { BookstoreSharedModule } from 'app/shared'; +import { HOME_ROUTE, HomeComponent } from './'; + +@NgModule({ + imports: [BookstoreSharedModule, RouterModule.forChild([HOME_ROUTE])], + declarations: [HomeComponent], + schemas: [CUSTOM_ELEMENTS_SCHEMA] +}) +export class BookstoreHomeModule {} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/home/home.route.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/home/home.route.ts new file mode 100644 index 0000000000..a59993f8f0 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/home/home.route.ts @@ -0,0 +1,12 @@ +import { Route } from '@angular/router'; + +import { HomeComponent } from './'; + +export const HOME_ROUTE: Route = { + path: '', + component: HomeComponent, + data: { + authorities: [], + pageTitle: 'Welcome, Java Hipster!' + } +}; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/home/home.scss b/jhipster-5/bookstore-monolith/src/main/webapp/app/home/home.scss new file mode 100644 index 0000000000..7fe48ff5fa --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/home/home.scss @@ -0,0 +1,23 @@ +/* ========================================================================== +Main page styles +========================================================================== */ + +.hipster { + display: inline-block; + width: 347px; + height: 497px; + background: url('../../content/images/jhipster_family_member_0.svg') no-repeat center top; + background-size: contain; +} + +/* wait autoprefixer update to allow simple generation of high pixel density media query */ +@media only screen and (-webkit-min-device-pixel-ratio: 2), + only screen and (-moz-min-device-pixel-ratio: 2), + only screen and (-o-min-device-pixel-ratio: 2/1), + only screen and (min-resolution: 192dpi), + only screen and (min-resolution: 2dppx) { + .hipster { + background: url('../../content/images/jhipster_family_member_0.svg') no-repeat center top; + background-size: contain; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/home/index.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/home/index.ts new file mode 100644 index 0000000000..d76285b277 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/home/index.ts @@ -0,0 +1,3 @@ +export * from './home.component'; +export * from './home.route'; +export * from './home.module'; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/error/error.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/error/error.component.html new file mode 100644 index 0000000000..b79392173e --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/error/error.component.html @@ -0,0 +1,19 @@ +
+
+
+ +
+
+

Error Page!

+ +
+
{{errorMessage}} +
+
+
You are not authorized to access this page. +
+
The page asked was not found. +
+
+
+
diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/error/error.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/error/error.component.ts new file mode 100644 index 0000000000..faa9658161 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/error/error.component.ts @@ -0,0 +1,28 @@ +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; + +@Component({ + selector: 'jhi-error', + templateUrl: './error.component.html' +}) +export class ErrorComponent implements OnInit { + errorMessage: string; + error403: boolean; + error404: boolean; + + constructor(private route: ActivatedRoute) {} + + ngOnInit() { + this.route.data.subscribe(routeData => { + if (routeData.error403) { + this.error403 = routeData.error403; + } + if (routeData.error404) { + this.error404 = routeData.error404; + } + if (routeData.errorMessage) { + this.errorMessage = routeData.errorMessage; + } + }); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/error/error.route.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/error/error.route.ts new file mode 100644 index 0000000000..85ab257ca9 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/error/error.route.ts @@ -0,0 +1,36 @@ +import { Routes } from '@angular/router'; + +import { ErrorComponent } from './error.component'; + +export const errorRoute: Routes = [ + { + path: 'error', + component: ErrorComponent, + data: { + authorities: [], + pageTitle: 'Bookstore' + } + }, + { + path: 'accessdenied', + component: ErrorComponent, + data: { + authorities: [], + pageTitle: 'Bookstore', + error403: true + } + }, + { + path: '404', + component: ErrorComponent, + data: { + authorities: [], + pageTitle: 'Bookstore', + error404: true + } + }, + { + path: '**', + redirectTo: '/404' + } +]; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/footer/footer.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/footer/footer.component.html new file mode 100644 index 0000000000..b3ba632e02 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/footer/footer.component.html @@ -0,0 +1,3 @@ + diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/footer/footer.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/footer/footer.component.ts new file mode 100644 index 0000000000..37da8bca75 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/footer/footer.component.ts @@ -0,0 +1,7 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'jhi-footer', + templateUrl: './footer.component.html' +}) +export class FooterComponent {} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/index.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/index.ts new file mode 100644 index 0000000000..8cbf6368d7 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/index.ts @@ -0,0 +1,9 @@ +export * from './error/error.component'; +export * from './error/error.route'; +export * from './main/main.component'; +export * from './footer/footer.component'; +export * from './navbar/navbar.component'; +export * from './navbar/navbar.route'; +export * from './profiles/page-ribbon.component'; +export * from './profiles/profile.service'; +export * from './profiles/profile-info.model'; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/main/main.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/main/main.component.html new file mode 100644 index 0000000000..5bcd12ab0b --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/main/main.component.html @@ -0,0 +1,11 @@ + +
+ +
+
+
+ + +
+ +
diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/main/main.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/main/main.component.ts new file mode 100644 index 0000000000..e1f2c8134e --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/main/main.component.ts @@ -0,0 +1,31 @@ +import { Component, OnInit } from '@angular/core'; +import { Router, ActivatedRouteSnapshot, NavigationEnd, NavigationError } from '@angular/router'; + +import { Title } from '@angular/platform-browser'; + +@Component({ + selector: 'jhi-main', + templateUrl: './main.component.html' +}) +export class JhiMainComponent implements OnInit { + constructor(private titleService: Title, private router: Router) {} + + private getPageTitle(routeSnapshot: ActivatedRouteSnapshot) { + let title: string = routeSnapshot.data && routeSnapshot.data['pageTitle'] ? routeSnapshot.data['pageTitle'] : 'bookstoreApp'; + if (routeSnapshot.firstChild) { + title = this.getPageTitle(routeSnapshot.firstChild) || title; + } + return title; + } + + ngOnInit() { + this.router.events.subscribe(event => { + if (event instanceof NavigationEnd) { + this.titleService.setTitle(this.getPageTitle(this.router.routerState.snapshot.root)); + } + if (event instanceof NavigationError && event.error.status === 404) { + this.router.navigate(['/404']); + } + }); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/navbar/navbar.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/navbar/navbar.component.html new file mode 100644 index 0000000000..e58d234c22 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/navbar/navbar.component.html @@ -0,0 +1,145 @@ + diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/navbar/navbar.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/navbar/navbar.component.ts new file mode 100644 index 0000000000..6e00d7a1cb --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/navbar/navbar.component.ts @@ -0,0 +1,65 @@ +import { Component, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; +import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; + +import { VERSION } from 'app/app.constants'; +import { AccountService, LoginModalService, LoginService } from 'app/core'; +import { ProfileService } from 'app/layouts/profiles/profile.service'; + +@Component({ + selector: 'jhi-navbar', + templateUrl: './navbar.component.html', + styleUrls: ['navbar.scss'] +}) +export class NavbarComponent implements OnInit { + inProduction: boolean; + isNavbarCollapsed: boolean; + languages: any[]; + swaggerEnabled: boolean; + modalRef: NgbModalRef; + version: string; + + constructor( + private loginService: LoginService, + private accountService: AccountService, + private loginModalService: LoginModalService, + private profileService: ProfileService, + private router: Router + ) { + this.version = VERSION ? 'v' + VERSION : ''; + this.isNavbarCollapsed = true; + } + + ngOnInit() { + this.profileService.getProfileInfo().then(profileInfo => { + this.inProduction = profileInfo.inProduction; + this.swaggerEnabled = profileInfo.swaggerEnabled; + }); + } + + collapseNavbar() { + this.isNavbarCollapsed = true; + } + + isAuthenticated() { + return this.accountService.isAuthenticated(); + } + + login() { + this.modalRef = this.loginModalService.open(); + } + + logout() { + this.collapseNavbar(); + this.loginService.logout(); + this.router.navigate(['']); + } + + toggleNavbar() { + this.isNavbarCollapsed = !this.isNavbarCollapsed; + } + + getImageUrl() { + return this.isAuthenticated() ? this.accountService.getImageUrl() : null; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/navbar/navbar.route.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/navbar/navbar.route.ts new file mode 100644 index 0000000000..317d99604b --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/navbar/navbar.route.ts @@ -0,0 +1,9 @@ +import { Route } from '@angular/router'; + +import { NavbarComponent } from './navbar.component'; + +export const navbarRoute: Route = { + path: '', + component: NavbarComponent, + outlet: 'navbar' +}; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/navbar/navbar.scss b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/navbar/navbar.scss new file mode 100644 index 0000000000..9a5f929293 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/navbar/navbar.scss @@ -0,0 +1,53 @@ +@import '~bootstrap/scss/functions'; +@import '~bootstrap/scss/variables'; + +/* ========================================================================== +Navbar +========================================================================== */ + +.navbar-version { + font-size: 0.65em; + color: $navbar-dark-color; +} + +.profile-image { + height: 1.75em; + width: 1.75em; +} + +.navbar { + padding: 0.2rem 1rem; + .dropdown-item.active, + .dropdown-item.active:focus, + .dropdown-item.active:hover { + background-color: $dark; + } + + ul.navbar-nav { + .nav-item { + margin-left: 0.5em; + } + } + + a.nav-link { + font-weight: 400; + } + + .navbar-toggler { + &:hover { + color: $navbar-dark-hover-color; + } + } +} + +/* ========================================================================== +Logo styles +========================================================================== */ +.logo-img { + height: 45px; + width: 45px; + display: inline-block; + vertical-align: middle; + background: url('../../../content/images/logo-jhipster.png') no-repeat center center; + background-size: contain; +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/profiles/page-ribbon.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/profiles/page-ribbon.component.ts new file mode 100644 index 0000000000..00fe76075d --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/profiles/page-ribbon.component.ts @@ -0,0 +1,26 @@ +import { Component, OnInit } from '@angular/core'; +import { ProfileService } from './profile.service'; +import { ProfileInfo } from './profile-info.model'; + +@Component({ + selector: 'jhi-page-ribbon', + template: ` + + `, + styleUrls: ['page-ribbon.scss'] +}) +export class PageRibbonComponent implements OnInit { + profileInfo: ProfileInfo; + ribbonEnv: string; + + constructor(private profileService: ProfileService) {} + + ngOnInit() { + this.profileService.getProfileInfo().then(profileInfo => { + this.profileInfo = profileInfo; + this.ribbonEnv = profileInfo.ribbonEnv; + }); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/profiles/page-ribbon.scss b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/profiles/page-ribbon.scss new file mode 100644 index 0000000000..90125b70cb --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/profiles/page-ribbon.scss @@ -0,0 +1,31 @@ +/* ========================================================================== +Developement Ribbon +========================================================================== */ +.ribbon { + background-color: rgba(170, 0, 0, 0.5); + left: -3.5em; + -moz-transform: rotate(-45deg); + -ms-transform: rotate(-45deg); + -o-transform: rotate(-45deg); + -webkit-transform: rotate(-45deg); + transform: rotate(-45deg); + overflow: hidden; + position: absolute; + top: 40px; + white-space: nowrap; + width: 15em; + z-index: 9999; + pointer-events: none; + opacity: 0.75; + a { + color: #fff; + display: block; + font-weight: 400; + margin: 1px 0; + padding: 10px 50px; + text-align: center; + text-decoration: none; + text-shadow: 0 0 5px #444; + pointer-events: none; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/profiles/profile-info.model.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/profiles/profile-info.model.ts new file mode 100644 index 0000000000..f1adc52c7b --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/profiles/profile-info.model.ts @@ -0,0 +1,6 @@ +export class ProfileInfo { + activeProfiles: string[]; + ribbonEnv: string; + inProduction: boolean; + swaggerEnabled: boolean; +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/profiles/profile.service.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/profiles/profile.service.ts new file mode 100644 index 0000000000..d07fad7e7f --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/profiles/profile.service.ts @@ -0,0 +1,40 @@ +import { Injectable } from '@angular/core'; +import { HttpClient, HttpResponse } from '@angular/common/http'; + +import { SERVER_API_URL } from 'app/app.constants'; +import { ProfileInfo } from './profile-info.model'; +import { map } from 'rxjs/operators'; + +@Injectable({ providedIn: 'root' }) +export class ProfileService { + private infoUrl = SERVER_API_URL + 'management/info'; + private profileInfo: Promise; + + constructor(private http: HttpClient) {} + + getProfileInfo(): Promise { + if (!this.profileInfo) { + this.profileInfo = this.http + .get(this.infoUrl, { observe: 'response' }) + .pipe( + map((res: HttpResponse) => { + const data = res.body; + const pi = new ProfileInfo(); + pi.activeProfiles = data['activeProfiles']; + const displayRibbonOnProfiles = data['display-ribbon-on-profiles'].split(','); + if (pi.activeProfiles) { + const ribbonProfiles = displayRibbonOnProfiles.filter(profile => pi.activeProfiles.includes(profile)); + if (ribbonProfiles.length !== 0) { + pi.ribbonEnv = ribbonProfiles[0]; + } + pi.inProduction = pi.activeProfiles.includes('prod'); + pi.swaggerEnabled = pi.activeProfiles.includes('swagger'); + } + return pi; + }) + ) + .toPromise(); + } + return this.profileInfo; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/polyfills.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/polyfills.ts new file mode 100644 index 0000000000..cf38f3221b --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/polyfills.ts @@ -0,0 +1,70 @@ +/** + * This file includes polyfills needed by Angular and is loaded before the app. + * You can add your own extra polyfills to this file. + * + * This file is divided into 2 sections: + * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. + * 2. Application imports. Files imported after ZoneJS that should be loaded before your main + * file. + * + * The current setup is for so-called "evergreen" browsers; the last versions of browsers that + * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), + * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. + * + * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html + */ + +/*************************************************************************************************** + * BROWSER POLYFILLS + */ + +/** IE9, IE10 and IE11 requires all of the following polyfills. **/ +import 'core-js/es6/symbol'; +import 'core-js/es6/object'; +import 'core-js/es6/function'; +import 'core-js/es6/parse-int'; +import 'core-js/es6/parse-float'; +import 'core-js/es6/number'; +import 'core-js/es6/math'; +import 'core-js/es6/string'; +import 'core-js/es6/date'; +import 'core-js/es6/array'; +import 'core-js/es7/array'; +import 'core-js/es6/regexp'; +import 'core-js/es6/map'; +import 'core-js/es6/weak-map'; +import 'core-js/es6/set'; + +/** IE10 and IE11 requires the following for NgClass support on SVG elements */ +// import 'classlist.js'; // Run `npm install --save classlist.js`. + +/** Evergreen browsers require these. **/ +import 'core-js/es6/reflect'; +import 'core-js/es7/reflect'; + +/** + * Required to support Web Animations `@angular/animation`. + * Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation + **/ +// import 'web-animations-js'; // Run `npm install --save web-animations-js`. + +/*************************************************************************************************** + * Zone JS is required by Angular itself. + */ +import 'zone.js/dist/zone'; // Included with Angular CLI. + +/*************************************************************************************************** + * APPLICATION IMPORTS + */ + +/** + * Date, currency, decimal and percent pipes. + * Needed for: All but Chrome, Firefox, Edge, IE11 and Safari 10 + */ +// import 'intl'; // Run `npm install --save intl`. +/** + * Need to import at least one locale-data with intl. + */ +// import 'intl/locale-data/jsonp/en'; + +require('../manifest.webapp'); diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/alert/alert-error.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/alert/alert-error.component.ts new file mode 100644 index 0000000000..892e2d828c --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/alert/alert-error.component.ts @@ -0,0 +1,110 @@ +import { Component, OnDestroy } from '@angular/core'; +import { JhiEventManager, JhiAlert, JhiAlertService } from 'ng-jhipster'; +import { Subscription } from 'rxjs'; + +@Component({ + selector: 'jhi-alert-error', + template: ` + + ` +}) +export class JhiAlertErrorComponent implements OnDestroy { + alerts: any[]; + cleanHttpErrorListener: Subscription; + /* tslint:disable */ + constructor(private alertService: JhiAlertService, private eventManager: JhiEventManager) { + /* tslint:enable */ + this.alerts = []; + + this.cleanHttpErrorListener = eventManager.subscribe('bookstoreApp.httpError', response => { + let i; + const httpErrorResponse = response.content; + switch (httpErrorResponse.status) { + // connection refused, server not reachable + case 0: + this.addErrorAlert('Server not reachable', 'error.server.not.reachable'); + break; + + case 400: + const arr = httpErrorResponse.headers.keys(); + let errorHeader = null; + let entityKey = null; + arr.forEach(entry => { + if (entry.toLowerCase().endsWith('app-error')) { + errorHeader = httpErrorResponse.headers.get(entry); + } else if (entry.toLowerCase().endsWith('app-params')) { + entityKey = httpErrorResponse.headers.get(entry); + } + }); + if (errorHeader) { + const entityName = entityKey; + this.addErrorAlert(errorHeader, errorHeader, { entityName }); + } else if (httpErrorResponse.error !== '' && httpErrorResponse.error.fieldErrors) { + const fieldErrors = httpErrorResponse.error.fieldErrors; + for (i = 0; i < fieldErrors.length; i++) { + const fieldError = fieldErrors[i]; + if (['Min', 'Max', 'DecimalMin', 'DecimalMax'].includes(fieldError.message)) { + fieldError.message = 'Size'; + } + // convert 'something[14].other[4].id' to 'something[].other[].id' so translations can be written to it + const convertedField = fieldError.field.replace(/\[\d*\]/g, '[]'); + const fieldName = convertedField.charAt(0).toUpperCase() + convertedField.slice(1); + this.addErrorAlert('Error on field "' + fieldName + '"', 'error.' + fieldError.message, { fieldName }); + } + } else if (httpErrorResponse.error !== '' && httpErrorResponse.error.message) { + this.addErrorAlert( + httpErrorResponse.error.message, + httpErrorResponse.error.message, + httpErrorResponse.error.params + ); + } else { + this.addErrorAlert(httpErrorResponse.error); + } + break; + + case 404: + this.addErrorAlert('Not found', 'error.url.not.found'); + break; + + default: + if (httpErrorResponse.error !== '' && httpErrorResponse.error.message) { + this.addErrorAlert(httpErrorResponse.error.message); + } else { + this.addErrorAlert(httpErrorResponse.error); + } + } + }); + } + + setClasses(alert) { + return { + toast: !!alert.toast, + [alert.position]: true + }; + } + + ngOnDestroy() { + if (this.cleanHttpErrorListener !== undefined && this.cleanHttpErrorListener !== null) { + this.eventManager.destroy(this.cleanHttpErrorListener); + this.alerts = []; + } + } + + addErrorAlert(message, key?, data?) { + const newAlert: JhiAlert = { + type: 'danger', + msg: message, + timeout: 5000, + toast: this.alertService.isToast(), + scoped: true + }; + + this.alerts.push(this.alertService.addAlert(newAlert, this.alerts)); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/alert/alert.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/alert/alert.component.ts new file mode 100644 index 0000000000..a77c3e72c5 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/alert/alert.component.ts @@ -0,0 +1,35 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { JhiAlertService } from 'ng-jhipster'; + +@Component({ + selector: 'jhi-alert', + template: ` + + ` +}) +export class JhiAlertComponent implements OnInit, OnDestroy { + alerts: any[]; + + constructor(private alertService: JhiAlertService) {} + + ngOnInit() { + this.alerts = this.alertService.get(); + } + + setClasses(alert) { + return { + toast: !!alert.toast, + [alert.position]: true + }; + } + + ngOnDestroy() { + this.alerts = []; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/auth/has-any-authority.directive.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/auth/has-any-authority.directive.ts new file mode 100644 index 0000000000..0f8cefb28e --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/auth/has-any-authority.directive.ts @@ -0,0 +1,42 @@ +import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core'; +import { AccountService } from 'app/core/auth/account.service'; + +/** + * @whatItDoes Conditionally includes an HTML element if current user has any + * of the authorities passed as the `expression`. + * + * @howToUse + * ``` + * ... + * + * ... + * ``` + */ +@Directive({ + selector: '[jhiHasAnyAuthority]' +}) +export class HasAnyAuthorityDirective { + private authorities: string[]; + + constructor( + private accountService: AccountService, + private templateRef: TemplateRef, + private viewContainerRef: ViewContainerRef + ) {} + + @Input() + set jhiHasAnyAuthority(value: string | string[]) { + this.authorities = typeof value === 'string' ? [value] : value; + this.updateView(); + // Get notified each time authentication state changes. + this.accountService.getAuthenticationState().subscribe(identity => this.updateView()); + } + + private updateView(): void { + const hasAnyAuthority = this.accountService.hasAnyAuthority(this.authorities); + this.viewContainerRef.clear(); + if (hasAnyAuthority) { + this.viewContainerRef.createEmbeddedView(this.templateRef); + } + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/constants/error.constants.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/constants/error.constants.ts new file mode 100644 index 0000000000..2ebea94220 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/constants/error.constants.ts @@ -0,0 +1,4 @@ +export const PROBLEM_BASE_URL = 'https://www.jhipster.tech/problem'; +export const EMAIL_ALREADY_USED_TYPE = PROBLEM_BASE_URL + '/email-already-used'; +export const LOGIN_ALREADY_USED_TYPE = PROBLEM_BASE_URL + '/login-already-used'; +export const EMAIL_NOT_FOUND_TYPE = PROBLEM_BASE_URL + '/email-not-found'; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/constants/input.constants.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/constants/input.constants.ts new file mode 100644 index 0000000000..1e3978a9b3 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/constants/input.constants.ts @@ -0,0 +1,2 @@ +export const DATE_FORMAT = 'YYYY-MM-DD'; +export const DATE_TIME_FORMAT = 'YYYY-MM-DDTHH:mm'; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/constants/pagination.constants.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/constants/pagination.constants.ts new file mode 100644 index 0000000000..a148d4579b --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/constants/pagination.constants.ts @@ -0,0 +1 @@ +export const ITEMS_PER_PAGE = 20; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/index.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/index.ts new file mode 100644 index 0000000000..92a8ccef73 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/index.ts @@ -0,0 +1,12 @@ +export * from './constants/error.constants'; +export * from './constants/pagination.constants'; +export * from './constants/input.constants'; +export * from './alert/alert.component'; +export * from './alert/alert-error.component'; +export * from './auth/has-any-authority.directive'; +export * from './login/login.component'; +export * from './util/request-util'; +export * from './shared-libs.module'; +export * from './shared-common.module'; +export * from './shared.module'; +export * from './util/datepicker-adapter'; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/login/login.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/login/login.component.html new file mode 100644 index 0000000000..60d593bd4b --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/login/login.component.html @@ -0,0 +1,43 @@ + + diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/login/login.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/login/login.component.ts new file mode 100644 index 0000000000..46711a0619 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/login/login.component.ts @@ -0,0 +1,87 @@ +import { Component, AfterViewInit, Renderer, ElementRef } from '@angular/core'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { Router } from '@angular/router'; +import { JhiEventManager } from 'ng-jhipster'; + +import { LoginService } from 'app/core/login/login.service'; +import { StateStorageService } from 'app/core/auth/state-storage.service'; + +@Component({ + selector: 'jhi-login-modal', + templateUrl: './login.component.html' +}) +export class JhiLoginModalComponent implements AfterViewInit { + authenticationError: boolean; + password: string; + rememberMe: boolean; + username: string; + credentials: any; + + constructor( + private eventManager: JhiEventManager, + private loginService: LoginService, + private stateStorageService: StateStorageService, + private elementRef: ElementRef, + private renderer: Renderer, + private router: Router, + public activeModal: NgbActiveModal + ) { + this.credentials = {}; + } + + ngAfterViewInit() { + setTimeout(() => this.renderer.invokeElementMethod(this.elementRef.nativeElement.querySelector('#username'), 'focus', []), 0); + } + + cancel() { + this.credentials = { + username: null, + password: null, + rememberMe: true + }; + this.authenticationError = false; + this.activeModal.dismiss('cancel'); + } + + login() { + this.loginService + .login({ + username: this.username, + password: this.password, + rememberMe: this.rememberMe + }) + .then(() => { + this.authenticationError = false; + this.activeModal.dismiss('login success'); + if (this.router.url === '/register' || /^\/activate\//.test(this.router.url) || /^\/reset\//.test(this.router.url)) { + this.router.navigate(['']); + } + + this.eventManager.broadcast({ + name: 'authenticationSuccess', + content: 'Sending Authentication Success' + }); + + // previousState was set in the authExpiredInterceptor before being redirected to login modal. + // since login is successful, go to stored previousState and clear previousState + const redirect = this.stateStorageService.getUrl(); + if (redirect) { + this.stateStorageService.storeUrl(null); + this.router.navigate([redirect]); + } + }) + .catch(() => { + this.authenticationError = true; + }); + } + + register() { + this.activeModal.dismiss('to state register'); + this.router.navigate(['/register']); + } + + requestResetPassword() { + this.activeModal.dismiss('to state requestReset'); + this.router.navigate(['/reset', 'request']); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/model/book.model.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/model/book.model.ts new file mode 100644 index 0000000000..ee943a4127 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/model/book.model.ts @@ -0,0 +1,21 @@ +import { Moment } from 'moment'; + +export interface IBook { + id?: number; + title?: string; + author?: string; + published?: Moment; + quantity?: number; + price?: number; +} + +export class Book implements IBook { + constructor( + public id?: number, + public title?: string, + public author?: string, + public published?: Moment, + public quantity?: number, + public price?: number + ) {} +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/shared-common.module.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/shared-common.module.ts new file mode 100644 index 0000000000..c6e52d67c5 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/shared-common.module.ts @@ -0,0 +1,10 @@ +import { NgModule } from '@angular/core'; + +import { BookstoreSharedLibsModule, JhiAlertComponent, JhiAlertErrorComponent } from './'; + +@NgModule({ + imports: [BookstoreSharedLibsModule], + declarations: [JhiAlertComponent, JhiAlertErrorComponent], + exports: [BookstoreSharedLibsModule, JhiAlertComponent, JhiAlertErrorComponent] +}) +export class BookstoreSharedCommonModule {} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/shared-libs.module.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/shared-libs.module.ts new file mode 100644 index 0000000000..79ac658edb --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/shared-libs.module.ts @@ -0,0 +1,20 @@ +import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { CommonModule } from '@angular/common'; +import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; +import { NgJhipsterModule } from 'ng-jhipster'; +import { InfiniteScrollModule } from 'ngx-infinite-scroll'; +import { CookieModule } from 'ngx-cookie'; +import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; + +@NgModule({ + imports: [NgbModule.forRoot(), InfiniteScrollModule, CookieModule.forRoot(), FontAwesomeModule], + exports: [FormsModule, CommonModule, NgbModule, NgJhipsterModule, InfiniteScrollModule, FontAwesomeModule] +}) +export class BookstoreSharedLibsModule { + static forRoot() { + return { + ngModule: BookstoreSharedLibsModule + }; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/shared.module.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/shared.module.ts new file mode 100644 index 0000000000..695b166793 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/shared.module.ts @@ -0,0 +1,21 @@ +import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; +import { NgbDateAdapter } from '@ng-bootstrap/ng-bootstrap'; + +import { NgbDateMomentAdapter } from './util/datepicker-adapter'; +import { BookstoreSharedLibsModule, BookstoreSharedCommonModule, JhiLoginModalComponent, HasAnyAuthorityDirective } from './'; + +@NgModule({ + imports: [BookstoreSharedLibsModule, BookstoreSharedCommonModule], + declarations: [JhiLoginModalComponent, HasAnyAuthorityDirective], + providers: [{ provide: NgbDateAdapter, useClass: NgbDateMomentAdapter }], + entryComponents: [JhiLoginModalComponent], + exports: [BookstoreSharedCommonModule, JhiLoginModalComponent, HasAnyAuthorityDirective], + schemas: [CUSTOM_ELEMENTS_SCHEMA] +}) +export class BookstoreSharedModule { + static forRoot() { + return { + ngModule: BookstoreSharedModule + }; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/util/datepicker-adapter.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/util/datepicker-adapter.ts new file mode 100644 index 0000000000..524a38c834 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/util/datepicker-adapter.ts @@ -0,0 +1,21 @@ +/** + * Angular bootstrap Date adapter + */ +import { Injectable } from '@angular/core'; +import { NgbDateAdapter, NgbDateStruct } from '@ng-bootstrap/ng-bootstrap'; +import { Moment } from 'moment'; +import * as moment from 'moment'; + +@Injectable() +export class NgbDateMomentAdapter extends NgbDateAdapter { + fromModel(date: Moment): NgbDateStruct { + if (date != null && moment.isMoment(date) && date.isValid()) { + return { year: date.year(), month: date.month() + 1, day: date.date() }; + } + return null; + } + + toModel(date: NgbDateStruct): Moment { + return date ? moment(date.year + '-' + date.month + '-' + date.day, 'YYYY-MM-DD') : null; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/util/request-util.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/util/request-util.ts new file mode 100644 index 0000000000..6579c3cb2a --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/util/request-util.ts @@ -0,0 +1,18 @@ +import { HttpParams } from '@angular/common/http'; + +export const createRequestOption = (req?: any): HttpParams => { + let options: HttpParams = new HttpParams(); + if (req) { + Object.keys(req).forEach(key => { + if (key !== 'sort') { + options = options.set(key, req[key]); + } + }); + if (req.sort) { + req.sort.forEach(val => { + options = options.append('sort', val); + }); + } + } + return options; +}; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/vendor.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/vendor.ts new file mode 100644 index 0000000000..e8923d5c66 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/vendor.ts @@ -0,0 +1,81 @@ +/* after changing this file run 'npm run webpack:build' */ +/* tslint:disable */ +import '../content/scss/vendor.scss'; + +// Imports all fontawesome core and solid icons + +import { library } from '@fortawesome/fontawesome-svg-core'; +import { + faUser, + faSort, + faSortUp, + faSortDown, + faSync, + faEye, + faBan, + faTimes, + faArrowLeft, + faSave, + faPlus, + faPencilAlt, + faBars, + faThList, + faUserPlus, + faRoad, + faTachometerAlt, + faHeart, + faList, + faBell, + faBook, + faHdd, + faFlag, + faWrench, + faClock, + faCloud, + faSignOutAlt, + faSignInAlt, + faCalendarAlt, + faSearch, + faTrashAlt, + faAsterisk, + faTasks, + faHome +} from '@fortawesome/free-solid-svg-icons'; + +// Adds the SVG icon to the library so you can use it in your page +library.add(faUser); +library.add(faSort); +library.add(faSortUp); +library.add(faSortDown); +library.add(faSync); +library.add(faEye); +library.add(faBan); +library.add(faTimes); +library.add(faArrowLeft); +library.add(faSave); +library.add(faPlus); +library.add(faPencilAlt); +library.add(faBars); +library.add(faHome); +library.add(faThList); +library.add(faUserPlus); +library.add(faRoad); +library.add(faTachometerAlt); +library.add(faHeart); +library.add(faList); +library.add(faBell); +library.add(faTasks); +library.add(faBook); +library.add(faHdd); +library.add(faFlag); +library.add(faWrench); +library.add(faClock); +library.add(faCloud); +library.add(faSignOutAlt); +library.add(faSignInAlt); +library.add(faCalendarAlt); +library.add(faSearch); +library.add(faTrashAlt); +library.add(faAsterisk); + +// jhipster-needle-add-element-to-vendor - JHipster will add new menu items here diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/content/css/loading.css b/jhipster-5/bookstore-monolith/src/main/webapp/content/css/loading.css new file mode 100644 index 0000000000..a1e24615b4 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/content/css/loading.css @@ -0,0 +1,152 @@ +@keyframes lds-pacman-1 { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 50% { + -webkit-transform: rotate(-45deg); + transform: rotate(-45deg); + } + 100% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } +} +@-webkit-keyframes lds-pacman-1 { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 50% { + -webkit-transform: rotate(-45deg); + transform: rotate(-45deg); + } + 100% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } +} +@keyframes lds-pacman-2 { + 0% { + -webkit-transform: rotate(180deg); + transform: rotate(180deg); + } + 50% { + -webkit-transform: rotate(225deg); + transform: rotate(225deg); + } + 100% { + -webkit-transform: rotate(180deg); + transform: rotate(180deg); + } +} +@-webkit-keyframes lds-pacman-2 { + 0% { + -webkit-transform: rotate(180deg); + transform: rotate(180deg); + } + 50% { + -webkit-transform: rotate(225deg); + transform: rotate(225deg); + } + 100% { + -webkit-transform: rotate(180deg); + transform: rotate(180deg); + } +} +@keyframes lds-pacman-3 { + 0% { + -webkit-transform: translate(190px, 0); + transform: translate(190px, 0); + opacity: 0; + } + 20% { + opacity: 1; + } + 100% { + -webkit-transform: translate(70px, 0); + transform: translate(70px, 0); + opacity: 1; + } +} +@-webkit-keyframes lds-pacman-3 { + 0% { + -webkit-transform: translate(190px, 0); + transform: translate(190px, 0); + opacity: 0; + } + 20% { + opacity: 1; + } + 100% { + -webkit-transform: translate(70px, 0); + transform: translate(70px, 0); + opacity: 1; + } +} + +.app-loading { + font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; + position: relative; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + top: 10em; +} +.app-loading p { + display: block; + font-size: 1.17em; + margin-inline-start: 0px; + margin-inline-end: 0px; + font-weight: normal; +} + +.app-loading .lds-pacman { + position: relative; + margin: auto; + width: 200px !important; + height: 200px !important; + -webkit-transform: translate(-100px, -100px) scale(1) translate(100px, 100px); + transform: translate(-100px, -100px) scale(1) translate(100px, 100px); +} +.app-loading .lds-pacman > div:nth-child(2) div { + position: absolute; + top: 40px; + left: 40px; + width: 120px; + height: 60px; + border-radius: 120px 120px 0 0; + background: #bbcedd; + -webkit-animation: lds-pacman-1 1s linear infinite; + animation: lds-pacman-1 1s linear infinite; + -webkit-transform-origin: 60px 60px; + transform-origin: 60px 60px; +} +.app-loading .lds-pacman > div:nth-child(2) div:nth-child(2) { + -webkit-animation: lds-pacman-2 1s linear infinite; + animation: lds-pacman-2 1s linear infinite; +} +.app-loading .lds-pacman > div:nth-child(1) div { + position: absolute; + top: 97px; + left: -8px; + width: 24px; + height: 10px; + background-image: url('../images/logo-jhipster.png'); + background-size: contain; + -webkit-animation: lds-pacman-3 1s linear infinite; + animation: lds-pacman-3 1.5s linear infinite; +} +.app-loading .lds-pacman > div:nth-child(1) div:nth-child(1) { + -webkit-animation-delay: -0.67s; + animation-delay: -1s; +} +.app-loading .lds-pacman > div:nth-child(1) div:nth-child(2) { + -webkit-animation-delay: -0.33s; + animation-delay: -0.5s; +} +.app-loading .lds-pacman > div:nth-child(1) div:nth-child(3) { + -webkit-animation-delay: 0s; + animation-delay: 0s; +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_0.svg b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_0.svg new file mode 100755 index 0000000000..1f9ab52790 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_0.svg @@ -0,0 +1,198 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_0_head-192.png b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_0_head-192.png new file mode 100644 index 0000000000..8133068921 Binary files /dev/null and b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_0_head-192.png differ diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_0_head-256.png b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_0_head-256.png new file mode 100644 index 0000000000..b4739ec3e4 Binary files /dev/null and b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_0_head-256.png differ diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_0_head-384.png b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_0_head-384.png new file mode 100644 index 0000000000..0280f27e8b Binary files /dev/null and b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_0_head-384.png differ diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_0_head-512.png b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_0_head-512.png new file mode 100644 index 0000000000..326141b927 Binary files /dev/null and b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_0_head-512.png differ diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_1.svg b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_1.svg new file mode 100755 index 0000000000..7a118f3077 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_1.svg @@ -0,0 +1,9387 @@ + + + +image/svg+xml \ No newline at end of file diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_1_head-192.png b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_1_head-192.png new file mode 100644 index 0000000000..dd2643c15d Binary files /dev/null and b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_1_head-192.png differ diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_1_head-256.png b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_1_head-256.png new file mode 100644 index 0000000000..2c5352683a Binary files /dev/null and b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_1_head-256.png differ diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_1_head-384.png b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_1_head-384.png new file mode 100644 index 0000000000..f930681c12 Binary files /dev/null and b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_1_head-384.png differ diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_1_head-512.png b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_1_head-512.png new file mode 100644 index 0000000000..9110dc8fe4 Binary files /dev/null and b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_1_head-512.png differ diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_2.svg b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_2.svg new file mode 100755 index 0000000000..1747933833 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_2.svg @@ -0,0 +1,841 @@ + + + +image/svg+xml \ No newline at end of file diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_2_head-192.png b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_2_head-192.png new file mode 100644 index 0000000000..2699ab4473 Binary files /dev/null and b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_2_head-192.png differ diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_2_head-256.png b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_2_head-256.png new file mode 100644 index 0000000000..3a5903e19e Binary files /dev/null and b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_2_head-256.png differ diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_2_head-384.png b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_2_head-384.png new file mode 100644 index 0000000000..da964fcb2e Binary files /dev/null and b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_2_head-384.png differ diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_2_head-512.png b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_2_head-512.png new file mode 100644 index 0000000000..6337f5effb Binary files /dev/null and b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_2_head-512.png differ diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_3.svg b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_3.svg new file mode 100755 index 0000000000..6b9e056662 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_3.svg @@ -0,0 +1,308 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_3_head-192.png b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_3_head-192.png new file mode 100644 index 0000000000..35b91257fc Binary files /dev/null and b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_3_head-192.png differ diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_3_head-256.png b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_3_head-256.png new file mode 100644 index 0000000000..098fd8fb05 Binary files /dev/null and b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_3_head-256.png differ diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_3_head-384.png b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_3_head-384.png new file mode 100644 index 0000000000..b770045754 Binary files /dev/null and b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_3_head-384.png differ diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_3_head-512.png b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_3_head-512.png new file mode 100644 index 0000000000..58b28b9c48 Binary files /dev/null and b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_3_head-512.png differ diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/content/images/logo-jhipster.png b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/logo-jhipster.png new file mode 100755 index 0000000000..5d31c2f84d Binary files /dev/null and b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/logo-jhipster.png differ diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/content/scss/_bootstrap-variables.scss b/jhipster-5/bookstore-monolith/src/main/webapp/content/scss/_bootstrap-variables.scss new file mode 100644 index 0000000000..be0f226497 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/content/scss/_bootstrap-variables.scss @@ -0,0 +1,42 @@ +/* +* Bootstrap overrides https://getbootstrap.com/docs/4.0/getting-started/theming/ +* All values defined in bootstrap source +* https://github.com/twbs/bootstrap/blob/v4-dev/scss/_variables.scss can be overwritten here +* Make sure not to add !default to values here +*/ + +// Colors: +// Grayscale and brand colors for use across Bootstrap. + +$primary: #3e8acc; +$success: #28a745; +$info: #17a2b8; +$warning: #ffc107; +$danger: #dc3545; + +// Options: +// Quickly modify global styling by enabling or disabling optional features. +$enable-rounded: true; +$enable-shadows: false; +$enable-gradients: false; +$enable-transitions: true; +$enable-hover-media-query: false; +$enable-grid-classes: true; +$enable-print-styles: true; + +// Components: +// Define common padding and border radius sizes and more. + +$border-radius: 0.15rem; +$border-radius-lg: 0.125rem; +$border-radius-sm: 0.1rem; + +// Body: +// Settings for the `` element. + +$body-bg: #e4e5e6; + +// Typography: +// Font, line-height, and color for body text, headings, and more. + +$font-size-base: 1rem; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/content/scss/global.scss b/jhipster-5/bookstore-monolith/src/main/webapp/content/scss/global.scss new file mode 100644 index 0000000000..cfbb9bf5b8 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/content/scss/global.scss @@ -0,0 +1,226 @@ +@import 'bootstrap-variables'; + +/* ============================================================== +Bootstrap tweaks +===============================================================*/ + +body, +h1, +h2, +h3, +h4 { + font-weight: 300; +} + +a { + color: #533f03; + font-weight: bold; +} + +a:hover { + color: #533f03; + font-weight: bold; + /* make sure browsers use the pointer cursor for anchors, even with no href */ + cursor: pointer; +} + +/* ========================================================================== +Browser Upgrade Prompt +========================================================================== */ +.browserupgrade { + margin: 0.2em 0; + background: #ccc; + color: #000; + padding: 0.2em 0; +} + +/* ========================================================================== +Generic styles +========================================================================== */ + +/* Error highlight on input fields */ +.ng-valid[required], +.ng-valid.required { + border-left: 5px solid green; +} + +.ng-invalid:not(form) { + border-left: 5px solid red; +} + +/* other generic styles */ + +.jh-card { + padding: 1.5%; + margin-top: 20px; + border: none; +} + +.error { + color: white; + background-color: red; +} + +.pad { + padding: 10px; +} + +.w-40 { + width: 40% !important; +} + +.w-60 { + width: 60% !important; +} + +.break { + white-space: normal; + word-break: break-all; +} + +.readonly { + background-color: #eee; + opacity: 1; +} + +.footer { + border-top: 1px solid rgba(0, 0, 0, 0.125); +} + +.hand, +[jhisortby] { + cursor: pointer; +} + +/* ========================================================================== +Custom alerts for notification +========================================================================== */ +.alerts { + .alert { + text-overflow: ellipsis; + pre { + background: none; + border: none; + font: inherit; + color: inherit; + padding: 0; + margin: 0; + } + .popover pre { + font-size: 10px; + } + } + .toast { + position: fixed; + width: 100%; + &.left { + left: 5px; + } + &.right { + right: 5px; + } + &.top { + top: 55px; + } + &.bottom { + bottom: 55px; + } + } +} + +@media screen and (min-width: 480px) { + .alerts .toast { + width: 50%; + } +} + +/* ========================================================================== +entity tables helpers +========================================================================== */ + +/* Remove Bootstrap padding from the element +http://stackoverflow.com/questions/19562903/remove-padding-from-columns-in-bootstrap-3 */ +@mixin no-padding($side) { + @if $side == 'all' { + .no-padding { + padding: 0 !important; + } + } @else { + .no-padding-#{$side} { + padding-#{$side}: 0 !important; + } + } +} +@include no-padding('left'); +@include no-padding('right'); +@include no-padding('top'); +@include no-padding('bottom'); +@include no-padding('all'); + +/* bootstrap 3 input-group 100% width +http://stackoverflow.com/questions/23436430/bootstrap-3-input-group-100-width */ +.width-min { + width: 1% !important; +} + +/* Makes toolbar not wrap on smaller screens +http://www.sketchingwithcss.com/samplechapter/cheatsheet.html#right */ +.flex-btn-group-container { + display: -webkit-flex; + display: flex; + -webkit-flex-direction: row; + flex-direction: row; + -webkit-justify-content: flex-end; + justify-content: flex-end; +} + +/* ========================================================================== +entity detail page css +========================================================================== */ +.row.jh-entity-details > { + dd { + margin-bottom: 15px; + } +} + +@media screen and (min-width: 768px) { + .row.jh-entity-details > { + dt { + margin-bottom: 15px; + } + dd { + border-bottom: 1px solid #eee; + padding-left: 180px; + margin-left: 0; + } + } +} + +/* ========================================================================== +ui bootstrap tweaks +========================================================================== */ +.nav, +.pagination, +.carousel, +.panel-title a { + cursor: pointer; +} + +.datetime-picker-dropdown > li.date-picker-menu div > table .btn-default, +.uib-datepicker-popup > li > div.uib-datepicker > table .btn-default { + border: 0; +} + +.datetime-picker-dropdown > li.date-picker-menu div > table:focus, +.uib-datepicker-popup > li > div.uib-datepicker > table:focus { + outline: none; +} + +.thread-dump-modal-lock { + max-width: 450px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +/* jhipster-needle-scss-add-main JHipster will add new css style */ diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/content/scss/vendor.scss b/jhipster-5/bookstore-monolith/src/main/webapp/content/scss/vendor.scss new file mode 100644 index 0000000000..12a8f54b83 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/content/scss/vendor.scss @@ -0,0 +1,12 @@ +/* after changing this file run 'npm run webpack:build' */ + +/*************************** +put Sass variables here: +eg $input-color: red; +****************************/ +// Override Boostrap variables +@import 'bootstrap-variables'; +// Import Bootstrap source files from node_modules +@import '~bootstrap/scss/bootstrap'; + +/* jhipster-needle-scss-add-vendor JHipster will add new css style */ diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/favicon.ico b/jhipster-5/bookstore-monolith/src/main/webapp/favicon.ico new file mode 100755 index 0000000000..4179874f53 Binary files /dev/null and b/jhipster-5/bookstore-monolith/src/main/webapp/favicon.ico differ diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/index.html b/jhipster-5/bookstore-monolith/src/main/webapp/index.html new file mode 100644 index 0000000000..a2fd4df265 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/index.html @@ -0,0 +1,108 @@ + + + + + + + Bookstore + + + + + + + + + + + +
+
+
+
+
+
+
+
+
+ +
+
+ + + + + + diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/manifest.webapp b/jhipster-5/bookstore-monolith/src/main/webapp/manifest.webapp new file mode 100644 index 0000000000..42b606ea1d --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/manifest.webapp @@ -0,0 +1,31 @@ +{ + "name": "Bookstore", + "short_name": "Bookstore", + "icons": [ + { + "src": "./content/images/jhipster_family_member_0_head-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "./content/images/jhipster_family_member_0_head-256.png", + "sizes": "256x256", + "type": "image/png" + }, + { + "src": "./content/images/jhipster_family_member_0_head-384.png", + "sizes": "384x384", + "type": "image/png" + }, + { + "src": "./content/images/jhipster_family_member_0_head-512.png", + "sizes": "512x512", + "type": "image/png" + } + ], + "theme_color": "#000000", + "background_color": "#e0e0e0", + "start_url": "/index.html", + "display": "standalone", + "orientation": "portrait" +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/robots.txt b/jhipster-5/bookstore-monolith/src/main/webapp/robots.txt new file mode 100644 index 0000000000..7cda27477d --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/robots.txt @@ -0,0 +1,11 @@ +# robotstxt.org/ + +User-agent: * +Disallow: /api/account +Disallow: /api/account/change-password +Disallow: /api/account/sessions +Disallow: /api/audits/ +Disallow: /api/logs/ +Disallow: /api/users/ +Disallow: /management/ +Disallow: /v2/api-docs/ diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/swagger-ui/index.html b/jhipster-5/bookstore-monolith/src/main/webapp/swagger-ui/index.html new file mode 100644 index 0000000000..416eacef70 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/swagger-ui/index.html @@ -0,0 +1,166 @@ + + + + + Swagger UI + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 
+
+ + diff --git a/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/config/WebConfigurerTest.java b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/config/WebConfigurerTest.java new file mode 100644 index 0000000000..670042d2df --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/config/WebConfigurerTest.java @@ -0,0 +1,189 @@ +package com.baeldung.jhipster5.config; + +import io.github.jhipster.config.JHipsterConstants; +import io.github.jhipster.config.JHipsterProperties; +import io.github.jhipster.web.filter.CachingHttpHeadersFilter; +import io.undertow.Undertow; +import io.undertow.Undertow.Builder; +import io.undertow.UndertowOptions; +import org.apache.commons.io.FilenameUtils; + +import org.h2.server.web.WebServlet; +import org.junit.Before; +import org.junit.Test; +import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory; +import org.springframework.http.HttpHeaders; +import org.springframework.mock.env.MockEnvironment; +import org.springframework.mock.web.MockServletContext; +import org.springframework.test.util.ReflectionTestUtils; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.xnio.OptionMap; + +import javax.servlet.*; +import java.util.*; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.options; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +/** + * Unit tests for the WebConfigurer class. + * + * @see WebConfigurer + */ +public class WebConfigurerTest { + + private WebConfigurer webConfigurer; + + private MockServletContext servletContext; + + private MockEnvironment env; + + private JHipsterProperties props; + + @Before + public void setup() { + servletContext = spy(new MockServletContext()); + doReturn(mock(FilterRegistration.Dynamic.class)) + .when(servletContext).addFilter(anyString(), any(Filter.class)); + doReturn(mock(ServletRegistration.Dynamic.class)) + .when(servletContext).addServlet(anyString(), any(Servlet.class)); + + env = new MockEnvironment(); + props = new JHipsterProperties(); + + webConfigurer = new WebConfigurer(env, props); + } + + @Test + public void testStartUpProdServletContext() throws ServletException { + env.setActiveProfiles(JHipsterConstants.SPRING_PROFILE_PRODUCTION); + webConfigurer.onStartup(servletContext); + + verify(servletContext).addFilter(eq("cachingHttpHeadersFilter"), any(CachingHttpHeadersFilter.class)); + verify(servletContext, never()).addServlet(eq("H2Console"), any(WebServlet.class)); + } + + @Test + public void testStartUpDevServletContext() throws ServletException { + env.setActiveProfiles(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT); + webConfigurer.onStartup(servletContext); + + verify(servletContext, never()).addFilter(eq("cachingHttpHeadersFilter"), any(CachingHttpHeadersFilter.class)); + verify(servletContext).addServlet(eq("H2Console"), any(WebServlet.class)); + } + + @Test + public void testCustomizeServletContainer() { + env.setActiveProfiles(JHipsterConstants.SPRING_PROFILE_PRODUCTION); + UndertowServletWebServerFactory container = new UndertowServletWebServerFactory(); + webConfigurer.customize(container); + assertThat(container.getMimeMappings().get("abs")).isEqualTo("audio/x-mpeg"); + assertThat(container.getMimeMappings().get("html")).isEqualTo("text/html;charset=utf-8"); + assertThat(container.getMimeMappings().get("json")).isEqualTo("text/html;charset=utf-8"); + if (container.getDocumentRoot() != null) { + assertThat(container.getDocumentRoot().getPath()).isEqualTo(FilenameUtils.separatorsToSystem("target/www")); + } + + Builder builder = Undertow.builder(); + container.getBuilderCustomizers().forEach(c -> c.customize(builder)); + OptionMap.Builder serverOptions = (OptionMap.Builder) ReflectionTestUtils.getField(builder, "serverOptions"); + assertThat(serverOptions.getMap().get(UndertowOptions.ENABLE_HTTP2)).isNull(); + } + + @Test + public void testUndertowHttp2Enabled() { + props.getHttp().setVersion(JHipsterProperties.Http.Version.V_2_0); + UndertowServletWebServerFactory container = new UndertowServletWebServerFactory(); + webConfigurer.customize(container); + Builder builder = Undertow.builder(); + container.getBuilderCustomizers().forEach(c -> c.customize(builder)); + OptionMap.Builder serverOptions = (OptionMap.Builder) ReflectionTestUtils.getField(builder, "serverOptions"); + assertThat(serverOptions.getMap().get(UndertowOptions.ENABLE_HTTP2)).isTrue(); + } + + @Test + public void testCorsFilterOnApiPath() throws Exception { + props.getCors().setAllowedOrigins(Collections.singletonList("*")); + props.getCors().setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE")); + props.getCors().setAllowedHeaders(Collections.singletonList("*")); + props.getCors().setMaxAge(1800L); + props.getCors().setAllowCredentials(true); + + MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new WebConfigurerTestController()) + .addFilters(webConfigurer.corsFilter()) + .build(); + + mockMvc.perform( + options("/api/test-cors") + .header(HttpHeaders.ORIGIN, "other.domain.com") + .header(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, "POST")) + .andExpect(status().isOk()) + .andExpect(header().string(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, "other.domain.com")) + .andExpect(header().string(HttpHeaders.VARY, "Origin")) + .andExpect(header().string(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, "GET,POST,PUT,DELETE")) + .andExpect(header().string(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true")) + .andExpect(header().string(HttpHeaders.ACCESS_CONTROL_MAX_AGE, "1800")); + + mockMvc.perform( + get("/api/test-cors") + .header(HttpHeaders.ORIGIN, "other.domain.com")) + .andExpect(status().isOk()) + .andExpect(header().string(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, "other.domain.com")); + } + + @Test + public void testCorsFilterOnOtherPath() throws Exception { + props.getCors().setAllowedOrigins(Collections.singletonList("*")); + props.getCors().setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE")); + props.getCors().setAllowedHeaders(Collections.singletonList("*")); + props.getCors().setMaxAge(1800L); + props.getCors().setAllowCredentials(true); + + MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new WebConfigurerTestController()) + .addFilters(webConfigurer.corsFilter()) + .build(); + + mockMvc.perform( + get("/test/test-cors") + .header(HttpHeaders.ORIGIN, "other.domain.com")) + .andExpect(status().isOk()) + .andExpect(header().doesNotExist(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN)); + } + + @Test + public void testCorsFilterDeactivated() throws Exception { + props.getCors().setAllowedOrigins(null); + + MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new WebConfigurerTestController()) + .addFilters(webConfigurer.corsFilter()) + .build(); + + mockMvc.perform( + get("/api/test-cors") + .header(HttpHeaders.ORIGIN, "other.domain.com")) + .andExpect(status().isOk()) + .andExpect(header().doesNotExist(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN)); + } + + @Test + public void testCorsFilterDeactivated2() throws Exception { + props.getCors().setAllowedOrigins(new ArrayList<>()); + + MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new WebConfigurerTestController()) + .addFilters(webConfigurer.corsFilter()) + .build(); + + mockMvc.perform( + get("/api/test-cors") + .header(HttpHeaders.ORIGIN, "other.domain.com")) + .andExpect(status().isOk()) + .andExpect(header().doesNotExist(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN)); + } +} diff --git a/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/config/WebConfigurerTestController.java b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/config/WebConfigurerTestController.java new file mode 100644 index 0000000000..c19b28ea16 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/config/WebConfigurerTestController.java @@ -0,0 +1,16 @@ +package com.baeldung.jhipster5.config; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class WebConfigurerTestController { + + @GetMapping("/api/test-cors") + public void testCorsOnApiPath() { + } + + @GetMapping("/test/test-cors") + public void testCorsOnOtherPath() { + } +} diff --git a/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/config/timezone/HibernateTimeZoneTest.java b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/config/timezone/HibernateTimeZoneTest.java new file mode 100644 index 0000000000..9027606e67 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/config/timezone/HibernateTimeZoneTest.java @@ -0,0 +1,176 @@ +package com.baeldung.jhipster5.config.timezone; + +import com.baeldung.jhipster5.BookstoreApp; +import com.baeldung.jhipster5.repository.timezone.DateTimeWrapper; +import com.baeldung.jhipster5.repository.timezone.DateTimeWrapperRepository; +import org.junit.Before; +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.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.support.rowset.SqlRowSet; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.transaction.annotation.Transactional; + +import java.time.*; +import java.time.format.DateTimeFormatter; + +import static java.lang.String.format; +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Unit tests for the UTC Hibernate configuration. + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = BookstoreApp.class) +public class HibernateTimeZoneTest { + + @Autowired + private DateTimeWrapperRepository dateTimeWrapperRepository; + @Autowired + private JdbcTemplate jdbcTemplate; + + private DateTimeWrapper dateTimeWrapper; + private DateTimeFormatter dateTimeFormatter; + private DateTimeFormatter timeFormatter; + private DateTimeFormatter dateFormatter; + + @Before + public void setup() { + dateTimeWrapper = new DateTimeWrapper(); + dateTimeWrapper.setInstant(Instant.parse("2014-11-12T05:50:00.0Z")); + dateTimeWrapper.setLocalDateTime(LocalDateTime.parse("2014-11-12T07:50:00.0")); + dateTimeWrapper.setOffsetDateTime(OffsetDateTime.parse("2011-12-14T08:30:00.0Z")); + dateTimeWrapper.setZonedDateTime(ZonedDateTime.parse("2011-12-14T08:30:00.0Z")); + dateTimeWrapper.setLocalTime(LocalTime.parse("14:30:00")); + dateTimeWrapper.setOffsetTime(OffsetTime.parse("14:30:00+02:00")); + dateTimeWrapper.setLocalDate(LocalDate.parse("2016-09-10")); + + dateTimeFormatter = DateTimeFormatter + .ofPattern("yyyy-MM-dd HH:mm:ss.S") + .withZone(ZoneId.of("UTC")); + + timeFormatter = DateTimeFormatter + .ofPattern("HH:mm:ss") + .withZone(ZoneId.of("UTC")); + + dateFormatter = DateTimeFormatter + .ofPattern("yyyy-MM-dd"); + } + + @Test + @Transactional + public void storeInstantWithUtcConfigShouldBeStoredOnGMTTimeZone() { + dateTimeWrapperRepository.saveAndFlush(dateTimeWrapper); + + String request = generateSqlRequest("instant", dateTimeWrapper.getId()); + SqlRowSet resultSet = jdbcTemplate.queryForRowSet(request); + String expectedValue = dateTimeFormatter.format(dateTimeWrapper.getInstant()); + + assertThatDateStoredValueIsEqualToInsertDateValueOnGMTTimeZone(resultSet, expectedValue); + } + + @Test + @Transactional + public void storeLocalDateTimeWithUtcConfigShouldBeStoredOnGMTTimeZone() { + dateTimeWrapperRepository.saveAndFlush(dateTimeWrapper); + + String request = generateSqlRequest("local_date_time", dateTimeWrapper.getId()); + SqlRowSet resultSet = jdbcTemplate.queryForRowSet(request); + String expectedValue = dateTimeWrapper + .getLocalDateTime() + .atZone(ZoneId.systemDefault()) + .format(dateTimeFormatter); + + assertThatDateStoredValueIsEqualToInsertDateValueOnGMTTimeZone(resultSet, expectedValue); + } + + @Test + @Transactional + public void storeOffsetDateTimeWithUtcConfigShouldBeStoredOnGMTTimeZone() { + dateTimeWrapperRepository.saveAndFlush(dateTimeWrapper); + + String request = generateSqlRequest("offset_date_time", dateTimeWrapper.getId()); + SqlRowSet resultSet = jdbcTemplate.queryForRowSet(request); + String expectedValue = dateTimeWrapper + .getOffsetDateTime() + .format(dateTimeFormatter); + + assertThatDateStoredValueIsEqualToInsertDateValueOnGMTTimeZone(resultSet, expectedValue); + } + + @Test + @Transactional + public void storeZoneDateTimeWithUtcConfigShouldBeStoredOnGMTTimeZone() { + dateTimeWrapperRepository.saveAndFlush(dateTimeWrapper); + + String request = generateSqlRequest("zoned_date_time", dateTimeWrapper.getId()); + SqlRowSet resultSet = jdbcTemplate.queryForRowSet(request); + String expectedValue = dateTimeWrapper + .getZonedDateTime() + .format(dateTimeFormatter); + + assertThatDateStoredValueIsEqualToInsertDateValueOnGMTTimeZone(resultSet, expectedValue); + } + + @Test + @Transactional + public void storeLocalTimeWithUtcConfigShouldBeStoredOnGMTTimeZoneAccordingToHis1stJan1970Value() { + dateTimeWrapperRepository.saveAndFlush(dateTimeWrapper); + + String request = generateSqlRequest("local_time", dateTimeWrapper.getId()); + SqlRowSet resultSet = jdbcTemplate.queryForRowSet(request); + String expectedValue = dateTimeWrapper + .getLocalTime() + .atDate(LocalDate.of(1970, Month.JANUARY, 1)) + .atZone(ZoneId.systemDefault()) + .format(timeFormatter); + + assertThatDateStoredValueIsEqualToInsertDateValueOnGMTTimeZone(resultSet, expectedValue); + } + + @Test + @Transactional + public void storeOffsetTimeWithUtcConfigShouldBeStoredOnGMTTimeZoneAccordingToHis1stJan1970Value() { + dateTimeWrapperRepository.saveAndFlush(dateTimeWrapper); + + String request = generateSqlRequest("offset_time", dateTimeWrapper.getId()); + SqlRowSet resultSet = jdbcTemplate.queryForRowSet(request); + String expectedValue = dateTimeWrapper + .getOffsetTime() + .toLocalTime() + .atDate(LocalDate.of(1970, Month.JANUARY, 1)) + .atZone(ZoneId.systemDefault()) + .format(timeFormatter); + + assertThatDateStoredValueIsEqualToInsertDateValueOnGMTTimeZone(resultSet, expectedValue); + } + + @Test + @Transactional + public void storeLocalDateWithUtcConfigShouldBeStoredWithoutTransformation() { + dateTimeWrapperRepository.saveAndFlush(dateTimeWrapper); + + String request = generateSqlRequest("local_date", dateTimeWrapper.getId()); + SqlRowSet resultSet = jdbcTemplate.queryForRowSet(request); + String expectedValue = dateTimeWrapper + .getLocalDate() + .format(dateFormatter); + + assertThatDateStoredValueIsEqualToInsertDateValueOnGMTTimeZone(resultSet, expectedValue); + } + + private String generateSqlRequest(String fieldName, long id) { + return format("SELECT %s FROM jhi_date_time_wrapper where id=%d", fieldName, id); + } + + private void assertThatDateStoredValueIsEqualToInsertDateValueOnGMTTimeZone(SqlRowSet sqlRowSet, String expectedValue) { + while (sqlRowSet.next()) { + String dbValue = sqlRowSet.getString(1); + + assertThat(dbValue).isNotNull(); + assertThat(dbValue).isEqualTo(expectedValue); + } + } +} diff --git a/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/repository/CustomAuditEventRepositoryIntTest.java b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/repository/CustomAuditEventRepositoryIntTest.java new file mode 100644 index 0000000000..eaf5c07504 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/repository/CustomAuditEventRepositoryIntTest.java @@ -0,0 +1,165 @@ +package com.baeldung.jhipster5.repository; + +import com.baeldung.jhipster5.BookstoreApp; +import com.baeldung.jhipster5.config.Constants; +import com.baeldung.jhipster5.config.audit.AuditEventConverter; +import com.baeldung.jhipster5.domain.PersistentAuditEvent; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.actuate.audit.AuditEvent; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpSession; +import org.springframework.security.web.authentication.WebAuthenticationDetails; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.transaction.annotation.Transactional; + +import javax.servlet.http.HttpSession; +import java.time.Instant; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; +import static com.baeldung.jhipster5.repository.CustomAuditEventRepository.EVENT_DATA_COLUMN_MAX_LENGTH; + +/** + * Test class for the CustomAuditEventRepository class. + * + * @see CustomAuditEventRepository + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = BookstoreApp.class) +@Transactional +public class CustomAuditEventRepositoryIntTest { + + @Autowired + private PersistenceAuditEventRepository persistenceAuditEventRepository; + + @Autowired + private AuditEventConverter auditEventConverter; + + private CustomAuditEventRepository customAuditEventRepository; + + private PersistentAuditEvent testUserEvent; + + private PersistentAuditEvent testOtherUserEvent; + + private PersistentAuditEvent testOldUserEvent; + + @Before + public void setup() { + customAuditEventRepository = new CustomAuditEventRepository(persistenceAuditEventRepository, auditEventConverter); + persistenceAuditEventRepository.deleteAll(); + Instant oneHourAgo = Instant.now().minusSeconds(3600); + + testUserEvent = new PersistentAuditEvent(); + testUserEvent.setPrincipal("test-user"); + testUserEvent.setAuditEventType("test-type"); + testUserEvent.setAuditEventDate(oneHourAgo); + Map data = new HashMap<>(); + data.put("test-key", "test-value"); + testUserEvent.setData(data); + + testOldUserEvent = new PersistentAuditEvent(); + testOldUserEvent.setPrincipal("test-user"); + testOldUserEvent.setAuditEventType("test-type"); + testOldUserEvent.setAuditEventDate(oneHourAgo.minusSeconds(10000)); + + testOtherUserEvent = new PersistentAuditEvent(); + testOtherUserEvent.setPrincipal("other-test-user"); + testOtherUserEvent.setAuditEventType("test-type"); + testOtherUserEvent.setAuditEventDate(oneHourAgo); + } + + @Test + public void addAuditEvent() { + Map data = new HashMap<>(); + data.put("test-key", "test-value"); + AuditEvent event = new AuditEvent("test-user", "test-type", data); + customAuditEventRepository.add(event); + List persistentAuditEvents = persistenceAuditEventRepository.findAll(); + assertThat(persistentAuditEvents).hasSize(1); + PersistentAuditEvent persistentAuditEvent = persistentAuditEvents.get(0); + assertThat(persistentAuditEvent.getPrincipal()).isEqualTo(event.getPrincipal()); + assertThat(persistentAuditEvent.getAuditEventType()).isEqualTo(event.getType()); + assertThat(persistentAuditEvent.getData()).containsKey("test-key"); + assertThat(persistentAuditEvent.getData().get("test-key")).isEqualTo("test-value"); + assertThat(persistentAuditEvent.getAuditEventDate()).isEqualTo(event.getTimestamp()); + } + + @Test + public void addAuditEventTruncateLargeData() { + Map data = new HashMap<>(); + StringBuilder largeData = new StringBuilder(); + for (int i = 0; i < EVENT_DATA_COLUMN_MAX_LENGTH + 10; i++) { + largeData.append("a"); + } + data.put("test-key", largeData); + AuditEvent event = new AuditEvent("test-user", "test-type", data); + customAuditEventRepository.add(event); + List persistentAuditEvents = persistenceAuditEventRepository.findAll(); + assertThat(persistentAuditEvents).hasSize(1); + PersistentAuditEvent persistentAuditEvent = persistentAuditEvents.get(0); + assertThat(persistentAuditEvent.getPrincipal()).isEqualTo(event.getPrincipal()); + assertThat(persistentAuditEvent.getAuditEventType()).isEqualTo(event.getType()); + assertThat(persistentAuditEvent.getData()).containsKey("test-key"); + String actualData = persistentAuditEvent.getData().get("test-key"); + assertThat(actualData.length()).isEqualTo(EVENT_DATA_COLUMN_MAX_LENGTH); + assertThat(actualData).isSubstringOf(largeData); + assertThat(persistentAuditEvent.getAuditEventDate()).isEqualTo(event.getTimestamp()); + } + + @Test + public void testAddEventWithWebAuthenticationDetails() { + HttpSession session = new MockHttpSession(null, "test-session-id"); + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setSession(session); + request.setRemoteAddr("1.2.3.4"); + WebAuthenticationDetails details = new WebAuthenticationDetails(request); + Map data = new HashMap<>(); + data.put("test-key", details); + AuditEvent event = new AuditEvent("test-user", "test-type", data); + customAuditEventRepository.add(event); + List persistentAuditEvents = persistenceAuditEventRepository.findAll(); + assertThat(persistentAuditEvents).hasSize(1); + PersistentAuditEvent persistentAuditEvent = persistentAuditEvents.get(0); + assertThat(persistentAuditEvent.getData().get("remoteAddress")).isEqualTo("1.2.3.4"); + assertThat(persistentAuditEvent.getData().get("sessionId")).isEqualTo("test-session-id"); + } + + @Test + public void testAddEventWithNullData() { + Map data = new HashMap<>(); + data.put("test-key", null); + AuditEvent event = new AuditEvent("test-user", "test-type", data); + customAuditEventRepository.add(event); + List persistentAuditEvents = persistenceAuditEventRepository.findAll(); + assertThat(persistentAuditEvents).hasSize(1); + PersistentAuditEvent persistentAuditEvent = persistentAuditEvents.get(0); + assertThat(persistentAuditEvent.getData().get("test-key")).isEqualTo("null"); + } + + @Test + public void addAuditEventWithAnonymousUser() { + Map data = new HashMap<>(); + data.put("test-key", "test-value"); + AuditEvent event = new AuditEvent(Constants.ANONYMOUS_USER, "test-type", data); + customAuditEventRepository.add(event); + List persistentAuditEvents = persistenceAuditEventRepository.findAll(); + assertThat(persistentAuditEvents).hasSize(0); + } + + @Test + public void addAuditEventWithAuthorizationFailureType() { + Map data = new HashMap<>(); + data.put("test-key", "test-value"); + AuditEvent event = new AuditEvent("test-user", "AUTHORIZATION_FAILURE", data); + customAuditEventRepository.add(event); + List persistentAuditEvents = persistenceAuditEventRepository.findAll(); + assertThat(persistentAuditEvents).hasSize(0); + } + +} diff --git a/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/repository/timezone/DateTimeWrapper.java b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/repository/timezone/DateTimeWrapper.java new file mode 100644 index 0000000000..473a8e782e --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/repository/timezone/DateTimeWrapper.java @@ -0,0 +1,131 @@ +package com.baeldung.jhipster5.repository.timezone; + +import javax.persistence.*; +import java.io.Serializable; +import java.time.*; +import java.util.Objects; + +@Entity +@Table(name = "jhi_date_time_wrapper") +public class DateTimeWrapper implements Serializable { + + private static final long serialVersionUID = 1L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "instant") + private Instant instant; + + @Column(name = "local_date_time") + private LocalDateTime localDateTime; + + @Column(name = "offset_date_time") + private OffsetDateTime offsetDateTime; + + @Column(name = "zoned_date_time") + private ZonedDateTime zonedDateTime; + + @Column(name = "local_time") + private LocalTime localTime; + + @Column(name = "offset_time") + private OffsetTime offsetTime; + + @Column(name = "local_date") + private LocalDate localDate; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Instant getInstant() { + return instant; + } + + public void setInstant(Instant instant) { + this.instant = instant; + } + + public LocalDateTime getLocalDateTime() { + return localDateTime; + } + + public void setLocalDateTime(LocalDateTime localDateTime) { + this.localDateTime = localDateTime; + } + + public OffsetDateTime getOffsetDateTime() { + return offsetDateTime; + } + + public void setOffsetDateTime(OffsetDateTime offsetDateTime) { + this.offsetDateTime = offsetDateTime; + } + + public ZonedDateTime getZonedDateTime() { + return zonedDateTime; + } + + public void setZonedDateTime(ZonedDateTime zonedDateTime) { + this.zonedDateTime = zonedDateTime; + } + + public LocalTime getLocalTime() { + return localTime; + } + + public void setLocalTime(LocalTime localTime) { + this.localTime = localTime; + } + + public OffsetTime getOffsetTime() { + return offsetTime; + } + + public void setOffsetTime(OffsetTime offsetTime) { + this.offsetTime = offsetTime; + } + + public LocalDate getLocalDate() { + return localDate; + } + + public void setLocalDate(LocalDate localDate) { + this.localDate = localDate; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + DateTimeWrapper dateTimeWrapper = (DateTimeWrapper) o; + return !(dateTimeWrapper.getId() == null || getId() == null) && Objects.equals(getId(), dateTimeWrapper.getId()); + } + + @Override + public int hashCode() { + return Objects.hashCode(getId()); + } + + @Override + public String toString() { + return "TimeZoneTest{" + + "id=" + id + + ", instant=" + instant + + ", localDateTime=" + localDateTime + + ", offsetDateTime=" + offsetDateTime + + ", zonedDateTime=" + zonedDateTime + + '}'; + } +} diff --git a/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/repository/timezone/DateTimeWrapperRepository.java b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/repository/timezone/DateTimeWrapperRepository.java new file mode 100644 index 0000000000..9c3831879f --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/repository/timezone/DateTimeWrapperRepository.java @@ -0,0 +1,12 @@ +package com.baeldung.jhipster5.repository.timezone; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +/** + * Spring Data JPA repository for the DateTimeWrapper entity. + */ +@Repository +public interface DateTimeWrapperRepository extends JpaRepository { + +} diff --git a/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/security/DomainUserDetailsServiceIntTest.java b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/security/DomainUserDetailsServiceIntTest.java new file mode 100644 index 0000000000..f11252de2b --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/security/DomainUserDetailsServiceIntTest.java @@ -0,0 +1,127 @@ +package com.baeldung.jhipster5.security; + +import com.baeldung.jhipster5.BookstoreApp; +import com.baeldung.jhipster5.domain.User; +import com.baeldung.jhipster5.repository.UserRepository; + +import org.apache.commons.lang3.RandomStringUtils; +import org.junit.Before; +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.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Locale; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Test class for DomainUserDetailsService. + * + * @see DomainUserDetailsService + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = BookstoreApp.class) +@Transactional +public class DomainUserDetailsServiceIntTest { + + private static final String USER_ONE_LOGIN = "test-user-one"; + private static final String USER_ONE_EMAIL = "test-user-one@localhost"; + private static final String USER_TWO_LOGIN = "test-user-two"; + private static final String USER_TWO_EMAIL = "test-user-two@localhost"; + private static final String USER_THREE_LOGIN = "test-user-three"; + private static final String USER_THREE_EMAIL = "test-user-three@localhost"; + + @Autowired + private UserRepository userRepository; + + @Autowired + private UserDetailsService domainUserDetailsService; + + private User userOne; + private User userTwo; + private User userThree; + + @Before + public void init() { + userOne = new User(); + userOne.setLogin(USER_ONE_LOGIN); + userOne.setPassword(RandomStringUtils.random(60)); + userOne.setActivated(true); + userOne.setEmail(USER_ONE_EMAIL); + userOne.setFirstName("userOne"); + userOne.setLastName("doe"); + userOne.setLangKey("en"); + userRepository.save(userOne); + + userTwo = new User(); + userTwo.setLogin(USER_TWO_LOGIN); + userTwo.setPassword(RandomStringUtils.random(60)); + userTwo.setActivated(true); + userTwo.setEmail(USER_TWO_EMAIL); + userTwo.setFirstName("userTwo"); + userTwo.setLastName("doe"); + userTwo.setLangKey("en"); + userRepository.save(userTwo); + + userThree = new User(); + userThree.setLogin(USER_THREE_LOGIN); + userThree.setPassword(RandomStringUtils.random(60)); + userThree.setActivated(false); + userThree.setEmail(USER_THREE_EMAIL); + userThree.setFirstName("userThree"); + userThree.setLastName("doe"); + userThree.setLangKey("en"); + userRepository.save(userThree); + } + + @Test + @Transactional + public void assertThatUserCanBeFoundByLogin() { + UserDetails userDetails = domainUserDetailsService.loadUserByUsername(USER_ONE_LOGIN); + assertThat(userDetails).isNotNull(); + assertThat(userDetails.getUsername()).isEqualTo(USER_ONE_LOGIN); + } + + @Test + @Transactional + public void assertThatUserCanBeFoundByLoginIgnoreCase() { + UserDetails userDetails = domainUserDetailsService.loadUserByUsername(USER_ONE_LOGIN.toUpperCase(Locale.ENGLISH)); + assertThat(userDetails).isNotNull(); + assertThat(userDetails.getUsername()).isEqualTo(USER_ONE_LOGIN); + } + + @Test + @Transactional + public void assertThatUserCanBeFoundByEmail() { + UserDetails userDetails = domainUserDetailsService.loadUserByUsername(USER_TWO_EMAIL); + assertThat(userDetails).isNotNull(); + assertThat(userDetails.getUsername()).isEqualTo(USER_TWO_LOGIN); + } + + @Test(expected = UsernameNotFoundException.class) + @Transactional + public void assertThatUserCanNotBeFoundByEmailIgnoreCase() { + domainUserDetailsService.loadUserByUsername(USER_TWO_EMAIL.toUpperCase(Locale.ENGLISH)); + } + + @Test + @Transactional + public void assertThatEmailIsPrioritizedOverLogin() { + UserDetails userDetails = domainUserDetailsService.loadUserByUsername(USER_ONE_EMAIL); + assertThat(userDetails).isNotNull(); + assertThat(userDetails.getUsername()).isEqualTo(USER_ONE_LOGIN); + } + + @Test(expected = UserNotActivatedException.class) + @Transactional + public void assertThatUserNotActivatedExceptionIsThrownForNotActivatedUsers() { + domainUserDetailsService.loadUserByUsername(USER_THREE_LOGIN); + } + +} diff --git a/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/security/SecurityUtilsUnitTest.java b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/security/SecurityUtilsUnitTest.java new file mode 100644 index 0000000000..b2736badd6 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/security/SecurityUtilsUnitTest.java @@ -0,0 +1,73 @@ +package com.baeldung.jhipster5.security; + +import org.junit.Test; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Test class for the SecurityUtils utility class. + * + * @see SecurityUtils + */ +public class SecurityUtilsUnitTest { + + @Test + public void testgetCurrentUserLogin() { + SecurityContext securityContext = SecurityContextHolder.createEmptyContext(); + securityContext.setAuthentication(new UsernamePasswordAuthenticationToken("admin", "admin")); + SecurityContextHolder.setContext(securityContext); + Optional login = SecurityUtils.getCurrentUserLogin(); + assertThat(login).contains("admin"); + } + + @Test + public void testgetCurrentUserJWT() { + SecurityContext securityContext = SecurityContextHolder.createEmptyContext(); + securityContext.setAuthentication(new UsernamePasswordAuthenticationToken("admin", "token")); + SecurityContextHolder.setContext(securityContext); + Optional jwt = SecurityUtils.getCurrentUserJWT(); + assertThat(jwt).contains("token"); + } + + @Test + public void testIsAuthenticated() { + SecurityContext securityContext = SecurityContextHolder.createEmptyContext(); + securityContext.setAuthentication(new UsernamePasswordAuthenticationToken("admin", "admin")); + SecurityContextHolder.setContext(securityContext); + boolean isAuthenticated = SecurityUtils.isAuthenticated(); + assertThat(isAuthenticated).isTrue(); + } + + @Test + public void testAnonymousIsNotAuthenticated() { + SecurityContext securityContext = SecurityContextHolder.createEmptyContext(); + Collection authorities = new ArrayList<>(); + authorities.add(new SimpleGrantedAuthority(AuthoritiesConstants.ANONYMOUS)); + securityContext.setAuthentication(new UsernamePasswordAuthenticationToken("anonymous", "anonymous", authorities)); + SecurityContextHolder.setContext(securityContext); + boolean isAuthenticated = SecurityUtils.isAuthenticated(); + assertThat(isAuthenticated).isFalse(); + } + + @Test + public void testIsCurrentUserInRole() { + SecurityContext securityContext = SecurityContextHolder.createEmptyContext(); + Collection authorities = new ArrayList<>(); + authorities.add(new SimpleGrantedAuthority(AuthoritiesConstants.USER)); + securityContext.setAuthentication(new UsernamePasswordAuthenticationToken("user", "user", authorities)); + SecurityContextHolder.setContext(securityContext); + + assertThat(SecurityUtils.isCurrentUserInRole(AuthoritiesConstants.USER)).isTrue(); + assertThat(SecurityUtils.isCurrentUserInRole(AuthoritiesConstants.ADMIN)).isFalse(); + } + +} diff --git a/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/security/jwt/JWTFilterTest.java b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/security/jwt/JWTFilterTest.java new file mode 100644 index 0000000000..b3de21819b --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/security/jwt/JWTFilterTest.java @@ -0,0 +1,115 @@ +package com.baeldung.jhipster5.security.jwt; + +import com.baeldung.jhipster5.security.AuthoritiesConstants; +import io.github.jhipster.config.JHipsterProperties; +import io.jsonwebtoken.io.Decoders; +import io.jsonwebtoken.security.Keys; + +import org.junit.Before; +import org.junit.Test; +import org.springframework.http.HttpStatus; +import org.springframework.mock.web.MockFilterChain; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.test.util.ReflectionTestUtils; + +import java.util.Collections; + +import static org.assertj.core.api.Assertions.assertThat; + +public class JWTFilterTest { + + private TokenProvider tokenProvider; + + private JWTFilter jwtFilter; + + @Before + public void setup() { + JHipsterProperties jHipsterProperties = new JHipsterProperties(); + tokenProvider = new TokenProvider(jHipsterProperties); + ReflectionTestUtils.setField(tokenProvider, "key", + Keys.hmacShaKeyFor(Decoders.BASE64 + .decode("fd54a45s65fds737b9aafcb3412e07ed99b267f33413274720ddbb7f6c5e64e9f14075f2d7ed041592f0b7657baf8"))); + + ReflectionTestUtils.setField(tokenProvider, "tokenValidityInMilliseconds", 60000); + jwtFilter = new JWTFilter(tokenProvider); + SecurityContextHolder.getContext().setAuthentication(null); + } + + @Test + public void testJWTFilter() throws Exception { + UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( + "test-user", + "test-password", + Collections.singletonList(new SimpleGrantedAuthority(AuthoritiesConstants.USER)) + ); + String jwt = tokenProvider.createToken(authentication, false); + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addHeader(JWTFilter.AUTHORIZATION_HEADER, "Bearer " + jwt); + request.setRequestURI("/api/test"); + MockHttpServletResponse response = new MockHttpServletResponse(); + MockFilterChain filterChain = new MockFilterChain(); + jwtFilter.doFilter(request, response, filterChain); + assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value()); + assertThat(SecurityContextHolder.getContext().getAuthentication().getName()).isEqualTo("test-user"); + assertThat(SecurityContextHolder.getContext().getAuthentication().getCredentials().toString()).isEqualTo(jwt); + } + + @Test + public void testJWTFilterInvalidToken() throws Exception { + String jwt = "wrong_jwt"; + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addHeader(JWTFilter.AUTHORIZATION_HEADER, "Bearer " + jwt); + request.setRequestURI("/api/test"); + MockHttpServletResponse response = new MockHttpServletResponse(); + MockFilterChain filterChain = new MockFilterChain(); + jwtFilter.doFilter(request, response, filterChain); + assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value()); + assertThat(SecurityContextHolder.getContext().getAuthentication()).isNull(); + } + + @Test + public void testJWTFilterMissingAuthorization() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setRequestURI("/api/test"); + MockHttpServletResponse response = new MockHttpServletResponse(); + MockFilterChain filterChain = new MockFilterChain(); + jwtFilter.doFilter(request, response, filterChain); + assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value()); + assertThat(SecurityContextHolder.getContext().getAuthentication()).isNull(); + } + + @Test + public void testJWTFilterMissingToken() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addHeader(JWTFilter.AUTHORIZATION_HEADER, "Bearer "); + request.setRequestURI("/api/test"); + MockHttpServletResponse response = new MockHttpServletResponse(); + MockFilterChain filterChain = new MockFilterChain(); + jwtFilter.doFilter(request, response, filterChain); + assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value()); + assertThat(SecurityContextHolder.getContext().getAuthentication()).isNull(); + } + + @Test + public void testJWTFilterWrongScheme() throws Exception { + UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( + "test-user", + "test-password", + Collections.singletonList(new SimpleGrantedAuthority(AuthoritiesConstants.USER)) + ); + String jwt = tokenProvider.createToken(authentication, false); + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addHeader(JWTFilter.AUTHORIZATION_HEADER, "Basic " + jwt); + request.setRequestURI("/api/test"); + MockHttpServletResponse response = new MockHttpServletResponse(); + MockFilterChain filterChain = new MockFilterChain(); + jwtFilter.doFilter(request, response, filterChain); + assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value()); + assertThat(SecurityContextHolder.getContext().getAuthentication()).isNull(); + } + +} diff --git a/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/security/jwt/TokenProviderTest.java b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/security/jwt/TokenProviderTest.java new file mode 100644 index 0000000000..11fcfddbf9 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/security/jwt/TokenProviderTest.java @@ -0,0 +1,111 @@ +package com.baeldung.jhipster5.security.jwt; + +import com.baeldung.jhipster5.security.AuthoritiesConstants; + +import java.security.Key; +import java.util.*; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.test.util.ReflectionTestUtils; + +import io.github.jhipster.config.JHipsterProperties; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import io.jsonwebtoken.io.Decoders; +import io.jsonwebtoken.security.Keys; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TokenProviderTest { + + private final long ONE_MINUTE = 60000; + private Key key; + private JHipsterProperties jHipsterProperties; + private TokenProvider tokenProvider; + + @Before + public void setup() { + jHipsterProperties = Mockito.mock(JHipsterProperties.class); + tokenProvider = new TokenProvider(jHipsterProperties); + key = Keys.hmacShaKeyFor(Decoders.BASE64 + .decode("fd54a45s65fds737b9aafcb3412e07ed99b267f33413274720ddbb7f6c5e64e9f14075f2d7ed041592f0b7657baf8")); + + ReflectionTestUtils.setField(tokenProvider, "key", key); + ReflectionTestUtils.setField(tokenProvider, "tokenValidityInMilliseconds", ONE_MINUTE); + } + + @Test + public void testReturnFalseWhenJWThasInvalidSignature() { + boolean isTokenValid = tokenProvider.validateToken(createTokenWithDifferentSignature()); + + assertThat(isTokenValid).isEqualTo(false); + } + + @Test + public void testReturnFalseWhenJWTisMalformed() { + Authentication authentication = createAuthentication(); + String token = tokenProvider.createToken(authentication, false); + String invalidToken = token.substring(1); + boolean isTokenValid = tokenProvider.validateToken(invalidToken); + + assertThat(isTokenValid).isEqualTo(false); + } + + @Test + public void testReturnFalseWhenJWTisExpired() { + ReflectionTestUtils.setField(tokenProvider, "tokenValidityInMilliseconds", -ONE_MINUTE); + + Authentication authentication = createAuthentication(); + String token = tokenProvider.createToken(authentication, false); + + boolean isTokenValid = tokenProvider.validateToken(token); + + assertThat(isTokenValid).isEqualTo(false); + } + + @Test + public void testReturnFalseWhenJWTisUnsupported() { + String unsupportedToken = createUnsupportedToken(); + + boolean isTokenValid = tokenProvider.validateToken(unsupportedToken); + + assertThat(isTokenValid).isEqualTo(false); + } + + @Test + public void testReturnFalseWhenJWTisInvalid() { + boolean isTokenValid = tokenProvider.validateToken(""); + + assertThat(isTokenValid).isEqualTo(false); + } + + private Authentication createAuthentication() { + Collection authorities = new ArrayList<>(); + authorities.add(new SimpleGrantedAuthority(AuthoritiesConstants.ANONYMOUS)); + return new UsernamePasswordAuthenticationToken("anonymous", "anonymous", authorities); + } + + private String createUnsupportedToken() { + return Jwts.builder() + .setPayload("payload") + .signWith(key, SignatureAlgorithm.HS512) + .compact(); + } + + private String createTokenWithDifferentSignature() { + Key otherKey = Keys.hmacShaKeyFor(Decoders.BASE64 + .decode("Xfd54a45s65fds737b9aafcb3412e07ed99b267f33413274720ddbb7f6c5e64e9f14075f2d7ed041592f0b7657baf8")); + + return Jwts.builder() + .setSubject("anonymous") + .signWith(otherKey, SignatureAlgorithm.HS512) + .setExpiration(new Date(new Date().getTime() + ONE_MINUTE)) + .compact(); + } +} diff --git a/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/service/MailServiceIntTest.java b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/service/MailServiceIntTest.java new file mode 100644 index 0000000000..4bde3276f5 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/service/MailServiceIntTest.java @@ -0,0 +1,187 @@ +package com.baeldung.jhipster5.service; +import com.baeldung.jhipster5.config.Constants; + +import com.baeldung.jhipster5.BookstoreApp; +import com.baeldung.jhipster5.domain.User; +import io.github.jhipster.config.JHipsterProperties; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.MessageSource; +import org.springframework.mail.MailSendException; +import org.springframework.mail.javamail.JavaMailSenderImpl; +import org.springframework.test.context.junit4.SpringRunner; +import org.thymeleaf.spring5.SpringTemplateEngine; + +import javax.mail.Multipart; +import javax.mail.internet.MimeBodyPart; +import javax.mail.internet.MimeMessage; +import javax.mail.internet.MimeMultipart; +import java.io.ByteArrayOutputStream; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = BookstoreApp.class) +public class MailServiceIntTest { + + @Autowired + private JHipsterProperties jHipsterProperties; + + @Autowired + private MessageSource messageSource; + + @Autowired + private SpringTemplateEngine templateEngine; + + @Spy + private JavaMailSenderImpl javaMailSender; + + @Captor + private ArgumentCaptor messageCaptor; + + private MailService mailService; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + doNothing().when(javaMailSender).send(any(MimeMessage.class)); + mailService = new MailService(jHipsterProperties, javaMailSender, messageSource, templateEngine); + } + + @Test + public void testSendEmail() throws Exception { + mailService.sendEmail("john.doe@example.com", "testSubject", "testContent", false, false); + verify(javaMailSender).send(messageCaptor.capture()); + MimeMessage message = messageCaptor.getValue(); + assertThat(message.getSubject()).isEqualTo("testSubject"); + assertThat(message.getAllRecipients()[0].toString()).isEqualTo("john.doe@example.com"); + assertThat(message.getFrom()[0].toString()).isEqualTo("test@localhost"); + assertThat(message.getContent()).isInstanceOf(String.class); + assertThat(message.getContent().toString()).isEqualTo("testContent"); + assertThat(message.getDataHandler().getContentType()).isEqualTo("text/plain; charset=UTF-8"); + } + + @Test + public void testSendHtmlEmail() throws Exception { + mailService.sendEmail("john.doe@example.com", "testSubject", "testContent", false, true); + verify(javaMailSender).send(messageCaptor.capture()); + MimeMessage message = messageCaptor.getValue(); + assertThat(message.getSubject()).isEqualTo("testSubject"); + assertThat(message.getAllRecipients()[0].toString()).isEqualTo("john.doe@example.com"); + assertThat(message.getFrom()[0].toString()).isEqualTo("test@localhost"); + assertThat(message.getContent()).isInstanceOf(String.class); + assertThat(message.getContent().toString()).isEqualTo("testContent"); + assertThat(message.getDataHandler().getContentType()).isEqualTo("text/html;charset=UTF-8"); + } + + @Test + public void testSendMultipartEmail() throws Exception { + mailService.sendEmail("john.doe@example.com", "testSubject", "testContent", true, false); + verify(javaMailSender).send(messageCaptor.capture()); + MimeMessage message = messageCaptor.getValue(); + MimeMultipart mp = (MimeMultipart) message.getContent(); + MimeBodyPart part = (MimeBodyPart) ((MimeMultipart) mp.getBodyPart(0).getContent()).getBodyPart(0); + ByteArrayOutputStream aos = new ByteArrayOutputStream(); + part.writeTo(aos); + assertThat(message.getSubject()).isEqualTo("testSubject"); + assertThat(message.getAllRecipients()[0].toString()).isEqualTo("john.doe@example.com"); + assertThat(message.getFrom()[0].toString()).isEqualTo("test@localhost"); + assertThat(message.getContent()).isInstanceOf(Multipart.class); + assertThat(aos.toString()).isEqualTo("\r\ntestContent"); + assertThat(part.getDataHandler().getContentType()).isEqualTo("text/plain; charset=UTF-8"); + } + + @Test + public void testSendMultipartHtmlEmail() throws Exception { + mailService.sendEmail("john.doe@example.com", "testSubject", "testContent", true, true); + verify(javaMailSender).send(messageCaptor.capture()); + MimeMessage message = messageCaptor.getValue(); + MimeMultipart mp = (MimeMultipart) message.getContent(); + MimeBodyPart part = (MimeBodyPart) ((MimeMultipart) mp.getBodyPart(0).getContent()).getBodyPart(0); + ByteArrayOutputStream aos = new ByteArrayOutputStream(); + part.writeTo(aos); + assertThat(message.getSubject()).isEqualTo("testSubject"); + assertThat(message.getAllRecipients()[0].toString()).isEqualTo("john.doe@example.com"); + assertThat(message.getFrom()[0].toString()).isEqualTo("test@localhost"); + assertThat(message.getContent()).isInstanceOf(Multipart.class); + assertThat(aos.toString()).isEqualTo("\r\ntestContent"); + assertThat(part.getDataHandler().getContentType()).isEqualTo("text/html;charset=UTF-8"); + } + + @Test + public void testSendEmailFromTemplate() throws Exception { + User user = new User(); + user.setLogin("john"); + user.setEmail("john.doe@example.com"); + user.setLangKey("en"); + mailService.sendEmailFromTemplate(user, "mail/testEmail", "email.test.title"); + verify(javaMailSender).send(messageCaptor.capture()); + MimeMessage message = messageCaptor.getValue(); + assertThat(message.getSubject()).isEqualTo("test title"); + assertThat(message.getAllRecipients()[0].toString()).isEqualTo(user.getEmail()); + assertThat(message.getFrom()[0].toString()).isEqualTo("test@localhost"); + assertThat(message.getContent().toString()).isEqualToNormalizingNewlines("test title, http://127.0.0.1:8080, john\n"); + assertThat(message.getDataHandler().getContentType()).isEqualTo("text/html;charset=UTF-8"); + } + + @Test + public void testSendActivationEmail() throws Exception { + User user = new User(); + user.setLangKey(Constants.DEFAULT_LANGUAGE); + user.setLogin("john"); + user.setEmail("john.doe@example.com"); + mailService.sendActivationEmail(user); + verify(javaMailSender).send(messageCaptor.capture()); + MimeMessage message = messageCaptor.getValue(); + assertThat(message.getAllRecipients()[0].toString()).isEqualTo(user.getEmail()); + assertThat(message.getFrom()[0].toString()).isEqualTo("test@localhost"); + assertThat(message.getContent().toString()).isNotEmpty(); + assertThat(message.getDataHandler().getContentType()).isEqualTo("text/html;charset=UTF-8"); + } + + @Test + public void testCreationEmail() throws Exception { + User user = new User(); + user.setLangKey(Constants.DEFAULT_LANGUAGE); + user.setLogin("john"); + user.setEmail("john.doe@example.com"); + mailService.sendCreationEmail(user); + verify(javaMailSender).send(messageCaptor.capture()); + MimeMessage message = messageCaptor.getValue(); + assertThat(message.getAllRecipients()[0].toString()).isEqualTo(user.getEmail()); + assertThat(message.getFrom()[0].toString()).isEqualTo("test@localhost"); + assertThat(message.getContent().toString()).isNotEmpty(); + assertThat(message.getDataHandler().getContentType()).isEqualTo("text/html;charset=UTF-8"); + } + + @Test + public void testSendPasswordResetMail() throws Exception { + User user = new User(); + user.setLangKey(Constants.DEFAULT_LANGUAGE); + user.setLogin("john"); + user.setEmail("john.doe@example.com"); + mailService.sendPasswordResetMail(user); + verify(javaMailSender).send(messageCaptor.capture()); + MimeMessage message = messageCaptor.getValue(); + assertThat(message.getAllRecipients()[0].toString()).isEqualTo(user.getEmail()); + assertThat(message.getFrom()[0].toString()).isEqualTo("test@localhost"); + assertThat(message.getContent().toString()).isNotEmpty(); + assertThat(message.getDataHandler().getContentType()).isEqualTo("text/html;charset=UTF-8"); + } + + @Test + public void testSendEmailWithException() throws Exception { + doThrow(MailSendException.class).when(javaMailSender).send(any(MimeMessage.class)); + mailService.sendEmail("john.doe@example.com", "testSubject", "testContent", false, false); + } + +} diff --git a/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/service/UserServiceIntTest.java b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/service/UserServiceIntTest.java new file mode 100644 index 0000000000..81034c2793 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/service/UserServiceIntTest.java @@ -0,0 +1,192 @@ +package com.baeldung.jhipster5.service; + +import com.baeldung.jhipster5.BookstoreApp; +import com.baeldung.jhipster5.config.Constants; +import com.baeldung.jhipster5.domain.User; +import com.baeldung.jhipster5.repository.UserRepository; +import com.baeldung.jhipster5.service.dto.UserDTO; +import com.baeldung.jhipster5.service.util.RandomUtil; + +import org.apache.commons.lang3.RandomStringUtils; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.data.auditing.AuditingHandler; +import org.springframework.data.auditing.DateTimeProvider; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.transaction.annotation.Transactional; + +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.time.LocalDateTime; +import java.util.Optional; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; + +/** + * Test class for the UserResource REST controller. + * + * @see UserService + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = BookstoreApp.class) +@Transactional +public class UserServiceIntTest { + + @Autowired + private UserRepository userRepository; + + @Autowired + private UserService userService; + + @Autowired + private AuditingHandler auditingHandler; + + @Mock + DateTimeProvider dateTimeProvider; + + private User user; + + @Before + public void init() { + user = new User(); + user.setLogin("johndoe"); + user.setPassword(RandomStringUtils.random(60)); + user.setActivated(true); + user.setEmail("johndoe@localhost"); + user.setFirstName("john"); + user.setLastName("doe"); + user.setImageUrl("http://placehold.it/50x50"); + user.setLangKey("en"); + + when(dateTimeProvider.getNow()).thenReturn(Optional.of(LocalDateTime.now())); + auditingHandler.setDateTimeProvider(dateTimeProvider); + } + + @Test + @Transactional + public void assertThatUserMustExistToResetPassword() { + userRepository.saveAndFlush(user); + Optional maybeUser = userService.requestPasswordReset("invalid.login@localhost"); + assertThat(maybeUser).isNotPresent(); + + maybeUser = userService.requestPasswordReset(user.getEmail()); + assertThat(maybeUser).isPresent(); + assertThat(maybeUser.orElse(null).getEmail()).isEqualTo(user.getEmail()); + assertThat(maybeUser.orElse(null).getResetDate()).isNotNull(); + assertThat(maybeUser.orElse(null).getResetKey()).isNotNull(); + } + + @Test + @Transactional + public void assertThatOnlyActivatedUserCanRequestPasswordReset() { + user.setActivated(false); + userRepository.saveAndFlush(user); + + Optional maybeUser = userService.requestPasswordReset(user.getLogin()); + assertThat(maybeUser).isNotPresent(); + userRepository.delete(user); + } + + @Test + @Transactional + public void assertThatResetKeyMustNotBeOlderThan24Hours() { + Instant daysAgo = Instant.now().minus(25, ChronoUnit.HOURS); + String resetKey = RandomUtil.generateResetKey(); + user.setActivated(true); + user.setResetDate(daysAgo); + user.setResetKey(resetKey); + userRepository.saveAndFlush(user); + + Optional maybeUser = userService.completePasswordReset("johndoe2", user.getResetKey()); + assertThat(maybeUser).isNotPresent(); + userRepository.delete(user); + } + + @Test + @Transactional + public void assertThatResetKeyMustBeValid() { + Instant daysAgo = Instant.now().minus(25, ChronoUnit.HOURS); + user.setActivated(true); + user.setResetDate(daysAgo); + user.setResetKey("1234"); + userRepository.saveAndFlush(user); + + Optional maybeUser = userService.completePasswordReset("johndoe2", user.getResetKey()); + assertThat(maybeUser).isNotPresent(); + userRepository.delete(user); + } + + @Test + @Transactional + public void assertThatUserCanResetPassword() { + String oldPassword = user.getPassword(); + Instant daysAgo = Instant.now().minus(2, ChronoUnit.HOURS); + String resetKey = RandomUtil.generateResetKey(); + user.setActivated(true); + user.setResetDate(daysAgo); + user.setResetKey(resetKey); + userRepository.saveAndFlush(user); + + Optional maybeUser = userService.completePasswordReset("johndoe2", user.getResetKey()); + assertThat(maybeUser).isPresent(); + assertThat(maybeUser.orElse(null).getResetDate()).isNull(); + assertThat(maybeUser.orElse(null).getResetKey()).isNull(); + assertThat(maybeUser.orElse(null).getPassword()).isNotEqualTo(oldPassword); + + userRepository.delete(user); + } + + @Test + @Transactional + public void testFindNotActivatedUsersByCreationDateBefore() { + Instant now = Instant.now(); + when(dateTimeProvider.getNow()).thenReturn(Optional.of(now.minus(4, ChronoUnit.DAYS))); + user.setActivated(false); + User dbUser = userRepository.saveAndFlush(user); + dbUser.setCreatedDate(now.minus(4, ChronoUnit.DAYS)); + userRepository.saveAndFlush(user); + List users = userRepository.findAllByActivatedIsFalseAndCreatedDateBefore(now.minus(3, ChronoUnit.DAYS)); + assertThat(users).isNotEmpty(); + userService.removeNotActivatedUsers(); + users = userRepository.findAllByActivatedIsFalseAndCreatedDateBefore(now.minus(3, ChronoUnit.DAYS)); + assertThat(users).isEmpty(); + } + + @Test + @Transactional + public void assertThatAnonymousUserIsNotGet() { + user.setLogin(Constants.ANONYMOUS_USER); + if (!userRepository.findOneByLogin(Constants.ANONYMOUS_USER).isPresent()) { + userRepository.saveAndFlush(user); + } + final PageRequest pageable = PageRequest.of(0, (int) userRepository.count()); + final Page allManagedUsers = userService.getAllManagedUsers(pageable); + assertThat(allManagedUsers.getContent().stream() + .noneMatch(user -> Constants.ANONYMOUS_USER.equals(user.getLogin()))) + .isTrue(); + } + + + @Test + @Transactional + public void testRemoveNotActivatedUsers() { + // custom "now" for audit to use as creation date + when(dateTimeProvider.getNow()).thenReturn(Optional.of(Instant.now().minus(30, ChronoUnit.DAYS))); + + user.setActivated(false); + userRepository.saveAndFlush(user); + + assertThat(userRepository.findOneByLogin("johndoe")).isPresent(); + userService.removeNotActivatedUsers(); + assertThat(userRepository.findOneByLogin("johndoe")).isNotPresent(); + } + +} diff --git a/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/service/mapper/UserMapperTest.java b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/service/mapper/UserMapperTest.java new file mode 100644 index 0000000000..3d66fa5813 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/service/mapper/UserMapperTest.java @@ -0,0 +1,150 @@ +package com.baeldung.jhipster5.service.mapper; + + +import com.baeldung.jhipster5.BookstoreApp; +import com.baeldung.jhipster5.domain.User; +import com.baeldung.jhipster5.service.dto.UserDTO; +import org.apache.commons.lang3.RandomStringUtils; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Test class for the UserMapper. + * + * @see UserMapper + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = BookstoreApp.class) +public class UserMapperTest { + + private static final String DEFAULT_LOGIN = "johndoe"; + + @Autowired + private UserMapper userMapper; + + private User user; + private UserDTO userDto; + + private static final Long DEFAULT_ID = 1L; + + @Before + public void init() { + user = new User(); + user.setLogin(DEFAULT_LOGIN); + user.setPassword(RandomStringUtils.random(60)); + user.setActivated(true); + user.setEmail("johndoe@localhost"); + user.setFirstName("john"); + user.setLastName("doe"); + user.setImageUrl("image_url"); + user.setLangKey("en"); + + userDto = new UserDTO(user); + } + + @Test + public void usersToUserDTOsShouldMapOnlyNonNullUsers(){ + List users = new ArrayList<>(); + users.add(user); + users.add(null); + + List userDTOS = userMapper.usersToUserDTOs(users); + + assertThat(userDTOS).isNotEmpty(); + assertThat(userDTOS).size().isEqualTo(1); + } + + @Test + public void userDTOsToUsersShouldMapOnlyNonNullUsers(){ + List usersDto = new ArrayList<>(); + usersDto.add(userDto); + usersDto.add(null); + + List users = userMapper.userDTOsToUsers(usersDto); + + assertThat(users).isNotEmpty(); + assertThat(users).size().isEqualTo(1); + } + + @Test + public void userDTOsToUsersWithAuthoritiesStringShouldMapToUsersWithAuthoritiesDomain(){ + Set authoritiesAsString = new HashSet<>(); + authoritiesAsString.add("ADMIN"); + userDto.setAuthorities(authoritiesAsString); + + List usersDto = new ArrayList<>(); + usersDto.add(userDto); + + List users = userMapper.userDTOsToUsers(usersDto); + + assertThat(users).isNotEmpty(); + assertThat(users).size().isEqualTo(1); + assertThat(users.get(0).getAuthorities()).isNotNull(); + assertThat(users.get(0).getAuthorities()).isNotEmpty(); + assertThat(users.get(0).getAuthorities().iterator().next().getName()).isEqualTo("ADMIN"); + } + + @Test + public void userDTOsToUsersMapWithNullAuthoritiesStringShouldReturnUserWithEmptyAuthorities(){ + userDto.setAuthorities(null); + + List usersDto = new ArrayList<>(); + usersDto.add(userDto); + + List users = userMapper.userDTOsToUsers(usersDto); + + assertThat(users).isNotEmpty(); + assertThat(users).size().isEqualTo(1); + assertThat(users.get(0).getAuthorities()).isNotNull(); + assertThat(users.get(0).getAuthorities()).isEmpty(); + } + + @Test + public void userDTOToUserMapWithAuthoritiesStringShouldReturnUserWithAuthorities(){ + Set authoritiesAsString = new HashSet<>(); + authoritiesAsString.add("ADMIN"); + userDto.setAuthorities(authoritiesAsString); + + userDto.setAuthorities(authoritiesAsString); + + User user = userMapper.userDTOToUser(userDto); + + assertThat(user).isNotNull(); + assertThat(user.getAuthorities()).isNotNull(); + assertThat(user.getAuthorities()).isNotEmpty(); + assertThat(user.getAuthorities().iterator().next().getName()).isEqualTo("ADMIN"); + } + + @Test + public void userDTOToUserMapWithNullAuthoritiesStringShouldReturnUserWithEmptyAuthorities(){ + userDto.setAuthorities(null); + + User user = userMapper.userDTOToUser(userDto); + + assertThat(user).isNotNull(); + assertThat(user.getAuthorities()).isNotNull(); + assertThat(user.getAuthorities()).isEmpty(); + } + + @Test + public void userDTOToUserMapWithNullUserShouldReturnNull(){ + assertThat(userMapper.userDTOToUser(null)).isNull(); + } + + @Test + public void testUserFromId() { + assertThat(userMapper.userFromId(DEFAULT_ID).getId()).isEqualTo(DEFAULT_ID); + assertThat(userMapper.userFromId(null)).isNull(); + } +} diff --git a/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/AccountResourceIntTest.java b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/AccountResourceIntTest.java new file mode 100644 index 0000000000..6db284a87f --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/AccountResourceIntTest.java @@ -0,0 +1,818 @@ +package com.baeldung.jhipster5.web.rest; + +import com.baeldung.jhipster5.BookstoreApp; +import com.baeldung.jhipster5.config.Constants; +import com.baeldung.jhipster5.domain.Authority; +import com.baeldung.jhipster5.domain.User; +import com.baeldung.jhipster5.repository.AuthorityRepository; +import com.baeldung.jhipster5.repository.UserRepository; +import com.baeldung.jhipster5.security.AuthoritiesConstants; +import com.baeldung.jhipster5.service.MailService; +import com.baeldung.jhipster5.service.UserService; +import com.baeldung.jhipster5.service.dto.PasswordChangeDTO; +import com.baeldung.jhipster5.service.dto.UserDTO; +import com.baeldung.jhipster5.web.rest.errors.ExceptionTranslator; +import com.baeldung.jhipster5.web.rest.vm.KeyAndPasswordVM; +import com.baeldung.jhipster5.web.rest.vm.ManagedUserVM; +import org.apache.commons.lang3.RandomStringUtils; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.transaction.annotation.Transactional; + +import java.time.Instant; +import java.util.*; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +/** + * Test class for the AccountResource REST controller. + * + * @see AccountResource + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = BookstoreApp.class) +public class AccountResourceIntTest { + + @Autowired + private UserRepository userRepository; + + @Autowired + private AuthorityRepository authorityRepository; + + @Autowired + private UserService userService; + + @Autowired + private PasswordEncoder passwordEncoder; + + @Autowired + private HttpMessageConverter[] httpMessageConverters; + + @Autowired + private ExceptionTranslator exceptionTranslator; + + @Mock + private UserService mockUserService; + + @Mock + private MailService mockMailService; + + private MockMvc restMvc; + + private MockMvc restUserMockMvc; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + doNothing().when(mockMailService).sendActivationEmail(any()); + AccountResource accountResource = + new AccountResource(userRepository, userService, mockMailService); + + AccountResource accountUserMockResource = + new AccountResource(userRepository, mockUserService, mockMailService); + this.restMvc = MockMvcBuilders.standaloneSetup(accountResource) + .setMessageConverters(httpMessageConverters) + .setControllerAdvice(exceptionTranslator) + .build(); + this.restUserMockMvc = MockMvcBuilders.standaloneSetup(accountUserMockResource) + .setControllerAdvice(exceptionTranslator) + .build(); + } + + @Test + public void testNonAuthenticatedUser() throws Exception { + restUserMockMvc.perform(get("/api/authenticate") + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(content().string("")); + } + + @Test + public void testAuthenticatedUser() throws Exception { + restUserMockMvc.perform(get("/api/authenticate") + .with(request -> { + request.setRemoteUser("test"); + return request; + }) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(content().string("test")); + } + + @Test + public void testGetExistingAccount() throws Exception { + Set authorities = new HashSet<>(); + Authority authority = new Authority(); + authority.setName(AuthoritiesConstants.ADMIN); + authorities.add(authority); + + User user = new User(); + user.setLogin("test"); + user.setFirstName("john"); + user.setLastName("doe"); + user.setEmail("john.doe@jhipster.com"); + user.setImageUrl("http://placehold.it/50x50"); + user.setLangKey("en"); + user.setAuthorities(authorities); + when(mockUserService.getUserWithAuthorities()).thenReturn(Optional.of(user)); + + restUserMockMvc.perform(get("/api/account") + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)) + .andExpect(jsonPath("$.login").value("test")) + .andExpect(jsonPath("$.firstName").value("john")) + .andExpect(jsonPath("$.lastName").value("doe")) + .andExpect(jsonPath("$.email").value("john.doe@jhipster.com")) + .andExpect(jsonPath("$.imageUrl").value("http://placehold.it/50x50")) + .andExpect(jsonPath("$.langKey").value("en")) + .andExpect(jsonPath("$.authorities").value(AuthoritiesConstants.ADMIN)); + } + + @Test + public void testGetUnknownAccount() throws Exception { + when(mockUserService.getUserWithAuthorities()).thenReturn(Optional.empty()); + + restUserMockMvc.perform(get("/api/account") + .accept(MediaType.APPLICATION_PROBLEM_JSON)) + .andExpect(status().isInternalServerError()); + } + + @Test + @Transactional + public void testRegisterValid() throws Exception { + ManagedUserVM validUser = new ManagedUserVM(); + validUser.setLogin("test-register-valid"); + validUser.setPassword("password"); + validUser.setFirstName("Alice"); + validUser.setLastName("Test"); + validUser.setEmail("test-register-valid@example.com"); + validUser.setImageUrl("http://placehold.it/50x50"); + validUser.setLangKey(Constants.DEFAULT_LANGUAGE); + validUser.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); + assertThat(userRepository.findOneByLogin("test-register-valid").isPresent()).isFalse(); + + restMvc.perform( + post("/api/register") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(validUser))) + .andExpect(status().isCreated()); + + assertThat(userRepository.findOneByLogin("test-register-valid").isPresent()).isTrue(); + } + + @Test + @Transactional + public void testRegisterInvalidLogin() throws Exception { + ManagedUserVM invalidUser = new ManagedUserVM(); + invalidUser.setLogin("funky-log!n");// <-- invalid + invalidUser.setPassword("password"); + invalidUser.setFirstName("Funky"); + invalidUser.setLastName("One"); + invalidUser.setEmail("funky@example.com"); + invalidUser.setActivated(true); + invalidUser.setImageUrl("http://placehold.it/50x50"); + invalidUser.setLangKey(Constants.DEFAULT_LANGUAGE); + invalidUser.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); + + restUserMockMvc.perform( + post("/api/register") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(invalidUser))) + .andExpect(status().isBadRequest()); + + Optional user = userRepository.findOneByEmailIgnoreCase("funky@example.com"); + assertThat(user.isPresent()).isFalse(); + } + + @Test + @Transactional + public void testRegisterInvalidEmail() throws Exception { + ManagedUserVM invalidUser = new ManagedUserVM(); + invalidUser.setLogin("bob"); + invalidUser.setPassword("password"); + invalidUser.setFirstName("Bob"); + invalidUser.setLastName("Green"); + invalidUser.setEmail("invalid");// <-- invalid + invalidUser.setActivated(true); + invalidUser.setImageUrl("http://placehold.it/50x50"); + invalidUser.setLangKey(Constants.DEFAULT_LANGUAGE); + invalidUser.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); + + restUserMockMvc.perform( + post("/api/register") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(invalidUser))) + .andExpect(status().isBadRequest()); + + Optional user = userRepository.findOneByLogin("bob"); + assertThat(user.isPresent()).isFalse(); + } + + @Test + @Transactional + public void testRegisterInvalidPassword() throws Exception { + ManagedUserVM invalidUser = new ManagedUserVM(); + invalidUser.setLogin("bob"); + invalidUser.setPassword("123");// password with only 3 digits + invalidUser.setFirstName("Bob"); + invalidUser.setLastName("Green"); + invalidUser.setEmail("bob@example.com"); + invalidUser.setActivated(true); + invalidUser.setImageUrl("http://placehold.it/50x50"); + invalidUser.setLangKey(Constants.DEFAULT_LANGUAGE); + invalidUser.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); + + restUserMockMvc.perform( + post("/api/register") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(invalidUser))) + .andExpect(status().isBadRequest()); + + Optional user = userRepository.findOneByLogin("bob"); + assertThat(user.isPresent()).isFalse(); + } + + @Test + @Transactional + public void testRegisterNullPassword() throws Exception { + ManagedUserVM invalidUser = new ManagedUserVM(); + invalidUser.setLogin("bob"); + invalidUser.setPassword(null);// invalid null password + invalidUser.setFirstName("Bob"); + invalidUser.setLastName("Green"); + invalidUser.setEmail("bob@example.com"); + invalidUser.setActivated(true); + invalidUser.setImageUrl("http://placehold.it/50x50"); + invalidUser.setLangKey(Constants.DEFAULT_LANGUAGE); + invalidUser.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); + + restUserMockMvc.perform( + post("/api/register") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(invalidUser))) + .andExpect(status().isBadRequest()); + + Optional user = userRepository.findOneByLogin("bob"); + assertThat(user.isPresent()).isFalse(); + } + + @Test + @Transactional + public void testRegisterDuplicateLogin() throws Exception { + // First registration + ManagedUserVM firstUser = new ManagedUserVM(); + firstUser.setLogin("alice"); + firstUser.setPassword("password"); + firstUser.setFirstName("Alice"); + firstUser.setLastName("Something"); + firstUser.setEmail("alice@example.com"); + firstUser.setImageUrl("http://placehold.it/50x50"); + firstUser.setLangKey(Constants.DEFAULT_LANGUAGE); + firstUser.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); + + // Duplicate login, different email + ManagedUserVM secondUser = new ManagedUserVM(); + secondUser.setLogin(firstUser.getLogin()); + secondUser.setPassword(firstUser.getPassword()); + secondUser.setFirstName(firstUser.getFirstName()); + secondUser.setLastName(firstUser.getLastName()); + secondUser.setEmail("alice2@example.com"); + secondUser.setImageUrl(firstUser.getImageUrl()); + secondUser.setLangKey(firstUser.getLangKey()); + secondUser.setCreatedBy(firstUser.getCreatedBy()); + secondUser.setCreatedDate(firstUser.getCreatedDate()); + secondUser.setLastModifiedBy(firstUser.getLastModifiedBy()); + secondUser.setLastModifiedDate(firstUser.getLastModifiedDate()); + secondUser.setAuthorities(new HashSet<>(firstUser.getAuthorities())); + + // First user + restMvc.perform( + post("/api/register") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(firstUser))) + .andExpect(status().isCreated()); + + // Second (non activated) user + restMvc.perform( + post("/api/register") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(secondUser))) + .andExpect(status().isCreated()); + + Optional testUser = userRepository.findOneByEmailIgnoreCase("alice2@example.com"); + assertThat(testUser.isPresent()).isTrue(); + testUser.get().setActivated(true); + userRepository.save(testUser.get()); + + // Second (already activated) user + restMvc.perform( + post("/api/register") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(secondUser))) + .andExpect(status().is4xxClientError()); + } + + @Test + @Transactional + public void testRegisterDuplicateEmail() throws Exception { + // First user + ManagedUserVM firstUser = new ManagedUserVM(); + firstUser.setLogin("test-register-duplicate-email"); + firstUser.setPassword("password"); + firstUser.setFirstName("Alice"); + firstUser.setLastName("Test"); + firstUser.setEmail("test-register-duplicate-email@example.com"); + firstUser.setImageUrl("http://placehold.it/50x50"); + firstUser.setLangKey(Constants.DEFAULT_LANGUAGE); + firstUser.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); + + // Register first user + restMvc.perform( + post("/api/register") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(firstUser))) + .andExpect(status().isCreated()); + + Optional testUser1 = userRepository.findOneByLogin("test-register-duplicate-email"); + assertThat(testUser1.isPresent()).isTrue(); + + // Duplicate email, different login + ManagedUserVM secondUser = new ManagedUserVM(); + secondUser.setLogin("test-register-duplicate-email-2"); + secondUser.setPassword(firstUser.getPassword()); + secondUser.setFirstName(firstUser.getFirstName()); + secondUser.setLastName(firstUser.getLastName()); + secondUser.setEmail(firstUser.getEmail()); + secondUser.setImageUrl(firstUser.getImageUrl()); + secondUser.setLangKey(firstUser.getLangKey()); + secondUser.setAuthorities(new HashSet<>(firstUser.getAuthorities())); + + // Register second (non activated) user + restMvc.perform( + post("/api/register") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(secondUser))) + .andExpect(status().isCreated()); + + Optional testUser2 = userRepository.findOneByLogin("test-register-duplicate-email"); + assertThat(testUser2.isPresent()).isFalse(); + + Optional testUser3 = userRepository.findOneByLogin("test-register-duplicate-email-2"); + assertThat(testUser3.isPresent()).isTrue(); + + // Duplicate email - with uppercase email address + ManagedUserVM userWithUpperCaseEmail = new ManagedUserVM(); + userWithUpperCaseEmail.setId(firstUser.getId()); + userWithUpperCaseEmail.setLogin("test-register-duplicate-email-3"); + userWithUpperCaseEmail.setPassword(firstUser.getPassword()); + userWithUpperCaseEmail.setFirstName(firstUser.getFirstName()); + userWithUpperCaseEmail.setLastName(firstUser.getLastName()); + userWithUpperCaseEmail.setEmail("TEST-register-duplicate-email@example.com"); + userWithUpperCaseEmail.setImageUrl(firstUser.getImageUrl()); + userWithUpperCaseEmail.setLangKey(firstUser.getLangKey()); + userWithUpperCaseEmail.setAuthorities(new HashSet<>(firstUser.getAuthorities())); + + // Register third (not activated) user + restMvc.perform( + post("/api/register") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(userWithUpperCaseEmail))) + .andExpect(status().isCreated()); + + Optional testUser4 = userRepository.findOneByLogin("test-register-duplicate-email-3"); + assertThat(testUser4.isPresent()).isTrue(); + assertThat(testUser4.get().getEmail()).isEqualTo("test-register-duplicate-email@example.com"); + + testUser4.get().setActivated(true); + userService.updateUser((new UserDTO(testUser4.get()))); + + // Register 4th (already activated) user + restMvc.perform( + post("/api/register") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(secondUser))) + .andExpect(status().is4xxClientError()); + } + + @Test + @Transactional + public void testRegisterAdminIsIgnored() throws Exception { + ManagedUserVM validUser = new ManagedUserVM(); + validUser.setLogin("badguy"); + validUser.setPassword("password"); + validUser.setFirstName("Bad"); + validUser.setLastName("Guy"); + validUser.setEmail("badguy@example.com"); + validUser.setActivated(true); + validUser.setImageUrl("http://placehold.it/50x50"); + validUser.setLangKey(Constants.DEFAULT_LANGUAGE); + validUser.setAuthorities(Collections.singleton(AuthoritiesConstants.ADMIN)); + + restMvc.perform( + post("/api/register") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(validUser))) + .andExpect(status().isCreated()); + + Optional userDup = userRepository.findOneByLogin("badguy"); + assertThat(userDup.isPresent()).isTrue(); + assertThat(userDup.get().getAuthorities()).hasSize(1) + .containsExactly(authorityRepository.findById(AuthoritiesConstants.USER).get()); + } + + @Test + @Transactional + public void testActivateAccount() throws Exception { + final String activationKey = "some activation key"; + User user = new User(); + user.setLogin("activate-account"); + user.setEmail("activate-account@example.com"); + user.setPassword(RandomStringUtils.random(60)); + user.setActivated(false); + user.setActivationKey(activationKey); + + userRepository.saveAndFlush(user); + + restMvc.perform(get("/api/activate?key={activationKey}", activationKey)) + .andExpect(status().isOk()); + + user = userRepository.findOneByLogin(user.getLogin()).orElse(null); + assertThat(user.getActivated()).isTrue(); + } + + @Test + @Transactional + public void testActivateAccountWithWrongKey() throws Exception { + restMvc.perform(get("/api/activate?key=wrongActivationKey")) + .andExpect(status().isInternalServerError()); + } + + @Test + @Transactional + @WithMockUser("save-account") + public void testSaveAccount() throws Exception { + User user = new User(); + user.setLogin("save-account"); + user.setEmail("save-account@example.com"); + user.setPassword(RandomStringUtils.random(60)); + user.setActivated(true); + + userRepository.saveAndFlush(user); + + UserDTO userDTO = new UserDTO(); + userDTO.setLogin("not-used"); + userDTO.setFirstName("firstname"); + userDTO.setLastName("lastname"); + userDTO.setEmail("save-account@example.com"); + userDTO.setActivated(false); + userDTO.setImageUrl("http://placehold.it/50x50"); + userDTO.setLangKey(Constants.DEFAULT_LANGUAGE); + userDTO.setAuthorities(Collections.singleton(AuthoritiesConstants.ADMIN)); + + restMvc.perform( + post("/api/account") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(userDTO))) + .andExpect(status().isOk()); + + User updatedUser = userRepository.findOneByLogin(user.getLogin()).orElse(null); + assertThat(updatedUser.getFirstName()).isEqualTo(userDTO.getFirstName()); + assertThat(updatedUser.getLastName()).isEqualTo(userDTO.getLastName()); + assertThat(updatedUser.getEmail()).isEqualTo(userDTO.getEmail()); + assertThat(updatedUser.getLangKey()).isEqualTo(userDTO.getLangKey()); + assertThat(updatedUser.getPassword()).isEqualTo(user.getPassword()); + assertThat(updatedUser.getImageUrl()).isEqualTo(userDTO.getImageUrl()); + assertThat(updatedUser.getActivated()).isEqualTo(true); + assertThat(updatedUser.getAuthorities()).isEmpty(); + } + + @Test + @Transactional + @WithMockUser("save-invalid-email") + public void testSaveInvalidEmail() throws Exception { + User user = new User(); + user.setLogin("save-invalid-email"); + user.setEmail("save-invalid-email@example.com"); + user.setPassword(RandomStringUtils.random(60)); + user.setActivated(true); + + userRepository.saveAndFlush(user); + + UserDTO userDTO = new UserDTO(); + userDTO.setLogin("not-used"); + userDTO.setFirstName("firstname"); + userDTO.setLastName("lastname"); + userDTO.setEmail("invalid email"); + userDTO.setActivated(false); + userDTO.setImageUrl("http://placehold.it/50x50"); + userDTO.setLangKey(Constants.DEFAULT_LANGUAGE); + userDTO.setAuthorities(Collections.singleton(AuthoritiesConstants.ADMIN)); + + restMvc.perform( + post("/api/account") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(userDTO))) + .andExpect(status().isBadRequest()); + + assertThat(userRepository.findOneByEmailIgnoreCase("invalid email")).isNotPresent(); + } + + @Test + @Transactional + @WithMockUser("save-existing-email") + public void testSaveExistingEmail() throws Exception { + User user = new User(); + user.setLogin("save-existing-email"); + user.setEmail("save-existing-email@example.com"); + user.setPassword(RandomStringUtils.random(60)); + user.setActivated(true); + + userRepository.saveAndFlush(user); + + User anotherUser = new User(); + anotherUser.setLogin("save-existing-email2"); + anotherUser.setEmail("save-existing-email2@example.com"); + anotherUser.setPassword(RandomStringUtils.random(60)); + anotherUser.setActivated(true); + + userRepository.saveAndFlush(anotherUser); + + UserDTO userDTO = new UserDTO(); + userDTO.setLogin("not-used"); + userDTO.setFirstName("firstname"); + userDTO.setLastName("lastname"); + userDTO.setEmail("save-existing-email2@example.com"); + userDTO.setActivated(false); + userDTO.setImageUrl("http://placehold.it/50x50"); + userDTO.setLangKey(Constants.DEFAULT_LANGUAGE); + userDTO.setAuthorities(Collections.singleton(AuthoritiesConstants.ADMIN)); + + restMvc.perform( + post("/api/account") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(userDTO))) + .andExpect(status().isBadRequest()); + + User updatedUser = userRepository.findOneByLogin("save-existing-email").orElse(null); + assertThat(updatedUser.getEmail()).isEqualTo("save-existing-email@example.com"); + } + + @Test + @Transactional + @WithMockUser("save-existing-email-and-login") + public void testSaveExistingEmailAndLogin() throws Exception { + User user = new User(); + user.setLogin("save-existing-email-and-login"); + user.setEmail("save-existing-email-and-login@example.com"); + user.setPassword(RandomStringUtils.random(60)); + user.setActivated(true); + + userRepository.saveAndFlush(user); + + UserDTO userDTO = new UserDTO(); + userDTO.setLogin("not-used"); + userDTO.setFirstName("firstname"); + userDTO.setLastName("lastname"); + userDTO.setEmail("save-existing-email-and-login@example.com"); + userDTO.setActivated(false); + userDTO.setImageUrl("http://placehold.it/50x50"); + userDTO.setLangKey(Constants.DEFAULT_LANGUAGE); + userDTO.setAuthorities(Collections.singleton(AuthoritiesConstants.ADMIN)); + + restMvc.perform( + post("/api/account") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(userDTO))) + .andExpect(status().isOk()); + + User updatedUser = userRepository.findOneByLogin("save-existing-email-and-login").orElse(null); + assertThat(updatedUser.getEmail()).isEqualTo("save-existing-email-and-login@example.com"); + } + + @Test + @Transactional + @WithMockUser("change-password-wrong-existing-password") + public void testChangePasswordWrongExistingPassword() throws Exception { + User user = new User(); + String currentPassword = RandomStringUtils.random(60); + user.setPassword(passwordEncoder.encode(currentPassword)); + user.setLogin("change-password-wrong-existing-password"); + user.setEmail("change-password-wrong-existing-password@example.com"); + userRepository.saveAndFlush(user); + + restMvc.perform(post("/api/account/change-password") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(new PasswordChangeDTO("1"+currentPassword, "new password")))) + .andExpect(status().isBadRequest()); + + User updatedUser = userRepository.findOneByLogin("change-password-wrong-existing-password").orElse(null); + assertThat(passwordEncoder.matches("new password", updatedUser.getPassword())).isFalse(); + assertThat(passwordEncoder.matches(currentPassword, updatedUser.getPassword())).isTrue(); + } + + @Test + @Transactional + @WithMockUser("change-password") + public void testChangePassword() throws Exception { + User user = new User(); + String currentPassword = RandomStringUtils.random(60); + user.setPassword(passwordEncoder.encode(currentPassword)); + user.setLogin("change-password"); + user.setEmail("change-password@example.com"); + userRepository.saveAndFlush(user); + + restMvc.perform(post("/api/account/change-password") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(new PasswordChangeDTO(currentPassword, "new password")))) + .andExpect(status().isOk()); + + User updatedUser = userRepository.findOneByLogin("change-password").orElse(null); + assertThat(passwordEncoder.matches("new password", updatedUser.getPassword())).isTrue(); + } + + @Test + @Transactional + @WithMockUser("change-password-too-small") + public void testChangePasswordTooSmall() throws Exception { + User user = new User(); + String currentPassword = RandomStringUtils.random(60); + user.setPassword(passwordEncoder.encode(currentPassword)); + user.setLogin("change-password-too-small"); + user.setEmail("change-password-too-small@example.com"); + userRepository.saveAndFlush(user); + + String newPassword = RandomStringUtils.random(ManagedUserVM.PASSWORD_MIN_LENGTH - 1); + + restMvc.perform(post("/api/account/change-password") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(new PasswordChangeDTO(currentPassword, newPassword)))) + .andExpect(status().isBadRequest()); + + User updatedUser = userRepository.findOneByLogin("change-password-too-small").orElse(null); + assertThat(updatedUser.getPassword()).isEqualTo(user.getPassword()); + } + + @Test + @Transactional + @WithMockUser("change-password-too-long") + public void testChangePasswordTooLong() throws Exception { + User user = new User(); + String currentPassword = RandomStringUtils.random(60); + user.setPassword(passwordEncoder.encode(currentPassword)); + user.setLogin("change-password-too-long"); + user.setEmail("change-password-too-long@example.com"); + userRepository.saveAndFlush(user); + + String newPassword = RandomStringUtils.random(ManagedUserVM.PASSWORD_MAX_LENGTH + 1); + + restMvc.perform(post("/api/account/change-password") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(new PasswordChangeDTO(currentPassword, newPassword)))) + .andExpect(status().isBadRequest()); + + User updatedUser = userRepository.findOneByLogin("change-password-too-long").orElse(null); + assertThat(updatedUser.getPassword()).isEqualTo(user.getPassword()); + } + + @Test + @Transactional + @WithMockUser("change-password-empty") + public void testChangePasswordEmpty() throws Exception { + User user = new User(); + String currentPassword = RandomStringUtils.random(60); + user.setPassword(passwordEncoder.encode(currentPassword)); + user.setLogin("change-password-empty"); + user.setEmail("change-password-empty@example.com"); + userRepository.saveAndFlush(user); + + restMvc.perform(post("/api/account/change-password") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(new PasswordChangeDTO(currentPassword, "")))) + .andExpect(status().isBadRequest()); + + User updatedUser = userRepository.findOneByLogin("change-password-empty").orElse(null); + assertThat(updatedUser.getPassword()).isEqualTo(user.getPassword()); + } + + @Test + @Transactional + public void testRequestPasswordReset() throws Exception { + User user = new User(); + user.setPassword(RandomStringUtils.random(60)); + user.setActivated(true); + user.setLogin("password-reset"); + user.setEmail("password-reset@example.com"); + userRepository.saveAndFlush(user); + + restMvc.perform(post("/api/account/reset-password/init") + .content("password-reset@example.com")) + .andExpect(status().isOk()); + } + + @Test + @Transactional + public void testRequestPasswordResetUpperCaseEmail() throws Exception { + User user = new User(); + user.setPassword(RandomStringUtils.random(60)); + user.setActivated(true); + user.setLogin("password-reset"); + user.setEmail("password-reset@example.com"); + userRepository.saveAndFlush(user); + + restMvc.perform(post("/api/account/reset-password/init") + .content("password-reset@EXAMPLE.COM")) + .andExpect(status().isOk()); + } + + @Test + public void testRequestPasswordResetWrongEmail() throws Exception { + restMvc.perform( + post("/api/account/reset-password/init") + .content("password-reset-wrong-email@example.com")) + .andExpect(status().isBadRequest()); + } + + @Test + @Transactional + public void testFinishPasswordReset() throws Exception { + User user = new User(); + user.setPassword(RandomStringUtils.random(60)); + user.setLogin("finish-password-reset"); + user.setEmail("finish-password-reset@example.com"); + user.setResetDate(Instant.now().plusSeconds(60)); + user.setResetKey("reset key"); + userRepository.saveAndFlush(user); + + KeyAndPasswordVM keyAndPassword = new KeyAndPasswordVM(); + keyAndPassword.setKey(user.getResetKey()); + keyAndPassword.setNewPassword("new password"); + + restMvc.perform( + post("/api/account/reset-password/finish") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(keyAndPassword))) + .andExpect(status().isOk()); + + User updatedUser = userRepository.findOneByLogin(user.getLogin()).orElse(null); + assertThat(passwordEncoder.matches(keyAndPassword.getNewPassword(), updatedUser.getPassword())).isTrue(); + } + + @Test + @Transactional + public void testFinishPasswordResetTooSmall() throws Exception { + User user = new User(); + user.setPassword(RandomStringUtils.random(60)); + user.setLogin("finish-password-reset-too-small"); + user.setEmail("finish-password-reset-too-small@example.com"); + user.setResetDate(Instant.now().plusSeconds(60)); + user.setResetKey("reset key too small"); + userRepository.saveAndFlush(user); + + KeyAndPasswordVM keyAndPassword = new KeyAndPasswordVM(); + keyAndPassword.setKey(user.getResetKey()); + keyAndPassword.setNewPassword("foo"); + + restMvc.perform( + post("/api/account/reset-password/finish") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(keyAndPassword))) + .andExpect(status().isBadRequest()); + + User updatedUser = userRepository.findOneByLogin(user.getLogin()).orElse(null); + assertThat(passwordEncoder.matches(keyAndPassword.getNewPassword(), updatedUser.getPassword())).isFalse(); + } + + + @Test + @Transactional + public void testFinishPasswordResetWrongKey() throws Exception { + KeyAndPasswordVM keyAndPassword = new KeyAndPasswordVM(); + keyAndPassword.setKey("wrong reset key"); + keyAndPassword.setNewPassword("new password"); + + restMvc.perform( + post("/api/account/reset-password/finish") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(keyAndPassword))) + .andExpect(status().isInternalServerError()); + } +} diff --git a/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/AuditResourceIntTest.java b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/AuditResourceIntTest.java new file mode 100644 index 0000000000..c3b91ab390 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/AuditResourceIntTest.java @@ -0,0 +1,162 @@ +package com.baeldung.jhipster5.web.rest; + +import com.baeldung.jhipster5.BookstoreApp; +import com.baeldung.jhipster5.config.audit.AuditEventConverter; +import com.baeldung.jhipster5.domain.PersistentAuditEvent; +import com.baeldung.jhipster5.repository.PersistenceAuditEventRepository; +import com.baeldung.jhipster5.service.AuditEventService; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.MockitoAnnotations; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.data.web.PageableHandlerMethodArgumentResolver; +import org.springframework.format.support.FormattingConversionService; +import org.springframework.http.MediaType; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.transaction.annotation.Transactional; + +import java.time.Instant; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.hamcrest.Matchers.hasItem; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +/** + * Test class for the AuditResource REST controller. + * + * @see AuditResource + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = BookstoreApp.class) +@Transactional +public class AuditResourceIntTest { + + private static final String SAMPLE_PRINCIPAL = "SAMPLE_PRINCIPAL"; + private static final String SAMPLE_TYPE = "SAMPLE_TYPE"; + private static final Instant SAMPLE_TIMESTAMP = Instant.parse("2015-08-04T10:11:30Z"); + private static final long SECONDS_PER_DAY = 60 * 60 * 24; + + @Autowired + private PersistenceAuditEventRepository auditEventRepository; + + @Autowired + private AuditEventConverter auditEventConverter; + + @Autowired + private MappingJackson2HttpMessageConverter jacksonMessageConverter; + + @Autowired + private FormattingConversionService formattingConversionService; + + @Autowired + private PageableHandlerMethodArgumentResolver pageableArgumentResolver; + + private PersistentAuditEvent auditEvent; + + private MockMvc restAuditMockMvc; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + AuditEventService auditEventService = + new AuditEventService(auditEventRepository, auditEventConverter); + AuditResource auditResource = new AuditResource(auditEventService); + this.restAuditMockMvc = MockMvcBuilders.standaloneSetup(auditResource) + .setCustomArgumentResolvers(pageableArgumentResolver) + .setConversionService(formattingConversionService) + .setMessageConverters(jacksonMessageConverter).build(); + } + + @Before + public void initTest() { + auditEventRepository.deleteAll(); + auditEvent = new PersistentAuditEvent(); + auditEvent.setAuditEventType(SAMPLE_TYPE); + auditEvent.setPrincipal(SAMPLE_PRINCIPAL); + auditEvent.setAuditEventDate(SAMPLE_TIMESTAMP); + } + + @Test + public void getAllAudits() throws Exception { + // Initialize the database + auditEventRepository.save(auditEvent); + + // Get all the audits + restAuditMockMvc.perform(get("/management/audits")) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)) + .andExpect(jsonPath("$.[*].principal").value(hasItem(SAMPLE_PRINCIPAL))); + } + + @Test + public void getAudit() throws Exception { + // Initialize the database + auditEventRepository.save(auditEvent); + + // Get the audit + restAuditMockMvc.perform(get("/management/audits/{id}", auditEvent.getId())) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)) + .andExpect(jsonPath("$.principal").value(SAMPLE_PRINCIPAL)); + } + + @Test + public void getAuditsByDate() throws Exception { + // Initialize the database + auditEventRepository.save(auditEvent); + + // Generate dates for selecting audits by date, making sure the period will contain the audit + String fromDate = SAMPLE_TIMESTAMP.minusSeconds(SECONDS_PER_DAY).toString().substring(0, 10); + String toDate = SAMPLE_TIMESTAMP.plusSeconds(SECONDS_PER_DAY).toString().substring(0, 10); + + // Get the audit + restAuditMockMvc.perform(get("/management/audits?fromDate="+fromDate+"&toDate="+toDate)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)) + .andExpect(jsonPath("$.[*].principal").value(hasItem(SAMPLE_PRINCIPAL))); + } + + @Test + public void getNonExistingAuditsByDate() throws Exception { + // Initialize the database + auditEventRepository.save(auditEvent); + + // Generate dates for selecting audits by date, making sure the period will not contain the sample audit + String fromDate = SAMPLE_TIMESTAMP.minusSeconds(2*SECONDS_PER_DAY).toString().substring(0, 10); + String toDate = SAMPLE_TIMESTAMP.minusSeconds(SECONDS_PER_DAY).toString().substring(0, 10); + + // Query audits but expect no results + restAuditMockMvc.perform(get("/management/audits?fromDate=" + fromDate + "&toDate=" + toDate)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)) + .andExpect(header().string("X-Total-Count", "0")); + } + + @Test + public void getNonExistingAudit() throws Exception { + // Get the audit + restAuditMockMvc.perform(get("/management/audits/{id}", Long.MAX_VALUE)) + .andExpect(status().isNotFound()); + } + + @Test + @Transactional + public void testPersistentAuditEventEquals() throws Exception { + TestUtil.equalsVerifier(PersistentAuditEvent.class); + PersistentAuditEvent auditEvent1 = new PersistentAuditEvent(); + auditEvent1.setId(1L); + PersistentAuditEvent auditEvent2 = new PersistentAuditEvent(); + auditEvent2.setId(auditEvent1.getId()); + assertThat(auditEvent1).isEqualTo(auditEvent2); + auditEvent2.setId(2L); + assertThat(auditEvent1).isNotEqualTo(auditEvent2); + auditEvent1.setId(null); + assertThat(auditEvent1).isNotEqualTo(auditEvent2); + } +} diff --git a/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/BookResourceIntTest.java b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/BookResourceIntTest.java new file mode 100644 index 0000000000..ef8f27ceea --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/BookResourceIntTest.java @@ -0,0 +1,416 @@ +package com.baeldung.jhipster5.web.rest; + +import com.baeldung.jhipster5.BookstoreApp; + +import com.baeldung.jhipster5.domain.Book; +import com.baeldung.jhipster5.repository.BookRepository; +import com.baeldung.jhipster5.service.BookService; +import com.baeldung.jhipster5.service.dto.BookDTO; +import com.baeldung.jhipster5.service.mapper.BookMapper; +import com.baeldung.jhipster5.web.rest.errors.ExceptionTranslator; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.MockitoAnnotations; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.data.web.PageableHandlerMethodArgumentResolver; +import org.springframework.http.MediaType; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.Validator; + +import javax.persistence.EntityManager; +import java.time.LocalDate; +import java.time.ZoneId; +import java.util.List; + + +import static com.baeldung.jhipster5.web.rest.TestUtil.createFormattingConversionService; +import static org.assertj.core.api.Assertions.assertThat; +import static org.hamcrest.Matchers.hasItem; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +/** + * Test class for the BookResource REST controller. + * + * @see BookResource + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = BookstoreApp.class) +public class BookResourceIntTest { + + private static final String DEFAULT_TITLE = "AAAAAAAAAA"; + private static final String UPDATED_TITLE = "BBBBBBBBBB"; + + private static final String DEFAULT_AUTHOR = "AAAAAAAAAA"; + private static final String UPDATED_AUTHOR = "BBBBBBBBBB"; + + private static final LocalDate DEFAULT_PUBLISHED = LocalDate.ofEpochDay(0L); + private static final LocalDate UPDATED_PUBLISHED = LocalDate.now(ZoneId.systemDefault()); + + private static final Integer DEFAULT_QUANTITY = 0; + private static final Integer UPDATED_QUANTITY = 1; + + private static final Double DEFAULT_PRICE = 0D; + private static final Double UPDATED_PRICE = 1D; + + @Autowired + private BookRepository bookRepository; + + @Autowired + private BookMapper bookMapper; + + @Autowired + private BookService bookService; + + @Autowired + private MappingJackson2HttpMessageConverter jacksonMessageConverter; + + @Autowired + private PageableHandlerMethodArgumentResolver pageableArgumentResolver; + + @Autowired + private ExceptionTranslator exceptionTranslator; + + @Autowired + private EntityManager em; + + @Autowired + private Validator validator; + + private MockMvc restBookMockMvc; + + private Book book; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + final BookResource bookResource = new BookResource(bookService); + this.restBookMockMvc = MockMvcBuilders.standaloneSetup(bookResource) + .setCustomArgumentResolvers(pageableArgumentResolver) + .setControllerAdvice(exceptionTranslator) + .setConversionService(createFormattingConversionService()) + .setMessageConverters(jacksonMessageConverter) + .setValidator(validator).build(); + } + + /** + * Create an entity for this test. + * + * This is a static method, as tests for other entities might also need it, + * if they test an entity which requires the current entity. + */ + public static Book createEntity(EntityManager em) { + Book book = new Book() + .title(DEFAULT_TITLE) + .author(DEFAULT_AUTHOR) + .published(DEFAULT_PUBLISHED) + .quantity(DEFAULT_QUANTITY) + .price(DEFAULT_PRICE); + return book; + } + + @Before + public void initTest() { + book = createEntity(em); + } + + @Test + @Transactional + public void createBook() throws Exception { + int databaseSizeBeforeCreate = bookRepository.findAll().size(); + + // Create the Book + BookDTO bookDTO = bookMapper.toDto(book); + restBookMockMvc.perform(post("/api/books") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(bookDTO))) + .andExpect(status().isCreated()); + + // Validate the Book in the database + List bookList = bookRepository.findAll(); + assertThat(bookList).hasSize(databaseSizeBeforeCreate + 1); + Book testBook = bookList.get(bookList.size() - 1); + assertThat(testBook.getTitle()).isEqualTo(DEFAULT_TITLE); + assertThat(testBook.getAuthor()).isEqualTo(DEFAULT_AUTHOR); + assertThat(testBook.getPublished()).isEqualTo(DEFAULT_PUBLISHED); + assertThat(testBook.getQuantity()).isEqualTo(DEFAULT_QUANTITY); + assertThat(testBook.getPrice()).isEqualTo(DEFAULT_PRICE); + } + + @Test + @Transactional + public void createBookWithExistingId() throws Exception { + int databaseSizeBeforeCreate = bookRepository.findAll().size(); + + // Create the Book with an existing ID + book.setId(1L); + BookDTO bookDTO = bookMapper.toDto(book); + + // An entity with an existing ID cannot be created, so this API call must fail + restBookMockMvc.perform(post("/api/books") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(bookDTO))) + .andExpect(status().isBadRequest()); + + // Validate the Book in the database + List bookList = bookRepository.findAll(); + assertThat(bookList).hasSize(databaseSizeBeforeCreate); + } + + @Test + @Transactional + public void checkTitleIsRequired() throws Exception { + int databaseSizeBeforeTest = bookRepository.findAll().size(); + // set the field null + book.setTitle(null); + + // Create the Book, which fails. + BookDTO bookDTO = bookMapper.toDto(book); + + restBookMockMvc.perform(post("/api/books") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(bookDTO))) + .andExpect(status().isBadRequest()); + + List bookList = bookRepository.findAll(); + assertThat(bookList).hasSize(databaseSizeBeforeTest); + } + + @Test + @Transactional + public void checkAuthorIsRequired() throws Exception { + int databaseSizeBeforeTest = bookRepository.findAll().size(); + // set the field null + book.setAuthor(null); + + // Create the Book, which fails. + BookDTO bookDTO = bookMapper.toDto(book); + + restBookMockMvc.perform(post("/api/books") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(bookDTO))) + .andExpect(status().isBadRequest()); + + List bookList = bookRepository.findAll(); + assertThat(bookList).hasSize(databaseSizeBeforeTest); + } + + @Test + @Transactional + public void checkPublishedIsRequired() throws Exception { + int databaseSizeBeforeTest = bookRepository.findAll().size(); + // set the field null + book.setPublished(null); + + // Create the Book, which fails. + BookDTO bookDTO = bookMapper.toDto(book); + + restBookMockMvc.perform(post("/api/books") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(bookDTO))) + .andExpect(status().isBadRequest()); + + List bookList = bookRepository.findAll(); + assertThat(bookList).hasSize(databaseSizeBeforeTest); + } + + @Test + @Transactional + public void checkQuantityIsRequired() throws Exception { + int databaseSizeBeforeTest = bookRepository.findAll().size(); + // set the field null + book.setQuantity(null); + + // Create the Book, which fails. + BookDTO bookDTO = bookMapper.toDto(book); + + restBookMockMvc.perform(post("/api/books") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(bookDTO))) + .andExpect(status().isBadRequest()); + + List bookList = bookRepository.findAll(); + assertThat(bookList).hasSize(databaseSizeBeforeTest); + } + + @Test + @Transactional + public void checkPriceIsRequired() throws Exception { + int databaseSizeBeforeTest = bookRepository.findAll().size(); + // set the field null + book.setPrice(null); + + // Create the Book, which fails. + BookDTO bookDTO = bookMapper.toDto(book); + + restBookMockMvc.perform(post("/api/books") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(bookDTO))) + .andExpect(status().isBadRequest()); + + List bookList = bookRepository.findAll(); + assertThat(bookList).hasSize(databaseSizeBeforeTest); + } + + @Test + @Transactional + public void getAllBooks() throws Exception { + // Initialize the database + bookRepository.saveAndFlush(book); + + // Get all the bookList + restBookMockMvc.perform(get("/api/books?sort=id,desc")) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)) + .andExpect(jsonPath("$.[*].id").value(hasItem(book.getId().intValue()))) + .andExpect(jsonPath("$.[*].title").value(hasItem(DEFAULT_TITLE.toString()))) + .andExpect(jsonPath("$.[*].author").value(hasItem(DEFAULT_AUTHOR.toString()))) + .andExpect(jsonPath("$.[*].published").value(hasItem(DEFAULT_PUBLISHED.toString()))) + .andExpect(jsonPath("$.[*].quantity").value(hasItem(DEFAULT_QUANTITY))) + .andExpect(jsonPath("$.[*].price").value(hasItem(DEFAULT_PRICE.doubleValue()))); + } + + @Test + @Transactional + public void getBook() throws Exception { + // Initialize the database + bookRepository.saveAndFlush(book); + + // Get the book + restBookMockMvc.perform(get("/api/books/{id}", book.getId())) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)) + .andExpect(jsonPath("$.id").value(book.getId().intValue())) + .andExpect(jsonPath("$.title").value(DEFAULT_TITLE.toString())) + .andExpect(jsonPath("$.author").value(DEFAULT_AUTHOR.toString())) + .andExpect(jsonPath("$.published").value(DEFAULT_PUBLISHED.toString())) + .andExpect(jsonPath("$.quantity").value(DEFAULT_QUANTITY)) + .andExpect(jsonPath("$.price").value(DEFAULT_PRICE.doubleValue())); + } + + @Test + @Transactional + public void getNonExistingBook() throws Exception { + // Get the book + restBookMockMvc.perform(get("/api/books/{id}", Long.MAX_VALUE)) + .andExpect(status().isNotFound()); + } + + @Test + @Transactional + public void updateBook() throws Exception { + // Initialize the database + bookRepository.saveAndFlush(book); + + int databaseSizeBeforeUpdate = bookRepository.findAll().size(); + + // Update the book + Book updatedBook = bookRepository.findById(book.getId()).get(); + // Disconnect from session so that the updates on updatedBook are not directly saved in db + em.detach(updatedBook); + updatedBook + .title(UPDATED_TITLE) + .author(UPDATED_AUTHOR) + .published(UPDATED_PUBLISHED) + .quantity(UPDATED_QUANTITY) + .price(UPDATED_PRICE); + BookDTO bookDTO = bookMapper.toDto(updatedBook); + + restBookMockMvc.perform(put("/api/books") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(bookDTO))) + .andExpect(status().isOk()); + + // Validate the Book in the database + List bookList = bookRepository.findAll(); + assertThat(bookList).hasSize(databaseSizeBeforeUpdate); + Book testBook = bookList.get(bookList.size() - 1); + assertThat(testBook.getTitle()).isEqualTo(UPDATED_TITLE); + assertThat(testBook.getAuthor()).isEqualTo(UPDATED_AUTHOR); + assertThat(testBook.getPublished()).isEqualTo(UPDATED_PUBLISHED); + assertThat(testBook.getQuantity()).isEqualTo(UPDATED_QUANTITY); + assertThat(testBook.getPrice()).isEqualTo(UPDATED_PRICE); + } + + @Test + @Transactional + public void updateNonExistingBook() throws Exception { + int databaseSizeBeforeUpdate = bookRepository.findAll().size(); + + // Create the Book + BookDTO bookDTO = bookMapper.toDto(book); + + // If the entity doesn't have an ID, it will throw BadRequestAlertException + restBookMockMvc.perform(put("/api/books") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(bookDTO))) + .andExpect(status().isBadRequest()); + + // Validate the Book in the database + List bookList = bookRepository.findAll(); + assertThat(bookList).hasSize(databaseSizeBeforeUpdate); + } + + @Test + @Transactional + public void deleteBook() throws Exception { + // Initialize the database + bookRepository.saveAndFlush(book); + + int databaseSizeBeforeDelete = bookRepository.findAll().size(); + + // Delete the book + restBookMockMvc.perform(delete("/api/books/{id}", book.getId()) + .accept(TestUtil.APPLICATION_JSON_UTF8)) + .andExpect(status().isOk()); + + // Validate the database is empty + List bookList = bookRepository.findAll(); + assertThat(bookList).hasSize(databaseSizeBeforeDelete - 1); + } + + @Test + @Transactional + public void equalsVerifier() throws Exception { + TestUtil.equalsVerifier(Book.class); + Book book1 = new Book(); + book1.setId(1L); + Book book2 = new Book(); + book2.setId(book1.getId()); + assertThat(book1).isEqualTo(book2); + book2.setId(2L); + assertThat(book1).isNotEqualTo(book2); + book1.setId(null); + assertThat(book1).isNotEqualTo(book2); + } + + @Test + @Transactional + public void dtoEqualsVerifier() throws Exception { + TestUtil.equalsVerifier(BookDTO.class); + BookDTO bookDTO1 = new BookDTO(); + bookDTO1.setId(1L); + BookDTO bookDTO2 = new BookDTO(); + assertThat(bookDTO1).isNotEqualTo(bookDTO2); + bookDTO2.setId(bookDTO1.getId()); + assertThat(bookDTO1).isEqualTo(bookDTO2); + bookDTO2.setId(2L); + assertThat(bookDTO1).isNotEqualTo(bookDTO2); + bookDTO1.setId(null); + assertThat(bookDTO1).isNotEqualTo(bookDTO2); + } + + @Test + @Transactional + public void testEntityFromId() { + assertThat(bookMapper.fromId(42L).getId()).isEqualTo(42); + assertThat(bookMapper.fromId(null)).isNull(); + } +} diff --git a/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/LogsResourceIntTest.java b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/LogsResourceIntTest.java new file mode 100644 index 0000000000..62f7f3f17c --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/LogsResourceIntTest.java @@ -0,0 +1,66 @@ +package com.baeldung.jhipster5.web.rest; + +import com.baeldung.jhipster5.BookstoreApp; +import com.baeldung.jhipster5.web.rest.vm.LoggerVM; +import ch.qos.logback.classic.AsyncAppender; +import ch.qos.logback.classic.LoggerContext; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.slf4j.LoggerFactory; +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 org.springframework.test.web.servlet.setup.MockMvcBuilders; + +import static org.assertj.core.api.Assertions.assertThat; +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.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +/** + * Test class for the LogsResource REST controller. + * + * @see LogsResource + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = BookstoreApp.class) +public class LogsResourceIntTest { + + private MockMvc restLogsMockMvc; + + @Before + public void setup() { + LogsResource logsResource = new LogsResource(); + this.restLogsMockMvc = MockMvcBuilders + .standaloneSetup(logsResource) + .build(); + } + + @Test + public void getAllLogs() throws Exception { + restLogsMockMvc.perform(get("/management/logs")) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)); + } + + @Test + public void changeLogs() throws Exception { + LoggerVM logger = new LoggerVM(); + logger.setLevel("INFO"); + logger.setName("ROOT"); + + restLogsMockMvc.perform(put("/management/logs") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(logger))) + .andExpect(status().isNoContent()); + } + + @Test + public void testLogstashAppender() { + LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); + assertThat(context.getLogger("ROOT").getAppender("ASYNC_LOGSTASH")).isInstanceOf(AsyncAppender.class); + } +} diff --git a/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/TestUtil.java b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/TestUtil.java new file mode 100644 index 0000000000..403bb9c9b0 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/TestUtil.java @@ -0,0 +1,141 @@ +package com.baeldung.jhipster5.web.rest; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import org.hamcrest.Description; +import org.hamcrest.TypeSafeDiagnosingMatcher; +import org.springframework.format.datetime.standard.DateTimeFormatterRegistrar; +import org.springframework.format.support.DefaultFormattingConversionService; +import org.springframework.format.support.FormattingConversionService; +import org.springframework.http.MediaType; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.time.ZonedDateTime; +import java.time.format.DateTimeParseException; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Utility class for testing REST controllers. + */ +public final class TestUtil { + + private static final ObjectMapper mapper = createObjectMapper(); + + /** MediaType for JSON UTF8 */ + public static final MediaType APPLICATION_JSON_UTF8 = new MediaType( + MediaType.APPLICATION_JSON.getType(), + MediaType.APPLICATION_JSON.getSubtype(), StandardCharsets.UTF_8); + + + private static ObjectMapper createObjectMapper() { + ObjectMapper mapper = new ObjectMapper(); + mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY); + mapper.registerModule(new JavaTimeModule()); + return mapper; + } + + /** + * Convert an object to JSON byte array. + * + * @param object + * the object to convert + * @return the JSON byte array + * @throws IOException + */ + public static byte[] convertObjectToJsonBytes(Object object) + throws IOException { + return mapper.writeValueAsBytes(object); + } + + /** + * Create a byte array with a specific size filled with specified data. + * + * @param size the size of the byte array + * @param data the data to put in the byte array + * @return the JSON byte array + */ + public static byte[] createByteArray(int size, String data) { + byte[] byteArray = new byte[size]; + for (int i = 0; i < size; i++) { + byteArray[i] = Byte.parseByte(data, 2); + } + return byteArray; + } + + /** + * A matcher that tests that the examined string represents the same instant as the reference datetime. + */ + public static class ZonedDateTimeMatcher extends TypeSafeDiagnosingMatcher { + + private final ZonedDateTime date; + + public ZonedDateTimeMatcher(ZonedDateTime date) { + this.date = date; + } + + @Override + protected boolean matchesSafely(String item, Description mismatchDescription) { + try { + if (!date.isEqual(ZonedDateTime.parse(item))) { + mismatchDescription.appendText("was ").appendValue(item); + return false; + } + return true; + } catch (DateTimeParseException e) { + mismatchDescription.appendText("was ").appendValue(item) + .appendText(", which could not be parsed as a ZonedDateTime"); + return false; + } + + } + + @Override + public void describeTo(Description description) { + description.appendText("a String representing the same Instant as ").appendValue(date); + } + } + + /** + * Creates a matcher that matches when the examined string reprensents the same instant as the reference datetime + * @param date the reference datetime against which the examined string is checked + */ + public static ZonedDateTimeMatcher sameInstant(ZonedDateTime date) { + return new ZonedDateTimeMatcher(date); + } + + /** + * Verifies the equals/hashcode contract on the domain object. + */ + public static void equalsVerifier(Class clazz) throws Exception { + T domainObject1 = clazz.getConstructor().newInstance(); + assertThat(domainObject1.toString()).isNotNull(); + assertThat(domainObject1).isEqualTo(domainObject1); + assertThat(domainObject1.hashCode()).isEqualTo(domainObject1.hashCode()); + // Test with an instance of another class + Object testOtherObject = new Object(); + assertThat(domainObject1).isNotEqualTo(testOtherObject); + assertThat(domainObject1).isNotEqualTo(null); + // Test with an instance of the same class + T domainObject2 = clazz.getConstructor().newInstance(); + assertThat(domainObject1).isNotEqualTo(domainObject2); + // HashCodes are equals because the objects are not persisted yet + assertThat(domainObject1.hashCode()).isEqualTo(domainObject2.hashCode()); + } + + /** + * Create a FormattingConversionService which use ISO date format, instead of the localized one. + * @return the FormattingConversionService + */ + public static FormattingConversionService createFormattingConversionService() { + DefaultFormattingConversionService dfcs = new DefaultFormattingConversionService (); + DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar(); + registrar.setUseIsoFormat(true); + registrar.registerFormatters(dfcs); + return dfcs; + } + + private TestUtil() {} +} diff --git a/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/UserJWTControllerIntTest.java b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/UserJWTControllerIntTest.java new file mode 100644 index 0000000000..3886710438 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/UserJWTControllerIntTest.java @@ -0,0 +1,125 @@ +package com.baeldung.jhipster5.web.rest; + +import com.baeldung.jhipster5.BookstoreApp; +import com.baeldung.jhipster5.domain.User; +import com.baeldung.jhipster5.repository.UserRepository; +import com.baeldung.jhipster5.security.jwt.TokenProvider; +import com.baeldung.jhipster5.web.rest.errors.ExceptionTranslator; +import com.baeldung.jhipster5.web.rest.vm.LoginVM; +import org.junit.Before; +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.security.authentication.AuthenticationManager; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.transaction.annotation.Transactional; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; +import static org.hamcrest.Matchers.nullValue; +import static org.hamcrest.Matchers.isEmptyString; +import static org.hamcrest.Matchers.not; + +/** + * Test class for the UserJWTController REST controller. + * + * @see UserJWTController + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = BookstoreApp.class) +public class UserJWTControllerIntTest { + + @Autowired + private TokenProvider tokenProvider; + + @Autowired + private AuthenticationManager authenticationManager; + + @Autowired + private UserRepository userRepository; + + @Autowired + private PasswordEncoder passwordEncoder; + + @Autowired + private ExceptionTranslator exceptionTranslator; + + private MockMvc mockMvc; + + @Before + public void setup() { + UserJWTController userJWTController = new UserJWTController(tokenProvider, authenticationManager); + this.mockMvc = MockMvcBuilders.standaloneSetup(userJWTController) + .setControllerAdvice(exceptionTranslator) + .build(); + } + + @Test + @Transactional + public void testAuthorize() throws Exception { + User user = new User(); + user.setLogin("user-jwt-controller"); + user.setEmail("user-jwt-controller@example.com"); + user.setActivated(true); + user.setPassword(passwordEncoder.encode("test")); + + userRepository.saveAndFlush(user); + + LoginVM login = new LoginVM(); + login.setUsername("user-jwt-controller"); + login.setPassword("test"); + mockMvc.perform(post("/api/authenticate") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(login))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id_token").isString()) + .andExpect(jsonPath("$.id_token").isNotEmpty()) + .andExpect(header().string("Authorization", not(nullValue()))) + .andExpect(header().string("Authorization", not(isEmptyString()))); + } + + @Test + @Transactional + public void testAuthorizeWithRememberMe() throws Exception { + User user = new User(); + user.setLogin("user-jwt-controller-remember-me"); + user.setEmail("user-jwt-controller-remember-me@example.com"); + user.setActivated(true); + user.setPassword(passwordEncoder.encode("test")); + + userRepository.saveAndFlush(user); + + LoginVM login = new LoginVM(); + login.setUsername("user-jwt-controller-remember-me"); + login.setPassword("test"); + login.setRememberMe(true); + mockMvc.perform(post("/api/authenticate") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(login))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id_token").isString()) + .andExpect(jsonPath("$.id_token").isNotEmpty()) + .andExpect(header().string("Authorization", not(nullValue()))) + .andExpect(header().string("Authorization", not(isEmptyString()))); + } + + @Test + @Transactional + public void testAuthorizeFails() throws Exception { + LoginVM login = new LoginVM(); + login.setUsername("wrong-user"); + login.setPassword("wrong password"); + mockMvc.perform(post("/api/authenticate") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(login))) + .andExpect(status().isUnauthorized()) + .andExpect(jsonPath("$.id_token").doesNotExist()) + .andExpect(header().doesNotExist("Authorization")); + } +} diff --git a/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/UserResourceIntTest.java b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/UserResourceIntTest.java new file mode 100644 index 0000000000..d31df3b15c --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/UserResourceIntTest.java @@ -0,0 +1,596 @@ +package com.baeldung.jhipster5.web.rest; + +import com.baeldung.jhipster5.BookstoreApp; +import com.baeldung.jhipster5.domain.Authority; +import com.baeldung.jhipster5.domain.User; +import com.baeldung.jhipster5.repository.UserRepository; +import com.baeldung.jhipster5.security.AuthoritiesConstants; +import com.baeldung.jhipster5.service.MailService; +import com.baeldung.jhipster5.service.UserService; +import com.baeldung.jhipster5.service.dto.UserDTO; +import com.baeldung.jhipster5.service.mapper.UserMapper; +import com.baeldung.jhipster5.web.rest.errors.ExceptionTranslator; +import com.baeldung.jhipster5.web.rest.vm.ManagedUserVM; +import org.apache.commons.lang3.RandomStringUtils; +import org.junit.Before; +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.data.web.PageableHandlerMethodArgumentResolver; +import org.springframework.http.MediaType; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.transaction.annotation.Transactional; + +import javax.persistence.EntityManager; +import java.time.Instant; +import java.util.*; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.hamcrest.Matchers.hasItems; +import static org.hamcrest.Matchers.hasItem; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +/** + * Test class for the UserResource REST controller. + * + * @see UserResource + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = BookstoreApp.class) +public class UserResourceIntTest { + + private static final String DEFAULT_LOGIN = "johndoe"; + private static final String UPDATED_LOGIN = "jhipster"; + + private static final Long DEFAULT_ID = 1L; + + private static final String DEFAULT_PASSWORD = "passjohndoe"; + private static final String UPDATED_PASSWORD = "passjhipster"; + + private static final String DEFAULT_EMAIL = "johndoe@localhost"; + private static final String UPDATED_EMAIL = "jhipster@localhost"; + + private static final String DEFAULT_FIRSTNAME = "john"; + private static final String UPDATED_FIRSTNAME = "jhipsterFirstName"; + + private static final String DEFAULT_LASTNAME = "doe"; + private static final String UPDATED_LASTNAME = "jhipsterLastName"; + + private static final String DEFAULT_IMAGEURL = "http://placehold.it/50x50"; + private static final String UPDATED_IMAGEURL = "http://placehold.it/40x40"; + + private static final String DEFAULT_LANGKEY = "en"; + private static final String UPDATED_LANGKEY = "fr"; + + @Autowired + private UserRepository userRepository; + + @Autowired + private MailService mailService; + + @Autowired + private UserService userService; + + @Autowired + private UserMapper userMapper; + + @Autowired + private MappingJackson2HttpMessageConverter jacksonMessageConverter; + + @Autowired + private PageableHandlerMethodArgumentResolver pageableArgumentResolver; + + @Autowired + private ExceptionTranslator exceptionTranslator; + + @Autowired + private EntityManager em; + + private MockMvc restUserMockMvc; + + private User user; + + @Before + public void setup() { + UserResource userResource = new UserResource(userService, userRepository, mailService); + + this.restUserMockMvc = MockMvcBuilders.standaloneSetup(userResource) + .setCustomArgumentResolvers(pageableArgumentResolver) + .setControllerAdvice(exceptionTranslator) + .setMessageConverters(jacksonMessageConverter) + .build(); + } + + /** + * Create a User. + * + * This is a static method, as tests for other entities might also need it, + * if they test an entity which has a required relationship to the User entity. + */ + public static User createEntity(EntityManager em) { + User user = new User(); + user.setLogin(DEFAULT_LOGIN + RandomStringUtils.randomAlphabetic(5)); + user.setPassword(RandomStringUtils.random(60)); + user.setActivated(true); + user.setEmail(RandomStringUtils.randomAlphabetic(5) + DEFAULT_EMAIL); + user.setFirstName(DEFAULT_FIRSTNAME); + user.setLastName(DEFAULT_LASTNAME); + user.setImageUrl(DEFAULT_IMAGEURL); + user.setLangKey(DEFAULT_LANGKEY); + return user; + } + + @Before + public void initTest() { + user = createEntity(em); + user.setLogin(DEFAULT_LOGIN); + user.setEmail(DEFAULT_EMAIL); + } + + @Test + @Transactional + public void createUser() throws Exception { + int databaseSizeBeforeCreate = userRepository.findAll().size(); + + // Create the User + ManagedUserVM managedUserVM = new ManagedUserVM(); + managedUserVM.setLogin(DEFAULT_LOGIN); + managedUserVM.setPassword(DEFAULT_PASSWORD); + managedUserVM.setFirstName(DEFAULT_FIRSTNAME); + managedUserVM.setLastName(DEFAULT_LASTNAME); + managedUserVM.setEmail(DEFAULT_EMAIL); + managedUserVM.setActivated(true); + managedUserVM.setImageUrl(DEFAULT_IMAGEURL); + managedUserVM.setLangKey(DEFAULT_LANGKEY); + managedUserVM.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); + + restUserMockMvc.perform(post("/api/users") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(managedUserVM))) + .andExpect(status().isCreated()); + + // Validate the User in the database + List userList = userRepository.findAll(); + assertThat(userList).hasSize(databaseSizeBeforeCreate + 1); + User testUser = userList.get(userList.size() - 1); + assertThat(testUser.getLogin()).isEqualTo(DEFAULT_LOGIN); + assertThat(testUser.getFirstName()).isEqualTo(DEFAULT_FIRSTNAME); + assertThat(testUser.getLastName()).isEqualTo(DEFAULT_LASTNAME); + assertThat(testUser.getEmail()).isEqualTo(DEFAULT_EMAIL); + assertThat(testUser.getImageUrl()).isEqualTo(DEFAULT_IMAGEURL); + assertThat(testUser.getLangKey()).isEqualTo(DEFAULT_LANGKEY); + } + + @Test + @Transactional + public void createUserWithExistingId() throws Exception { + int databaseSizeBeforeCreate = userRepository.findAll().size(); + + ManagedUserVM managedUserVM = new ManagedUserVM(); + managedUserVM.setId(1L); + managedUserVM.setLogin(DEFAULT_LOGIN); + managedUserVM.setPassword(DEFAULT_PASSWORD); + managedUserVM.setFirstName(DEFAULT_FIRSTNAME); + managedUserVM.setLastName(DEFAULT_LASTNAME); + managedUserVM.setEmail(DEFAULT_EMAIL); + managedUserVM.setActivated(true); + managedUserVM.setImageUrl(DEFAULT_IMAGEURL); + managedUserVM.setLangKey(DEFAULT_LANGKEY); + managedUserVM.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); + + // An entity with an existing ID cannot be created, so this API call must fail + restUserMockMvc.perform(post("/api/users") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(managedUserVM))) + .andExpect(status().isBadRequest()); + + // Validate the User in the database + List userList = userRepository.findAll(); + assertThat(userList).hasSize(databaseSizeBeforeCreate); + } + + @Test + @Transactional + public void createUserWithExistingLogin() throws Exception { + // Initialize the database + userRepository.saveAndFlush(user); + int databaseSizeBeforeCreate = userRepository.findAll().size(); + + ManagedUserVM managedUserVM = new ManagedUserVM(); + managedUserVM.setLogin(DEFAULT_LOGIN);// this login should already be used + managedUserVM.setPassword(DEFAULT_PASSWORD); + managedUserVM.setFirstName(DEFAULT_FIRSTNAME); + managedUserVM.setLastName(DEFAULT_LASTNAME); + managedUserVM.setEmail("anothermail@localhost"); + managedUserVM.setActivated(true); + managedUserVM.setImageUrl(DEFAULT_IMAGEURL); + managedUserVM.setLangKey(DEFAULT_LANGKEY); + managedUserVM.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); + + // Create the User + restUserMockMvc.perform(post("/api/users") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(managedUserVM))) + .andExpect(status().isBadRequest()); + + // Validate the User in the database + List userList = userRepository.findAll(); + assertThat(userList).hasSize(databaseSizeBeforeCreate); + } + + @Test + @Transactional + public void createUserWithExistingEmail() throws Exception { + // Initialize the database + userRepository.saveAndFlush(user); + int databaseSizeBeforeCreate = userRepository.findAll().size(); + + ManagedUserVM managedUserVM = new ManagedUserVM(); + managedUserVM.setLogin("anotherlogin"); + managedUserVM.setPassword(DEFAULT_PASSWORD); + managedUserVM.setFirstName(DEFAULT_FIRSTNAME); + managedUserVM.setLastName(DEFAULT_LASTNAME); + managedUserVM.setEmail(DEFAULT_EMAIL);// this email should already be used + managedUserVM.setActivated(true); + managedUserVM.setImageUrl(DEFAULT_IMAGEURL); + managedUserVM.setLangKey(DEFAULT_LANGKEY); + managedUserVM.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); + + // Create the User + restUserMockMvc.perform(post("/api/users") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(managedUserVM))) + .andExpect(status().isBadRequest()); + + // Validate the User in the database + List userList = userRepository.findAll(); + assertThat(userList).hasSize(databaseSizeBeforeCreate); + } + + @Test + @Transactional + public void getAllUsers() throws Exception { + // Initialize the database + userRepository.saveAndFlush(user); + + // Get all the users + restUserMockMvc.perform(get("/api/users?sort=id,desc") + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)) + .andExpect(jsonPath("$.[*].login").value(hasItem(DEFAULT_LOGIN))) + .andExpect(jsonPath("$.[*].firstName").value(hasItem(DEFAULT_FIRSTNAME))) + .andExpect(jsonPath("$.[*].lastName").value(hasItem(DEFAULT_LASTNAME))) + .andExpect(jsonPath("$.[*].email").value(hasItem(DEFAULT_EMAIL))) + .andExpect(jsonPath("$.[*].imageUrl").value(hasItem(DEFAULT_IMAGEURL))) + .andExpect(jsonPath("$.[*].langKey").value(hasItem(DEFAULT_LANGKEY))); + } + + @Test + @Transactional + public void getUser() throws Exception { + // Initialize the database + userRepository.saveAndFlush(user); + + // Get the user + restUserMockMvc.perform(get("/api/users/{login}", user.getLogin())) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)) + .andExpect(jsonPath("$.login").value(user.getLogin())) + .andExpect(jsonPath("$.firstName").value(DEFAULT_FIRSTNAME)) + .andExpect(jsonPath("$.lastName").value(DEFAULT_LASTNAME)) + .andExpect(jsonPath("$.email").value(DEFAULT_EMAIL)) + .andExpect(jsonPath("$.imageUrl").value(DEFAULT_IMAGEURL)) + .andExpect(jsonPath("$.langKey").value(DEFAULT_LANGKEY)); + } + + @Test + @Transactional + public void getNonExistingUser() throws Exception { + restUserMockMvc.perform(get("/api/users/unknown")) + .andExpect(status().isNotFound()); + } + + @Test + @Transactional + public void updateUser() throws Exception { + // Initialize the database + userRepository.saveAndFlush(user); + int databaseSizeBeforeUpdate = userRepository.findAll().size(); + + // Update the user + User updatedUser = userRepository.findById(user.getId()).get(); + + ManagedUserVM managedUserVM = new ManagedUserVM(); + managedUserVM.setId(updatedUser.getId()); + managedUserVM.setLogin(updatedUser.getLogin()); + managedUserVM.setPassword(UPDATED_PASSWORD); + managedUserVM.setFirstName(UPDATED_FIRSTNAME); + managedUserVM.setLastName(UPDATED_LASTNAME); + managedUserVM.setEmail(UPDATED_EMAIL); + managedUserVM.setActivated(updatedUser.getActivated()); + managedUserVM.setImageUrl(UPDATED_IMAGEURL); + managedUserVM.setLangKey(UPDATED_LANGKEY); + managedUserVM.setCreatedBy(updatedUser.getCreatedBy()); + managedUserVM.setCreatedDate(updatedUser.getCreatedDate()); + managedUserVM.setLastModifiedBy(updatedUser.getLastModifiedBy()); + managedUserVM.setLastModifiedDate(updatedUser.getLastModifiedDate()); + managedUserVM.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); + + restUserMockMvc.perform(put("/api/users") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(managedUserVM))) + .andExpect(status().isOk()); + + // Validate the User in the database + List userList = userRepository.findAll(); + assertThat(userList).hasSize(databaseSizeBeforeUpdate); + User testUser = userList.get(userList.size() - 1); + assertThat(testUser.getFirstName()).isEqualTo(UPDATED_FIRSTNAME); + assertThat(testUser.getLastName()).isEqualTo(UPDATED_LASTNAME); + assertThat(testUser.getEmail()).isEqualTo(UPDATED_EMAIL); + assertThat(testUser.getImageUrl()).isEqualTo(UPDATED_IMAGEURL); + assertThat(testUser.getLangKey()).isEqualTo(UPDATED_LANGKEY); + } + + @Test + @Transactional + public void updateUserLogin() throws Exception { + // Initialize the database + userRepository.saveAndFlush(user); + int databaseSizeBeforeUpdate = userRepository.findAll().size(); + + // Update the user + User updatedUser = userRepository.findById(user.getId()).get(); + + ManagedUserVM managedUserVM = new ManagedUserVM(); + managedUserVM.setId(updatedUser.getId()); + managedUserVM.setLogin(UPDATED_LOGIN); + managedUserVM.setPassword(UPDATED_PASSWORD); + managedUserVM.setFirstName(UPDATED_FIRSTNAME); + managedUserVM.setLastName(UPDATED_LASTNAME); + managedUserVM.setEmail(UPDATED_EMAIL); + managedUserVM.setActivated(updatedUser.getActivated()); + managedUserVM.setImageUrl(UPDATED_IMAGEURL); + managedUserVM.setLangKey(UPDATED_LANGKEY); + managedUserVM.setCreatedBy(updatedUser.getCreatedBy()); + managedUserVM.setCreatedDate(updatedUser.getCreatedDate()); + managedUserVM.setLastModifiedBy(updatedUser.getLastModifiedBy()); + managedUserVM.setLastModifiedDate(updatedUser.getLastModifiedDate()); + managedUserVM.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); + + restUserMockMvc.perform(put("/api/users") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(managedUserVM))) + .andExpect(status().isOk()); + + // Validate the User in the database + List userList = userRepository.findAll(); + assertThat(userList).hasSize(databaseSizeBeforeUpdate); + User testUser = userList.get(userList.size() - 1); + assertThat(testUser.getLogin()).isEqualTo(UPDATED_LOGIN); + assertThat(testUser.getFirstName()).isEqualTo(UPDATED_FIRSTNAME); + assertThat(testUser.getLastName()).isEqualTo(UPDATED_LASTNAME); + assertThat(testUser.getEmail()).isEqualTo(UPDATED_EMAIL); + assertThat(testUser.getImageUrl()).isEqualTo(UPDATED_IMAGEURL); + assertThat(testUser.getLangKey()).isEqualTo(UPDATED_LANGKEY); + } + + @Test + @Transactional + public void updateUserExistingEmail() throws Exception { + // Initialize the database with 2 users + userRepository.saveAndFlush(user); + + User anotherUser = new User(); + anotherUser.setLogin("jhipster"); + anotherUser.setPassword(RandomStringUtils.random(60)); + anotherUser.setActivated(true); + anotherUser.setEmail("jhipster@localhost"); + anotherUser.setFirstName("java"); + anotherUser.setLastName("hipster"); + anotherUser.setImageUrl(""); + anotherUser.setLangKey("en"); + userRepository.saveAndFlush(anotherUser); + + // Update the user + User updatedUser = userRepository.findById(user.getId()).get(); + + ManagedUserVM managedUserVM = new ManagedUserVM(); + managedUserVM.setId(updatedUser.getId()); + managedUserVM.setLogin(updatedUser.getLogin()); + managedUserVM.setPassword(updatedUser.getPassword()); + managedUserVM.setFirstName(updatedUser.getFirstName()); + managedUserVM.setLastName(updatedUser.getLastName()); + managedUserVM.setEmail("jhipster@localhost");// this email should already be used by anotherUser + managedUserVM.setActivated(updatedUser.getActivated()); + managedUserVM.setImageUrl(updatedUser.getImageUrl()); + managedUserVM.setLangKey(updatedUser.getLangKey()); + managedUserVM.setCreatedBy(updatedUser.getCreatedBy()); + managedUserVM.setCreatedDate(updatedUser.getCreatedDate()); + managedUserVM.setLastModifiedBy(updatedUser.getLastModifiedBy()); + managedUserVM.setLastModifiedDate(updatedUser.getLastModifiedDate()); + managedUserVM.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); + + restUserMockMvc.perform(put("/api/users") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(managedUserVM))) + .andExpect(status().isBadRequest()); + } + + @Test + @Transactional + public void updateUserExistingLogin() throws Exception { + // Initialize the database + userRepository.saveAndFlush(user); + + User anotherUser = new User(); + anotherUser.setLogin("jhipster"); + anotherUser.setPassword(RandomStringUtils.random(60)); + anotherUser.setActivated(true); + anotherUser.setEmail("jhipster@localhost"); + anotherUser.setFirstName("java"); + anotherUser.setLastName("hipster"); + anotherUser.setImageUrl(""); + anotherUser.setLangKey("en"); + userRepository.saveAndFlush(anotherUser); + + // Update the user + User updatedUser = userRepository.findById(user.getId()).get(); + + ManagedUserVM managedUserVM = new ManagedUserVM(); + managedUserVM.setId(updatedUser.getId()); + managedUserVM.setLogin("jhipster");// this login should already be used by anotherUser + managedUserVM.setPassword(updatedUser.getPassword()); + managedUserVM.setFirstName(updatedUser.getFirstName()); + managedUserVM.setLastName(updatedUser.getLastName()); + managedUserVM.setEmail(updatedUser.getEmail()); + managedUserVM.setActivated(updatedUser.getActivated()); + managedUserVM.setImageUrl(updatedUser.getImageUrl()); + managedUserVM.setLangKey(updatedUser.getLangKey()); + managedUserVM.setCreatedBy(updatedUser.getCreatedBy()); + managedUserVM.setCreatedDate(updatedUser.getCreatedDate()); + managedUserVM.setLastModifiedBy(updatedUser.getLastModifiedBy()); + managedUserVM.setLastModifiedDate(updatedUser.getLastModifiedDate()); + managedUserVM.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); + + restUserMockMvc.perform(put("/api/users") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(managedUserVM))) + .andExpect(status().isBadRequest()); + } + + @Test + @Transactional + public void deleteUser() throws Exception { + // Initialize the database + userRepository.saveAndFlush(user); + int databaseSizeBeforeDelete = userRepository.findAll().size(); + + // Delete the user + restUserMockMvc.perform(delete("/api/users/{login}", user.getLogin()) + .accept(TestUtil.APPLICATION_JSON_UTF8)) + .andExpect(status().isOk()); + + // Validate the database is empty + List userList = userRepository.findAll(); + assertThat(userList).hasSize(databaseSizeBeforeDelete - 1); + } + + @Test + @Transactional + public void getAllAuthorities() throws Exception { + restUserMockMvc.perform(get("/api/users/authorities") + .accept(TestUtil.APPLICATION_JSON_UTF8) + .contentType(TestUtil.APPLICATION_JSON_UTF8)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)) + .andExpect(jsonPath("$").isArray()) + .andExpect(jsonPath("$").value(hasItems(AuthoritiesConstants.USER, AuthoritiesConstants.ADMIN))); + } + + @Test + @Transactional + public void testUserEquals() throws Exception { + TestUtil.equalsVerifier(User.class); + User user1 = new User(); + user1.setId(1L); + User user2 = new User(); + user2.setId(user1.getId()); + assertThat(user1).isEqualTo(user2); + user2.setId(2L); + assertThat(user1).isNotEqualTo(user2); + user1.setId(null); + assertThat(user1).isNotEqualTo(user2); + } + + @Test + public void testUserDTOtoUser() { + UserDTO userDTO = new UserDTO(); + userDTO.setId(DEFAULT_ID); + userDTO.setLogin(DEFAULT_LOGIN); + userDTO.setFirstName(DEFAULT_FIRSTNAME); + userDTO.setLastName(DEFAULT_LASTNAME); + userDTO.setEmail(DEFAULT_EMAIL); + userDTO.setActivated(true); + userDTO.setImageUrl(DEFAULT_IMAGEURL); + userDTO.setLangKey(DEFAULT_LANGKEY); + userDTO.setCreatedBy(DEFAULT_LOGIN); + userDTO.setLastModifiedBy(DEFAULT_LOGIN); + userDTO.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); + + User user = userMapper.userDTOToUser(userDTO); + assertThat(user.getId()).isEqualTo(DEFAULT_ID); + assertThat(user.getLogin()).isEqualTo(DEFAULT_LOGIN); + assertThat(user.getFirstName()).isEqualTo(DEFAULT_FIRSTNAME); + assertThat(user.getLastName()).isEqualTo(DEFAULT_LASTNAME); + assertThat(user.getEmail()).isEqualTo(DEFAULT_EMAIL); + assertThat(user.getActivated()).isEqualTo(true); + assertThat(user.getImageUrl()).isEqualTo(DEFAULT_IMAGEURL); + assertThat(user.getLangKey()).isEqualTo(DEFAULT_LANGKEY); + assertThat(user.getCreatedBy()).isNull(); + assertThat(user.getCreatedDate()).isNotNull(); + assertThat(user.getLastModifiedBy()).isNull(); + assertThat(user.getLastModifiedDate()).isNotNull(); + assertThat(user.getAuthorities()).extracting("name").containsExactly(AuthoritiesConstants.USER); + } + + @Test + public void testUserToUserDTO() { + user.setId(DEFAULT_ID); + user.setCreatedBy(DEFAULT_LOGIN); + user.setCreatedDate(Instant.now()); + user.setLastModifiedBy(DEFAULT_LOGIN); + user.setLastModifiedDate(Instant.now()); + Set authorities = new HashSet<>(); + Authority authority = new Authority(); + authority.setName(AuthoritiesConstants.USER); + authorities.add(authority); + user.setAuthorities(authorities); + + UserDTO userDTO = userMapper.userToUserDTO(user); + + assertThat(userDTO.getId()).isEqualTo(DEFAULT_ID); + assertThat(userDTO.getLogin()).isEqualTo(DEFAULT_LOGIN); + assertThat(userDTO.getFirstName()).isEqualTo(DEFAULT_FIRSTNAME); + assertThat(userDTO.getLastName()).isEqualTo(DEFAULT_LASTNAME); + assertThat(userDTO.getEmail()).isEqualTo(DEFAULT_EMAIL); + assertThat(userDTO.isActivated()).isEqualTo(true); + assertThat(userDTO.getImageUrl()).isEqualTo(DEFAULT_IMAGEURL); + assertThat(userDTO.getLangKey()).isEqualTo(DEFAULT_LANGKEY); + assertThat(userDTO.getCreatedBy()).isEqualTo(DEFAULT_LOGIN); + assertThat(userDTO.getCreatedDate()).isEqualTo(user.getCreatedDate()); + assertThat(userDTO.getLastModifiedBy()).isEqualTo(DEFAULT_LOGIN); + assertThat(userDTO.getLastModifiedDate()).isEqualTo(user.getLastModifiedDate()); + assertThat(userDTO.getAuthorities()).containsExactly(AuthoritiesConstants.USER); + assertThat(userDTO.toString()).isNotNull(); + } + + @Test + public void testAuthorityEquals() { + Authority authorityA = new Authority(); + assertThat(authorityA).isEqualTo(authorityA); + assertThat(authorityA).isNotEqualTo(null); + assertThat(authorityA).isNotEqualTo(new Object()); + assertThat(authorityA.hashCode()).isEqualTo(0); + assertThat(authorityA.toString()).isNotNull(); + + Authority authorityB = new Authority(); + assertThat(authorityA).isEqualTo(authorityB); + + authorityB.setName(AuthoritiesConstants.ADMIN); + assertThat(authorityA).isNotEqualTo(authorityB); + + authorityA.setName(AuthoritiesConstants.USER); + assertThat(authorityA).isNotEqualTo(authorityB); + + authorityB.setName(AuthoritiesConstants.USER); + assertThat(authorityA).isEqualTo(authorityB); + assertThat(authorityA.hashCode()).isEqualTo(authorityB.hashCode()); + } +} diff --git a/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/errors/ExceptionTranslatorIntTest.java b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/errors/ExceptionTranslatorIntTest.java new file mode 100644 index 0000000000..a94d54063b --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/errors/ExceptionTranslatorIntTest.java @@ -0,0 +1,150 @@ +package com.baeldung.jhipster5.web.rest.errors; + +import com.baeldung.jhipster5.BookstoreApp; +import org.junit.Before; +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.http.MediaType; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +/** + * Test class for the ExceptionTranslator controller advice. + * + * @see ExceptionTranslator + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = BookstoreApp.class) +public class ExceptionTranslatorIntTest { + + @Autowired + private ExceptionTranslatorTestController controller; + + @Autowired + private ExceptionTranslator exceptionTranslator; + + @Autowired + private MappingJackson2HttpMessageConverter jacksonMessageConverter; + + private MockMvc mockMvc; + + @Before + public void setup() { + mockMvc = MockMvcBuilders.standaloneSetup(controller) + .setControllerAdvice(exceptionTranslator) + .setMessageConverters(jacksonMessageConverter) + .build(); + } + + @Test + public void testConcurrencyFailure() throws Exception { + mockMvc.perform(get("/test/concurrency-failure")) + .andExpect(status().isConflict()) + .andExpect(content().contentType(MediaType.APPLICATION_PROBLEM_JSON)) + .andExpect(jsonPath("$.message").value(ErrorConstants.ERR_CONCURRENCY_FAILURE)); + } + + @Test + public void testMethodArgumentNotValid() throws Exception { + mockMvc.perform(post("/test/method-argument").content("{}").contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest()) + .andExpect(content().contentType(MediaType.APPLICATION_PROBLEM_JSON)) + .andExpect(jsonPath("$.message").value(ErrorConstants.ERR_VALIDATION)) + .andExpect(jsonPath("$.fieldErrors.[0].objectName").value("testDTO")) + .andExpect(jsonPath("$.fieldErrors.[0].field").value("test")) + .andExpect(jsonPath("$.fieldErrors.[0].message").value("NotNull")); + } + + @Test + public void testParameterizedError() throws Exception { + mockMvc.perform(get("/test/parameterized-error")) + .andExpect(status().isBadRequest()) + .andExpect(content().contentType(MediaType.APPLICATION_PROBLEM_JSON)) + .andExpect(jsonPath("$.message").value("test parameterized error")) + .andExpect(jsonPath("$.params.param0").value("param0_value")) + .andExpect(jsonPath("$.params.param1").value("param1_value")); + } + + @Test + public void testParameterizedError2() throws Exception { + mockMvc.perform(get("/test/parameterized-error2")) + .andExpect(status().isBadRequest()) + .andExpect(content().contentType(MediaType.APPLICATION_PROBLEM_JSON)) + .andExpect(jsonPath("$.message").value("test parameterized error")) + .andExpect(jsonPath("$.params.foo").value("foo_value")) + .andExpect(jsonPath("$.params.bar").value("bar_value")); + } + + @Test + public void testMissingServletRequestPartException() throws Exception { + mockMvc.perform(get("/test/missing-servlet-request-part")) + .andExpect(status().isBadRequest()) + .andExpect(content().contentType(MediaType.APPLICATION_PROBLEM_JSON)) + .andExpect(jsonPath("$.message").value("error.http.400")); + } + + @Test + public void testMissingServletRequestParameterException() throws Exception { + mockMvc.perform(get("/test/missing-servlet-request-parameter")) + .andExpect(status().isBadRequest()) + .andExpect(content().contentType(MediaType.APPLICATION_PROBLEM_JSON)) + .andExpect(jsonPath("$.message").value("error.http.400")); + } + + @Test + public void testAccessDenied() throws Exception { + mockMvc.perform(get("/test/access-denied")) + .andExpect(status().isForbidden()) + .andExpect(content().contentType(MediaType.APPLICATION_PROBLEM_JSON)) + .andExpect(jsonPath("$.message").value("error.http.403")) + .andExpect(jsonPath("$.detail").value("test access denied!")); + } + + @Test + public void testUnauthorized() throws Exception { + mockMvc.perform(get("/test/unauthorized")) + .andExpect(status().isUnauthorized()) + .andExpect(content().contentType(MediaType.APPLICATION_PROBLEM_JSON)) + .andExpect(jsonPath("$.message").value("error.http.401")) + .andExpect(jsonPath("$.path").value("/test/unauthorized")) + .andExpect(jsonPath("$.detail").value("test authentication failed!")); + } + + @Test + public void testMethodNotSupported() throws Exception { + mockMvc.perform(post("/test/access-denied")) + .andExpect(status().isMethodNotAllowed()) + .andExpect(content().contentType(MediaType.APPLICATION_PROBLEM_JSON)) + .andExpect(jsonPath("$.message").value("error.http.405")) + .andExpect(jsonPath("$.detail").value("Request method 'POST' not supported")); + } + + @Test + public void testExceptionWithResponseStatus() throws Exception { + mockMvc.perform(get("/test/response-status")) + .andExpect(status().isBadRequest()) + .andExpect(content().contentType(MediaType.APPLICATION_PROBLEM_JSON)) + .andExpect(jsonPath("$.message").value("error.http.400")) + .andExpect(jsonPath("$.title").value("test response status")); + } + + @Test + public void testInternalServerError() throws Exception { + mockMvc.perform(get("/test/internal-server-error")) + .andExpect(status().isInternalServerError()) + .andExpect(content().contentType(MediaType.APPLICATION_PROBLEM_JSON)) + .andExpect(jsonPath("$.message").value("error.http.500")) + .andExpect(jsonPath("$.title").value("Internal Server Error")); + } + +} diff --git a/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/errors/ExceptionTranslatorTestController.java b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/errors/ExceptionTranslatorTestController.java new file mode 100644 index 0000000000..f8d84151b9 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/errors/ExceptionTranslatorTestController.java @@ -0,0 +1,86 @@ +package com.baeldung.jhipster5.web.rest.errors; + +import org.springframework.dao.ConcurrencyFailureException; +import org.springframework.http.HttpStatus; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import java.util.HashMap; +import java.util.Map; + +@RestController +public class ExceptionTranslatorTestController { + + @GetMapping("/test/concurrency-failure") + public void concurrencyFailure() { + throw new ConcurrencyFailureException("test concurrency failure"); + } + + @PostMapping("/test/method-argument") + public void methodArgument(@Valid @RequestBody TestDTO testDTO) { + } + + @GetMapping("/test/parameterized-error") + public void parameterizedError() { + throw new CustomParameterizedException("test parameterized error", "param0_value", "param1_value"); + } + + @GetMapping("/test/parameterized-error2") + public void parameterizedError2() { + Map params = new HashMap<>(); + params.put("foo", "foo_value"); + params.put("bar", "bar_value"); + throw new CustomParameterizedException("test parameterized error", params); + } + + @GetMapping("/test/missing-servlet-request-part") + public void missingServletRequestPartException(@RequestPart String part) { + } + + @GetMapping("/test/missing-servlet-request-parameter") + public void missingServletRequestParameterException(@RequestParam String param) { + } + + @GetMapping("/test/access-denied") + public void accessdenied() { + throw new AccessDeniedException("test access denied!"); + } + + @GetMapping("/test/unauthorized") + public void unauthorized() { + throw new BadCredentialsException("test authentication failed!"); + } + + @GetMapping("/test/response-status") + public void exceptionWithReponseStatus() { + throw new TestResponseStatusException(); + } + + @GetMapping("/test/internal-server-error") + public void internalServerError() { + throw new RuntimeException(); + } + + public static class TestDTO { + + @NotNull + private String test; + + public String getTest() { + return test; + } + + public void setTest(String test) { + this.test = test; + } + } + + @ResponseStatus(value = HttpStatus.BAD_REQUEST, reason = "test response status") + @SuppressWarnings("serial") + public static class TestResponseStatusException extends RuntimeException { + } + +} diff --git a/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/util/PaginationUtilUnitTest.java b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/util/PaginationUtilUnitTest.java new file mode 100644 index 0000000000..78b17ee859 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/util/PaginationUtilUnitTest.java @@ -0,0 +1,44 @@ +package com.baeldung.jhipster5.web.rest.util; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Test; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.PageRequest; +import org.springframework.http.HttpHeaders; + +/** + * Tests based on parsing algorithm in app/components/util/pagination-util.service.js + * + * @see PaginationUtil + */ +public class PaginationUtilUnitTest { + + @Test + public void generatePaginationHttpHeadersTest() { + String baseUrl = "/api/_search/example"; + List content = new ArrayList<>(); + Page page = new PageImpl<>(content, PageRequest.of(6, 50), 400L); + HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, baseUrl); + List strHeaders = headers.get(HttpHeaders.LINK); + assertNotNull(strHeaders); + assertTrue(strHeaders.size() == 1); + String headerData = strHeaders.get(0); + assertTrue(headerData.split(",").length == 4); + String expectedData = "; rel=\"next\"," + + "; rel=\"prev\"," + + "; rel=\"last\"," + + "; rel=\"first\""; + assertEquals(expectedData, headerData); + List xTotalCountHeaders = headers.get("X-Total-Count"); + assertTrue(xTotalCountHeaders.size() == 1); + assertTrue(Long.valueOf(xTotalCountHeaders.get(0)).equals(400L)); + } + +} diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/jest-global-mocks.ts b/jhipster-5/bookstore-monolith/src/test/javascript/jest-global-mocks.ts new file mode 100644 index 0000000000..a998259857 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/jest-global-mocks.ts @@ -0,0 +1,15 @@ +const mock = () => { + let storage = {}; + return { + getItem: key => (key in storage ? storage[key] : null), + setItem: (key, value) => (storage[key] = value || ''), + removeItem: key => delete storage[key], + clear: () => (storage = {}) + }; +}; + +Object.defineProperty(window, 'localStorage', { value: mock() }); +Object.defineProperty(window, 'sessionStorage', { value: mock() }); +Object.defineProperty(window, 'getComputedStyle', { + value: () => ['-webkit-appearance'] +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/jest.conf.js b/jhipster-5/bookstore-monolith/src/test/javascript/jest.conf.js new file mode 100644 index 0000000000..05054a94b8 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/jest.conf.js @@ -0,0 +1,26 @@ +module.exports = { + preset: 'jest-preset-angular', + setupTestFrameworkScriptFile: '/src/test/javascript/jest.ts', + coverageDirectory: '/target/test-results/', + globals: { + 'ts-jest': { + tsConfigFile: 'tsconfig.json' + }, + __TRANSFORM_HTML__: true + }, + coveragePathIgnorePatterns: [ + '/src/test/javascript' + ], + moduleNameMapper: { + 'app/(.*)': '/src/main/webapp/app/$1' + }, + reporters: [ + 'default', + [ 'jest-junit', { output: './target/test-results/TESTS-results-jest.xml' } ] + ], + testResultsProcessor: 'jest-sonar-reporter', + transformIgnorePatterns: ['node_modules/(?!@angular/common/locales)'], + testMatch: ['/src/test/javascript/spec/**/+(*.)+(spec.ts)'], + rootDir: '../../../', + testURL: "http://localhost/" +}; diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/jest.ts b/jhipster-5/bookstore-monolith/src/test/javascript/jest.ts new file mode 100644 index 0000000000..904329f538 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/jest.ts @@ -0,0 +1,2 @@ +import 'jest-preset-angular'; +import './jest-global-mocks'; diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/account/activate/activate.component.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/account/activate/activate.component.spec.ts new file mode 100644 index 0000000000..87a550e8ef --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/account/activate/activate.component.spec.ts @@ -0,0 +1,72 @@ +import { TestBed, async, tick, fakeAsync, inject } from '@angular/core/testing'; +import { ActivatedRoute } from '@angular/router'; +import { Observable, of, throwError } from 'rxjs'; + +import { BookstoreTestModule } from '../../../test.module'; +import { MockActivatedRoute } from '../../../helpers/mock-route.service'; +import { ActivateService } from 'app/account/activate/activate.service'; +import { ActivateComponent } from 'app/account/activate/activate.component'; + +describe('Component Tests', () => { + describe('ActivateComponent', () => { + let comp: ActivateComponent; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [BookstoreTestModule], + declarations: [ActivateComponent], + providers: [ + { + provide: ActivatedRoute, + useValue: new MockActivatedRoute({ key: 'ABC123' }) + } + ] + }) + .overrideTemplate(ActivateComponent, '') + .compileComponents(); + })); + + beforeEach(() => { + const fixture = TestBed.createComponent(ActivateComponent); + comp = fixture.componentInstance; + }); + + it('calls activate.get with the key from params', inject( + [ActivateService], + fakeAsync((service: ActivateService) => { + spyOn(service, 'get').and.returnValue(of()); + + comp.ngOnInit(); + tick(); + + expect(service.get).toHaveBeenCalledWith('ABC123'); + }) + )); + + it('should set set success to OK upon successful activation', inject( + [ActivateService], + fakeAsync((service: ActivateService) => { + spyOn(service, 'get').and.returnValue(of({})); + + comp.ngOnInit(); + tick(); + + expect(comp.error).toBe(null); + expect(comp.success).toEqual('OK'); + }) + )); + + it('should set set error to ERROR upon activation failure', inject( + [ActivateService], + fakeAsync((service: ActivateService) => { + spyOn(service, 'get').and.returnValue(throwError('ERROR')); + + comp.ngOnInit(); + tick(); + + expect(comp.error).toBe('ERROR'); + expect(comp.success).toEqual(null); + }) + )); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/account/password-reset/finish/password-reset-finish.component.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/account/password-reset/finish/password-reset-finish.component.spec.ts new file mode 100644 index 0000000000..36a3b8db65 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/account/password-reset/finish/password-reset-finish.component.spec.ts @@ -0,0 +1,119 @@ +import { ComponentFixture, TestBed, inject, tick, fakeAsync } from '@angular/core/testing'; +import { Observable, of, throwError } from 'rxjs'; +import { Renderer, ElementRef } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; + +import { BookstoreTestModule } from '../../../../test.module'; +import { PasswordResetFinishComponent } from 'app/account/password-reset/finish/password-reset-finish.component'; +import { PasswordResetFinishService } from 'app/account/password-reset/finish/password-reset-finish.service'; +import { MockActivatedRoute } from '../../../../helpers/mock-route.service'; + +describe('Component Tests', () => { + describe('PasswordResetFinishComponent', () => { + let fixture: ComponentFixture; + let comp: PasswordResetFinishComponent; + + beforeEach(() => { + fixture = TestBed.configureTestingModule({ + imports: [BookstoreTestModule], + declarations: [PasswordResetFinishComponent], + providers: [ + { + provide: ActivatedRoute, + useValue: new MockActivatedRoute({ key: 'XYZPDQ' }) + }, + { + provide: Renderer, + useValue: { + invokeElementMethod(renderElement: any, methodName: string, args?: any[]) {} + } + }, + { + provide: ElementRef, + useValue: new ElementRef(null) + } + ] + }) + .overrideTemplate(PasswordResetFinishComponent, '') + .createComponent(PasswordResetFinishComponent); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(PasswordResetFinishComponent); + comp = fixture.componentInstance; + comp.ngOnInit(); + }); + + it('should define its initial state', () => { + comp.ngOnInit(); + + expect(comp.keyMissing).toBeFalsy(); + expect(comp.key).toEqual('XYZPDQ'); + expect(comp.resetAccount).toEqual({}); + }); + + it('sets focus after the view has been initialized', inject([ElementRef], (elementRef: ElementRef) => { + const element = fixture.nativeElement; + const node = { + focus() {} + }; + + elementRef.nativeElement = element; + spyOn(element, 'querySelector').and.returnValue(node); + spyOn(node, 'focus'); + + comp.ngAfterViewInit(); + + expect(element.querySelector).toHaveBeenCalledWith('#password'); + expect(node.focus).toHaveBeenCalled(); + })); + + it('should ensure the two passwords entered match', () => { + comp.resetAccount.password = 'password'; + comp.confirmPassword = 'non-matching'; + + comp.finishReset(); + + expect(comp.doNotMatch).toEqual('ERROR'); + }); + + it('should update success to OK after resetting password', inject( + [PasswordResetFinishService], + fakeAsync((service: PasswordResetFinishService) => { + spyOn(service, 'save').and.returnValue(of({})); + + comp.resetAccount.password = 'password'; + comp.confirmPassword = 'password'; + + comp.finishReset(); + tick(); + + expect(service.save).toHaveBeenCalledWith({ + key: 'XYZPDQ', + newPassword: 'password' + }); + expect(comp.success).toEqual('OK'); + }) + )); + + it('should notify of generic error', inject( + [PasswordResetFinishService], + fakeAsync((service: PasswordResetFinishService) => { + spyOn(service, 'save').and.returnValue(throwError('ERROR')); + + comp.resetAccount.password = 'password'; + comp.confirmPassword = 'password'; + + comp.finishReset(); + tick(); + + expect(service.save).toHaveBeenCalledWith({ + key: 'XYZPDQ', + newPassword: 'password' + }); + expect(comp.success).toBeNull(); + expect(comp.error).toEqual('ERROR'); + }) + )); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/account/password-reset/init/password-reset-init.component.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/account/password-reset/init/password-reset-init.component.spec.ts new file mode 100644 index 0000000000..f121a4dd27 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/account/password-reset/init/password-reset-init.component.spec.ts @@ -0,0 +1,110 @@ +import { ComponentFixture, TestBed, inject } from '@angular/core/testing'; +import { Renderer, ElementRef } from '@angular/core'; +import { Observable, of, throwError } from 'rxjs'; + +import { BookstoreTestModule } from '../../../../test.module'; +import { PasswordResetInitComponent } from 'app/account/password-reset/init/password-reset-init.component'; +import { PasswordResetInitService } from 'app/account/password-reset/init/password-reset-init.service'; +import { EMAIL_NOT_FOUND_TYPE } from 'app/shared'; + +describe('Component Tests', () => { + describe('PasswordResetInitComponent', () => { + let fixture: ComponentFixture; + let comp: PasswordResetInitComponent; + + beforeEach(() => { + fixture = TestBed.configureTestingModule({ + imports: [BookstoreTestModule], + declarations: [PasswordResetInitComponent], + providers: [ + { + provide: Renderer, + useValue: { + invokeElementMethod(renderElement: any, methodName: string, args?: any[]) {} + } + }, + { + provide: ElementRef, + useValue: new ElementRef(null) + } + ] + }) + .overrideTemplate(PasswordResetInitComponent, '') + .createComponent(PasswordResetInitComponent); + comp = fixture.componentInstance; + comp.ngOnInit(); + }); + + it('should define its initial state', () => { + expect(comp.success).toBeUndefined(); + expect(comp.error).toBeUndefined(); + expect(comp.errorEmailNotExists).toBeUndefined(); + expect(comp.resetAccount).toEqual({}); + }); + + it('sets focus after the view has been initialized', inject([ElementRef], (elementRef: ElementRef) => { + const element = fixture.nativeElement; + const node = { + focus() {} + }; + + elementRef.nativeElement = element; + spyOn(element, 'querySelector').and.returnValue(node); + spyOn(node, 'focus'); + + comp.ngAfterViewInit(); + + expect(element.querySelector).toHaveBeenCalledWith('#email'); + expect(node.focus).toHaveBeenCalled(); + })); + + it('notifies of success upon successful requestReset', inject([PasswordResetInitService], (service: PasswordResetInitService) => { + spyOn(service, 'save').and.returnValue(of({})); + comp.resetAccount.email = 'user@domain.com'; + + comp.requestReset(); + + expect(service.save).toHaveBeenCalledWith('user@domain.com'); + expect(comp.success).toEqual('OK'); + expect(comp.error).toBeNull(); + expect(comp.errorEmailNotExists).toBeNull(); + })); + + it('notifies of unknown email upon email address not registered/400', inject( + [PasswordResetInitService], + (service: PasswordResetInitService) => { + spyOn(service, 'save').and.returnValue( + throwError({ + status: 400, + error: { type: EMAIL_NOT_FOUND_TYPE } + }) + ); + comp.resetAccount.email = 'user@domain.com'; + + comp.requestReset(); + + expect(service.save).toHaveBeenCalledWith('user@domain.com'); + expect(comp.success).toBeNull(); + expect(comp.error).toBeNull(); + expect(comp.errorEmailNotExists).toEqual('ERROR'); + } + )); + + it('notifies of error upon error response', inject([PasswordResetInitService], (service: PasswordResetInitService) => { + spyOn(service, 'save').and.returnValue( + throwError({ + status: 503, + data: 'something else' + }) + ); + comp.resetAccount.email = 'user@domain.com'; + + comp.requestReset(); + + expect(service.save).toHaveBeenCalledWith('user@domain.com'); + expect(comp.success).toBeNull(); + expect(comp.errorEmailNotExists).toBeNull(); + expect(comp.error).toEqual('ERROR'); + })); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/account/password/password-strength-bar.component.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/account/password/password-strength-bar.component.spec.ts new file mode 100644 index 0000000000..35e923ac00 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/account/password/password-strength-bar.component.spec.ts @@ -0,0 +1,48 @@ +import { ComponentFixture, TestBed, async } from '@angular/core/testing'; + +import { PasswordStrengthBarComponent } from 'app/account/password/password-strength-bar.component'; + +describe('Component Tests', () => { + describe('PasswordStrengthBarComponent', () => { + let comp: PasswordStrengthBarComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [PasswordStrengthBarComponent] + }) + .overrideTemplate(PasswordStrengthBarComponent, '') + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(PasswordStrengthBarComponent); + comp = fixture.componentInstance; + }); + + describe('PasswordStrengthBarComponents', () => { + it('should initialize with default values', () => { + expect(comp.measureStrength('')).toBe(0); + expect(comp.colors).toEqual(['#F00', '#F90', '#FF0', '#9F0', '#0F0']); + expect(comp.getColor(0).idx).toBe(1); + expect(comp.getColor(0).col).toBe(comp.colors[0]); + }); + + it('should increase strength upon password value change', () => { + expect(comp.measureStrength('')).toBe(0); + expect(comp.measureStrength('aa')).toBeGreaterThanOrEqual(comp.measureStrength('')); + expect(comp.measureStrength('aa^6')).toBeGreaterThanOrEqual(comp.measureStrength('aa')); + expect(comp.measureStrength('Aa090(**)')).toBeGreaterThanOrEqual(comp.measureStrength('aa^6')); + expect(comp.measureStrength('Aa090(**)+-07365')).toBeGreaterThanOrEqual(comp.measureStrength('Aa090(**)')); + }); + + it('should change the color based on strength', () => { + expect(comp.getColor(0).col).toBe(comp.colors[0]); + expect(comp.getColor(11).col).toBe(comp.colors[1]); + expect(comp.getColor(22).col).toBe(comp.colors[2]); + expect(comp.getColor(33).col).toBe(comp.colors[3]); + expect(comp.getColor(44).col).toBe(comp.colors[4]); + }); + }); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/account/password/password.component.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/account/password/password.component.spec.ts new file mode 100644 index 0000000000..86edf940bd --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/account/password/password.component.spec.ts @@ -0,0 +1,89 @@ +import { ComponentFixture, TestBed, async } from '@angular/core/testing'; +import { HttpResponse } from '@angular/common/http'; +import { Observable, of, throwError } from 'rxjs'; + +import { BookstoreTestModule } from '../../../test.module'; +import { PasswordComponent } from 'app/account/password/password.component'; +import { PasswordService } from 'app/account/password/password.service'; + +describe('Component Tests', () => { + describe('PasswordComponent', () => { + let comp: PasswordComponent; + let fixture: ComponentFixture; + let service: PasswordService; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [BookstoreTestModule], + declarations: [PasswordComponent], + providers: [] + }) + .overrideTemplate(PasswordComponent, '') + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(PasswordComponent); + comp = fixture.componentInstance; + service = fixture.debugElement.injector.get(PasswordService); + }); + + it('should show error if passwords do not match', () => { + // GIVEN + comp.newPassword = 'password1'; + comp.confirmPassword = 'password2'; + // WHEN + comp.changePassword(); + // THEN + expect(comp.doNotMatch).toBe('ERROR'); + expect(comp.error).toBeNull(); + expect(comp.success).toBeNull(); + }); + + it('should call Auth.changePassword when passwords match', () => { + // GIVEN + const passwordValues = { + currentPassword: 'oldPassword', + newPassword: 'myPassword' + }; + + spyOn(service, 'save').and.returnValue(of(new HttpResponse({ body: true }))); + comp.currentPassword = passwordValues.currentPassword; + comp.newPassword = comp.confirmPassword = passwordValues.newPassword; + + // WHEN + comp.changePassword(); + + // THEN + expect(service.save).toHaveBeenCalledWith(passwordValues.newPassword, passwordValues.currentPassword); + }); + + it('should set success to OK upon success', function() { + // GIVEN + spyOn(service, 'save').and.returnValue(of(new HttpResponse({ body: true }))); + comp.newPassword = comp.confirmPassword = 'myPassword'; + + // WHEN + comp.changePassword(); + + // THEN + expect(comp.doNotMatch).toBeNull(); + expect(comp.error).toBeNull(); + expect(comp.success).toBe('OK'); + }); + + it('should notify of error if change password fails', function() { + // GIVEN + spyOn(service, 'save').and.returnValue(throwError('ERROR')); + comp.newPassword = comp.confirmPassword = 'myPassword'; + + // WHEN + comp.changePassword(); + + // THEN + expect(comp.doNotMatch).toBeNull(); + expect(comp.success).toBeNull(); + expect(comp.error).toBe('ERROR'); + }); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/account/register/register.component.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/account/register/register.component.spec.ts new file mode 100644 index 0000000000..ae02abbb91 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/account/register/register.component.spec.ts @@ -0,0 +1,118 @@ +import { ComponentFixture, TestBed, async, inject, tick, fakeAsync } from '@angular/core/testing'; +import { Observable, of, throwError } from 'rxjs'; + +import { BookstoreTestModule } from '../../../test.module'; +import { EMAIL_ALREADY_USED_TYPE, LOGIN_ALREADY_USED_TYPE } from 'app/shared'; +import { Register } from 'app/account/register/register.service'; +import { RegisterComponent } from 'app/account/register/register.component'; + +describe('Component Tests', () => { + describe('RegisterComponent', () => { + let fixture: ComponentFixture; + let comp: RegisterComponent; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [BookstoreTestModule], + declarations: [RegisterComponent] + }) + .overrideTemplate(RegisterComponent, '') + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(RegisterComponent); + comp = fixture.componentInstance; + comp.ngOnInit(); + }); + + it('should ensure the two passwords entered match', () => { + comp.registerAccount.password = 'password'; + comp.confirmPassword = 'non-matching'; + + comp.register(); + + expect(comp.doNotMatch).toEqual('ERROR'); + }); + + it('should update success to OK after creating an account', inject( + [Register], + fakeAsync((service: Register) => { + spyOn(service, 'save').and.returnValue(of({})); + comp.registerAccount.password = comp.confirmPassword = 'password'; + + comp.register(); + tick(); + + expect(service.save).toHaveBeenCalledWith({ + password: 'password', + langKey: 'en' + }); + expect(comp.success).toEqual(true); + expect(comp.registerAccount.langKey).toEqual('en'); + expect(comp.errorUserExists).toBeNull(); + expect(comp.errorEmailExists).toBeNull(); + expect(comp.error).toBeNull(); + }) + )); + + it('should notify of user existence upon 400/login already in use', inject( + [Register], + fakeAsync((service: Register) => { + spyOn(service, 'save').and.returnValue( + throwError({ + status: 400, + error: { type: LOGIN_ALREADY_USED_TYPE } + }) + ); + comp.registerAccount.password = comp.confirmPassword = 'password'; + + comp.register(); + tick(); + + expect(comp.errorUserExists).toEqual('ERROR'); + expect(comp.errorEmailExists).toBeNull(); + expect(comp.error).toBeNull(); + }) + )); + + it('should notify of email existence upon 400/email address already in use', inject( + [Register], + fakeAsync((service: Register) => { + spyOn(service, 'save').and.returnValue( + throwError({ + status: 400, + error: { type: EMAIL_ALREADY_USED_TYPE } + }) + ); + comp.registerAccount.password = comp.confirmPassword = 'password'; + + comp.register(); + tick(); + + expect(comp.errorEmailExists).toEqual('ERROR'); + expect(comp.errorUserExists).toBeNull(); + expect(comp.error).toBeNull(); + }) + )); + + it('should notify of generic error', inject( + [Register], + fakeAsync((service: Register) => { + spyOn(service, 'save').and.returnValue( + throwError({ + status: 503 + }) + ); + comp.registerAccount.password = comp.confirmPassword = 'password'; + + comp.register(); + tick(); + + expect(comp.errorUserExists).toBeNull(); + expect(comp.errorEmailExists).toBeNull(); + expect(comp.error).toEqual('ERROR'); + }) + )); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/account/settings/settings.component.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/account/settings/settings.component.spec.ts new file mode 100644 index 0000000000..b6a6d34c19 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/account/settings/settings.component.spec.ts @@ -0,0 +1,81 @@ +import { ComponentFixture, TestBed, async } from '@angular/core/testing'; +import { Observable, throwError } from 'rxjs'; + +import { BookstoreTestModule } from '../../../test.module'; +import { AccountService } from 'app/core'; +import { SettingsComponent } from 'app/account/settings/settings.component'; + +describe('Component Tests', () => { + describe('SettingsComponent', () => { + let comp: SettingsComponent; + let fixture: ComponentFixture; + let mockAuth: any; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [BookstoreTestModule], + declarations: [SettingsComponent], + providers: [] + }) + .overrideTemplate(SettingsComponent, '') + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(SettingsComponent); + comp = fixture.componentInstance; + mockAuth = fixture.debugElement.injector.get(AccountService); + }); + + it('should send the current identity upon save', () => { + // GIVEN + const accountValues = { + firstName: 'John', + lastName: 'Doe', + + activated: true, + email: 'john.doe@mail.com', + langKey: 'en', + login: 'john' + }; + mockAuth.setIdentityResponse(accountValues); + + // WHEN + comp.settingsAccount = accountValues; + comp.save(); + + // THEN + expect(mockAuth.identitySpy).toHaveBeenCalled(); + expect(mockAuth.saveSpy).toHaveBeenCalledWith(accountValues); + expect(comp.settingsAccount).toEqual(accountValues); + }); + + it('should notify of success upon successful save', () => { + // GIVEN + const accountValues = { + firstName: 'John', + lastName: 'Doe' + }; + mockAuth.setIdentityResponse(accountValues); + + // WHEN + comp.save(); + + // THEN + expect(comp.error).toBeNull(); + expect(comp.success).toBe('OK'); + }); + + it('should notify of error upon failed save', () => { + // GIVEN + mockAuth.saveSpy.and.returnValue(throwError('ERROR')); + + // WHEN + comp.save(); + + // THEN + expect(comp.error).toEqual('ERROR'); + expect(comp.success).toBeNull(); + }); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/audits/audits.component.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/audits/audits.component.spec.ts new file mode 100644 index 0000000000..254791f51a --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/audits/audits.component.spec.ts @@ -0,0 +1,133 @@ +import { ComponentFixture, TestBed, async } from '@angular/core/testing'; +import { Observable, of } from 'rxjs'; +import { HttpHeaders, HttpResponse } from '@angular/common/http'; + +import { BookstoreTestModule } from '../../../test.module'; +import { AuditsComponent } from 'app/admin/audits/audits.component'; +import { AuditsService } from 'app/admin/audits/audits.service'; +import { Audit } from 'app/admin/audits/audit.model'; +import { ITEMS_PER_PAGE } from 'app/shared'; + +function build2DigitsDatePart(datePart: number) { + return `0${datePart}`.slice(-2); +} + +function getDate(isToday = true) { + let date: Date = new Date(); + if (isToday) { + // Today + 1 day - needed if the current day must be included + date.setDate(date.getDate() + 1); + } else { + // get last month + if (date.getMonth() === 0) { + date = new Date(date.getFullYear() - 1, 11, date.getDate()); + } else { + date = new Date(date.getFullYear(), date.getMonth() - 1, date.getDate()); + } + } + const monthString = build2DigitsDatePart(date.getMonth() + 1); + const dateString = build2DigitsDatePart(date.getDate()); + return `${date.getFullYear()}-${monthString}-${dateString}`; +} + +describe('Component Tests', () => { + describe('AuditsComponent', () => { + let comp: AuditsComponent; + let fixture: ComponentFixture; + let service: AuditsService; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [BookstoreTestModule], + declarations: [AuditsComponent], + providers: [AuditsService] + }) + .overrideTemplate(AuditsComponent, '') + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(AuditsComponent); + comp = fixture.componentInstance; + service = fixture.debugElement.injector.get(AuditsService); + }); + + describe('today function ', () => { + it('should set toDate to current date', () => { + comp.today(); + expect(comp.toDate).toBe(getDate()); + }); + }); + + describe('previousMonth function ', () => { + it('should set fromDate to current date', () => { + comp.previousMonth(); + expect(comp.fromDate).toBe(getDate(false)); + }); + }); + + describe('By default, on init', () => { + it('should set all default values correctly', () => { + fixture.detectChanges(); + expect(comp.toDate).toBe(getDate()); + expect(comp.fromDate).toBe(getDate(false)); + expect(comp.itemsPerPage).toBe(ITEMS_PER_PAGE); + expect(comp.page).toBe(10); + expect(comp.reverse).toBeFalsy(); + expect(comp.predicate).toBe('id'); + }); + }); + + describe('OnInit', () => { + it('Should call load all on init', () => { + // GIVEN + const headers = new HttpHeaders().append('link', 'link;link'); + const audit = new Audit({ remoteAddress: '127.0.0.1', sessionId: '123' }, 'user', '20140101', 'AUTHENTICATION_SUCCESS'); + spyOn(service, 'query').and.returnValue( + of( + new HttpResponse({ + body: [audit], + headers + }) + ) + ); + + // WHEN + comp.ngOnInit(); + + // THEN + expect(service.query).toHaveBeenCalled(); + expect(comp.audits[0]).toEqual(jasmine.objectContaining(audit)); + }); + }); + + describe('Create sort object', () => { + it('Should sort only by id asc', () => { + // GIVEN + comp.predicate = 'id'; + comp.reverse = false; + + // WHEN + const sort = comp.sort(); + + // THEN + expect(sort.length).toEqual(1); + expect(sort[0]).toEqual('id,desc'); + }); + + it('Should sort by timestamp asc then by id', () => { + // GIVEN + comp.predicate = 'timestamp'; + comp.reverse = true; + + // WHEN + const sort = comp.sort(); + + // THEN + expect(sort.length).toEqual(2); + expect(sort[0]).toEqual('timestamp,asc'); + expect(sort[1]).toEqual('id'); + }); + }); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/audits/audits.service.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/audits/audits.service.spec.ts new file mode 100644 index 0000000000..84ff79f633 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/audits/audits.service.spec.ts @@ -0,0 +1,59 @@ +import { TestBed } from '@angular/core/testing'; + +import { AuditsService } from 'app/admin/audits/audits.service'; +import { Audit } from 'app/admin/audits/audit.model'; +import { SERVER_API_URL } from 'app/app.constants'; +import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; + +describe('Service Tests', () => { + describe('Audits Service', () => { + let service: AuditsService; + let httpMock; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule] + }); + + service = TestBed.get(AuditsService); + httpMock = TestBed.get(HttpTestingController); + }); + + afterEach(() => { + httpMock.verify(); + }); + + describe('Service methods', () => { + it('should call correct URL', () => { + service.query({}).subscribe(() => {}); + + const req = httpMock.expectOne({ method: 'GET' }); + const resourceUrl = SERVER_API_URL + 'management/audits'; + expect(req.request.url).toEqual(resourceUrl); + }); + + it('should return Audits', () => { + const audit = new Audit({ remoteAddress: '127.0.0.1', sessionId: '123' }, 'user', '20140101', 'AUTHENTICATION_SUCCESS'); + + service.query({}).subscribe(received => { + expect(received.body[0]).toEqual(audit); + }); + + const req = httpMock.expectOne({ method: 'GET' }); + req.flush([audit]); + }); + + it('should propagate not found response', () => { + service.query({}).subscribe(null, (_error: any) => { + expect(_error.status).toEqual(404); + }); + + const req = httpMock.expectOne({ method: 'GET' }); + req.flush('Invalid request parameters', { + status: 404, + statusText: 'Bad Request' + }); + }); + }); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/configuration/configuration.component.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/configuration/configuration.component.spec.ts new file mode 100644 index 0000000000..d21f87b57b --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/configuration/configuration.component.spec.ts @@ -0,0 +1,71 @@ +import { ComponentFixture, TestBed, async } from '@angular/core/testing'; +import { of } from 'rxjs'; +import { HttpHeaders, HttpResponse } from '@angular/common/http'; + +import { BookstoreTestModule } from '../../../test.module'; +import { JhiConfigurationComponent } from 'app/admin/configuration/configuration.component'; +import { JhiConfigurationService } from 'app/admin/configuration/configuration.service'; +import { ITEMS_PER_PAGE } from 'app/shared'; +import { Log } from 'app/admin'; + +describe('Component Tests', () => { + describe('JhiConfigurationComponent', () => { + let comp: JhiConfigurationComponent; + let fixture: ComponentFixture; + let service: JhiConfigurationService; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [BookstoreTestModule], + declarations: [JhiConfigurationComponent], + providers: [JhiConfigurationService] + }) + .overrideTemplate(JhiConfigurationComponent, '') + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(JhiConfigurationComponent); + comp = fixture.componentInstance; + service = fixture.debugElement.injector.get(JhiConfigurationService); + }); + + describe('OnInit', () => { + it('should set all default values correctly', () => { + expect(comp.configKeys).toEqual([]); + expect(comp.filter).toBe(''); + expect(comp.orderProp).toBe('prefix'); + expect(comp.reverse).toBe(false); + }); + it('Should call load all on init', () => { + // GIVEN + const body = [{ config: 'test', properties: 'test' }, { config: 'test2' }]; + const envConfig = { envConfig: 'test' }; + spyOn(service, 'get').and.returnValue(of(body)); + spyOn(service, 'getEnv').and.returnValue(of(envConfig)); + + // WHEN + comp.ngOnInit(); + + // THEN + expect(service.get).toHaveBeenCalled(); + expect(service.getEnv).toHaveBeenCalled(); + expect(comp.configKeys).toEqual([['0', '1', '2', '3']]); + expect(comp.allConfiguration).toEqual(envConfig); + }); + }); + describe('keys method', () => { + it('should return the keys of an Object', () => { + // GIVEN + const data = { + key1: 'test', + key2: 'test2' + }; + + // THEN + expect(comp.keys(data)).toEqual(['key1', 'key2']); + expect(comp.keys(undefined)).toEqual([]); + }); + }); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/configuration/configuration.service.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/configuration/configuration.service.spec.ts new file mode 100644 index 0000000000..6039044b7f --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/configuration/configuration.service.spec.ts @@ -0,0 +1,64 @@ +import { TestBed } from '@angular/core/testing'; + +import { JhiConfigurationService } from 'app/admin/configuration/configuration.service'; +import { SERVER_API_URL } from 'app/app.constants'; +import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; +import { HttpResponse } from '@angular/common/http'; + +describe('Service Tests', () => { + describe('Logs Service', () => { + let service: JhiConfigurationService; + let httpMock; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule] + }); + + service = TestBed.get(JhiConfigurationService); + httpMock = TestBed.get(HttpTestingController); + }); + + afterEach(() => { + httpMock.verify(); + }); + + describe('Service methods', () => { + it('should call correct URL', () => { + service.get().subscribe(() => {}); + + const req = httpMock.expectOne({ method: 'GET' }); + const resourceUrl = SERVER_API_URL + 'management/configprops'; + expect(req.request.url).toEqual(resourceUrl); + }); + + it('should get the config', () => { + const angularConfig = { + contexts: { + angular: { + beans: ['test2'] + } + } + }; + service.get().subscribe(received => { + expect(received.body[0]).toEqual(angularConfig); + }); + + const req = httpMock.expectOne({ method: 'GET' }); + req.flush(angularConfig); + }); + + it('should get the env', () => { + const propertySources = new HttpResponse({ + body: [{ name: 'test1', properties: 'test1' }, { name: 'test2', properties: 'test2' }] + }); + service.get().subscribe(received => { + expect(received.body[0]).toEqual(propertySources); + }); + + const req = httpMock.expectOne({ method: 'GET' }); + req.flush(propertySources); + }); + }); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/health/health.component.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/health/health.component.spec.ts new file mode 100644 index 0000000000..549b430f67 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/health/health.component.spec.ts @@ -0,0 +1,321 @@ +import { ComponentFixture, TestBed, async } from '@angular/core/testing'; +import { HttpResponse, HttpErrorResponse } from '@angular/common/http'; +import { of, throwError } from 'rxjs'; + +import { BookstoreTestModule } from '../../../test.module'; +import { JhiHealthCheckComponent } from 'app/admin/health/health.component'; +import { JhiHealthService } from 'app/admin/health/health.service'; + +describe('Component Tests', () => { + describe('JhiHealthCheckComponent', () => { + let comp: JhiHealthCheckComponent; + let fixture: ComponentFixture; + let service: JhiHealthService; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [BookstoreTestModule], + declarations: [JhiHealthCheckComponent] + }) + .overrideTemplate(JhiHealthCheckComponent, '') + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(JhiHealthCheckComponent); + comp = fixture.componentInstance; + service = fixture.debugElement.injector.get(JhiHealthService); + }); + + describe('baseName and subSystemName', () => { + it('should return the basename when it has no sub system', () => { + expect(comp.baseName('base')).toBe('base'); + }); + + it('should return the basename when it has sub systems', () => { + expect(comp.baseName('base.subsystem.system')).toBe('base'); + }); + + it('should return the sub system name', () => { + expect(comp.subSystemName('subsystem')).toBe(''); + }); + + it('should return the subsystem when it has multiple keys', () => { + expect(comp.subSystemName('subsystem.subsystem.system')).toBe(' - subsystem.system'); + }); + }); + + describe('transformHealthData', () => { + it('should flatten empty health data', () => { + const data = {}; + const expected = []; + expect(service.transformHealthData(data)).toEqual(expected); + }); + + it('should flatten health data with no subsystems', () => { + const data = { + details: { + status: 'UP', + db: { + status: 'UP', + database: 'H2', + hello: '1' + }, + mail: { + status: 'UP', + error: 'mail.a.b.c' + } + } + }; + const expected = [ + { + name: 'db', + status: 'UP', + details: { + database: 'H2', + hello: '1' + } + }, + { + name: 'mail', + error: 'mail.a.b.c', + status: 'UP' + } + ]; + expect(service.transformHealthData(data)).toEqual(expected); + }); + + it('should flatten health data with subsystems at level 1, main system has no additional information', () => { + const data = { + details: { + status: 'UP', + db: { + status: 'UP', + database: 'H2', + hello: '1' + }, + mail: { + status: 'UP', + error: 'mail.a.b.c' + }, + system: { + status: 'DOWN', + subsystem1: { + status: 'UP', + property1: 'system.subsystem1.property1' + }, + subsystem2: { + status: 'DOWN', + error: 'system.subsystem1.error', + property2: 'system.subsystem2.property2' + } + } + } + }; + const expected = [ + { + name: 'db', + status: 'UP', + details: { + database: 'H2', + hello: '1' + } + }, + { + name: 'mail', + error: 'mail.a.b.c', + status: 'UP' + }, + { + name: 'system.subsystem1', + status: 'UP', + details: { + property1: 'system.subsystem1.property1' + } + }, + { + name: 'system.subsystem2', + error: 'system.subsystem1.error', + status: 'DOWN', + details: { + property2: 'system.subsystem2.property2' + } + } + ]; + expect(service.transformHealthData(data)).toEqual(expected); + }); + + it('should flatten health data with subsystems at level 1, main system has additional information', () => { + const data = { + details: { + status: 'UP', + db: { + status: 'UP', + database: 'H2', + hello: '1' + }, + mail: { + status: 'UP', + error: 'mail.a.b.c' + }, + system: { + status: 'DOWN', + property1: 'system.property1', + subsystem1: { + status: 'UP', + property1: 'system.subsystem1.property1' + }, + subsystem2: { + status: 'DOWN', + error: 'system.subsystem1.error', + property2: 'system.subsystem2.property2' + } + } + } + }; + const expected = [ + { + name: 'db', + status: 'UP', + details: { + database: 'H2', + hello: '1' + } + }, + { + name: 'mail', + error: 'mail.a.b.c', + status: 'UP' + }, + { + name: 'system', + status: 'DOWN', + details: { + property1: 'system.property1' + } + }, + { + name: 'system.subsystem1', + status: 'UP', + details: { + property1: 'system.subsystem1.property1' + } + }, + { + name: 'system.subsystem2', + error: 'system.subsystem1.error', + status: 'DOWN', + details: { + property2: 'system.subsystem2.property2' + } + } + ]; + expect(service.transformHealthData(data)).toEqual(expected); + }); + + it('should flatten health data with subsystems at level 1, main system has additional error', () => { + const data = { + details: { + status: 'UP', + db: { + status: 'UP', + database: 'H2', + hello: '1' + }, + mail: { + status: 'UP', + error: 'mail.a.b.c' + }, + system: { + status: 'DOWN', + error: 'show me', + subsystem1: { + status: 'UP', + property1: 'system.subsystem1.property1' + }, + subsystem2: { + status: 'DOWN', + error: 'system.subsystem1.error', + property2: 'system.subsystem2.property2' + } + } + } + }; + const expected = [ + { + name: 'db', + status: 'UP', + details: { + database: 'H2', + hello: '1' + } + }, + { + name: 'mail', + error: 'mail.a.b.c', + status: 'UP' + }, + { + name: 'system', + error: 'show me', + status: 'DOWN' + }, + { + name: 'system.subsystem1', + status: 'UP', + details: { + property1: 'system.subsystem1.property1' + } + }, + { + name: 'system.subsystem2', + error: 'system.subsystem1.error', + status: 'DOWN', + details: { + property2: 'system.subsystem2.property2' + } + } + ]; + expect(service.transformHealthData(data)).toEqual(expected); + }); + }); + + describe('getBadgeClass', () => { + it('should get badge class', () => { + const upBadgeClass = comp.getBadgeClass('UP'); + const downBadgeClass = comp.getBadgeClass('DOWN'); + expect(upBadgeClass).toEqual('badge-success'); + expect(downBadgeClass).toEqual('badge-danger'); + }); + }); + + describe('refresh', () => { + it('should call refresh on init', () => { + // GIVEN + spyOn(service, 'checkHealth').and.returnValue(of(new HttpResponse())); + spyOn(service, 'transformHealthData').and.returnValue(of({ data: 'test' })); + + // WHEN + comp.ngOnInit(); + + // THEN + expect(service.checkHealth).toHaveBeenCalled(); + expect(service.transformHealthData).toHaveBeenCalled(); + expect(comp.healthData.value).toEqual({ data: 'test' }); + }); + it('should handle a 503 on refreshing health data', () => { + // GIVEN + spyOn(service, 'checkHealth').and.returnValue(throwError(new HttpErrorResponse({ status: 503, error: 'Mail down' }))); + spyOn(service, 'transformHealthData').and.returnValue(of({ health: 'down' })); + + // WHEN + comp.refresh(); + + // THEN + expect(service.checkHealth).toHaveBeenCalled(); + expect(service.transformHealthData).toHaveBeenCalled(); + expect(comp.healthData.value).toEqual({ health: 'down' }); + }); + }); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/logs/logs.component.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/logs/logs.component.spec.ts new file mode 100644 index 0000000000..def356c0f2 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/logs/logs.component.spec.ts @@ -0,0 +1,77 @@ +import { ComponentFixture, TestBed, async } from '@angular/core/testing'; +import { of } from 'rxjs'; +import { HttpHeaders, HttpResponse } from '@angular/common/http'; + +import { BookstoreTestModule } from '../../../test.module'; +import { LogsComponent } from 'app/admin/logs/logs.component'; +import { LogsService } from 'app/admin/logs/logs.service'; +import { ITEMS_PER_PAGE } from 'app/shared'; +import { Log } from 'app/admin'; + +describe('Component Tests', () => { + describe('LogsComponent', () => { + let comp: LogsComponent; + let fixture: ComponentFixture; + let service: LogsService; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [BookstoreTestModule], + declarations: [LogsComponent], + providers: [LogsService] + }) + .overrideTemplate(LogsComponent, '') + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(LogsComponent); + comp = fixture.componentInstance; + service = fixture.debugElement.injector.get(LogsService); + }); + + describe('OnInit', () => { + it('should set all default values correctly', () => { + expect(comp.filter).toBe(''); + expect(comp.orderProp).toBe('name'); + expect(comp.reverse).toBe(false); + }); + it('Should call load all on init', () => { + // GIVEN + const headers = new HttpHeaders().append('link', 'link;link'); + const log = new Log('main', 'WARN'); + spyOn(service, 'findAll').and.returnValue( + of( + new HttpResponse({ + body: [log], + headers + }) + ) + ); + + // WHEN + comp.ngOnInit(); + + // THEN + expect(service.findAll).toHaveBeenCalled(); + expect(comp.loggers[0]).toEqual(jasmine.objectContaining(log)); + }); + }); + describe('change log level', () => { + it('should change log level correctly', () => { + // GIVEN + const log = new Log('main', 'ERROR'); + spyOn(service, 'changeLevel').and.returnValue(of(new HttpResponse())); + spyOn(service, 'findAll').and.returnValue(of(new HttpResponse({ body: [log] }))); + + // WHEN + comp.changeLevel('main', 'ERROR'); + + // THEN + expect(service.changeLevel).toHaveBeenCalled(); + expect(service.findAll).toHaveBeenCalled(); + expect(comp.loggers[0]).toEqual(jasmine.objectContaining(log)); + }); + }); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/logs/logs.service.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/logs/logs.service.spec.ts new file mode 100644 index 0000000000..c34833922e --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/logs/logs.service.spec.ts @@ -0,0 +1,58 @@ +import { TestBed } from '@angular/core/testing'; + +import { LogsService } from 'app/admin/logs/logs.service'; +import { Log } from 'app/admin/logs/log.model'; +import { SERVER_API_URL } from 'app/app.constants'; +import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; + +describe('Service Tests', () => { + describe('Logs Service', () => { + let service: LogsService; + let httpMock; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule] + }); + + service = TestBed.get(LogsService); + httpMock = TestBed.get(HttpTestingController); + }); + + afterEach(() => { + httpMock.verify(); + }); + + describe('Service methods', () => { + it('should call correct URL', () => { + service.findAll().subscribe(() => {}); + + const req = httpMock.expectOne({ method: 'GET' }); + const resourceUrl = SERVER_API_URL + 'management/logs'; + expect(req.request.url).toEqual(resourceUrl); + }); + + it('should return Logs', () => { + const log = new Log('main', 'ERROR'); + + service.findAll().subscribe(received => { + expect(received.body[0]).toEqual(log); + }); + + const req = httpMock.expectOne({ method: 'GET' }); + req.flush([log]); + }); + + it('should change log level', () => { + const log = new Log('main', 'ERROR'); + + service.changeLevel(log).subscribe(received => { + expect(received.body[0]).toEqual(log); + }); + + const req = httpMock.expectOne({ method: 'PUT' }); + req.flush([log]); + }); + }); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/metrics/metrics.component.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/metrics/metrics.component.spec.ts new file mode 100644 index 0000000000..d4a992b963 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/metrics/metrics.component.spec.ts @@ -0,0 +1,55 @@ +import { ComponentFixture, TestBed, async } from '@angular/core/testing'; +import { HttpResponse, HttpErrorResponse } from '@angular/common/http'; +import { of, throwError } from 'rxjs'; + +import { BookstoreTestModule } from '../../../test.module'; +import { JhiMetricsMonitoringComponent } from 'app/admin/metrics/metrics.component'; +import { JhiMetricsService } from 'app/admin/metrics/metrics.service'; + +describe('Component Tests', () => { + describe('JhiMetricsMonitoringComponent', () => { + let comp: JhiMetricsMonitoringComponent; + let fixture: ComponentFixture; + let service: JhiMetricsService; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [BookstoreTestModule], + declarations: [JhiMetricsMonitoringComponent] + }) + .overrideTemplate(JhiMetricsMonitoringComponent, '') + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(JhiMetricsMonitoringComponent); + comp = fixture.componentInstance; + service = fixture.debugElement.injector.get(JhiMetricsService); + }); + + describe('refresh', () => { + it('should call refresh on init', () => { + // GIVEN + const response = { + timers: { + service: 'test', + unrelatedKey: 'test' + }, + gauges: { + 'jcache.statistics': { + value: 2 + }, + unrelatedKey: 'test' + } + }; + spyOn(service, 'getMetrics').and.returnValue(of(response)); + + // WHEN + comp.ngOnInit(); + + // THEN + expect(service.getMetrics).toHaveBeenCalled(); + }); + }); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/metrics/metrics.service.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/metrics/metrics.service.spec.ts new file mode 100644 index 0000000000..2c3665b062 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/metrics/metrics.service.spec.ts @@ -0,0 +1,57 @@ +import { TestBed } from '@angular/core/testing'; + +import { JhiMetricsService } from 'app/admin/metrics/metrics.service'; +import { SERVER_API_URL } from 'app/app.constants'; +import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; + +describe('Service Tests', () => { + describe('Logs Service', () => { + let service: JhiMetricsService; + let httpMock; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule] + }); + + service = TestBed.get(JhiMetricsService); + httpMock = TestBed.get(HttpTestingController); + }); + + afterEach(() => { + httpMock.verify(); + }); + + describe('Service methods', () => { + it('should call correct URL', () => { + service.getMetrics().subscribe(() => {}); + + const req = httpMock.expectOne({ method: 'GET' }); + const resourceUrl = SERVER_API_URL + 'management/jhi-metrics'; + expect(req.request.url).toEqual(resourceUrl); + }); + + it('should return Metrics', () => { + const metrics = []; + + service.getMetrics().subscribe(received => { + expect(received.body[0]).toEqual(metrics); + }); + + const req = httpMock.expectOne({ method: 'GET' }); + req.flush([metrics]); + }); + + it('should return Thread Dump', () => { + const dump = [{ name: 'test1', threadState: 'RUNNABLE' }]; + + service.threadDump().subscribe(received => { + expect(received.body[0]).toEqual(dump); + }); + + const req = httpMock.expectOne({ method: 'GET' }); + req.flush([dump]); + }); + }); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/user-management/user-management-delete-dialog.component.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/user-management/user-management-delete-dialog.component.spec.ts new file mode 100644 index 0000000000..596e1b5609 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/user-management/user-management-delete-dialog.component.spec.ts @@ -0,0 +1,54 @@ +import { ComponentFixture, TestBed, async, inject, fakeAsync, tick } from '@angular/core/testing'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { Observable, of } from 'rxjs'; +import { JhiEventManager } from 'ng-jhipster'; + +import { BookstoreTestModule } from '../../../test.module'; +import { UserMgmtDeleteDialogComponent } from 'app/admin/user-management/user-management-delete-dialog.component'; +import { UserService } from 'app/core'; + +describe('Component Tests', () => { + describe('User Management Delete Component', () => { + let comp: UserMgmtDeleteDialogComponent; + let fixture: ComponentFixture; + let service: UserService; + let mockEventManager: any; + let mockActiveModal: any; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [BookstoreTestModule], + declarations: [UserMgmtDeleteDialogComponent] + }) + .overrideTemplate(UserMgmtDeleteDialogComponent, '') + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(UserMgmtDeleteDialogComponent); + comp = fixture.componentInstance; + service = fixture.debugElement.injector.get(UserService); + mockEventManager = fixture.debugElement.injector.get(JhiEventManager); + mockActiveModal = fixture.debugElement.injector.get(NgbActiveModal); + }); + + describe('confirmDelete', () => { + it('Should call delete service on confirmDelete', inject( + [], + fakeAsync(() => { + // GIVEN + spyOn(service, 'delete').and.returnValue(of({})); + + // WHEN + comp.confirmDelete('user'); + tick(); + + // THEN + expect(service.delete).toHaveBeenCalledWith('user'); + expect(mockActiveModal.dismissSpy).toHaveBeenCalled(); + expect(mockEventManager.broadcastSpy).toHaveBeenCalled(); + }) + )); + }); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/user-management/user-management-detail.component.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/user-management/user-management-detail.component.spec.ts new file mode 100644 index 0000000000..f64b8bb88b --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/user-management/user-management-detail.component.spec.ts @@ -0,0 +1,65 @@ +import { ComponentFixture, TestBed, async } from '@angular/core/testing'; +import { ActivatedRoute } from '@angular/router'; +import { of } from 'rxjs'; + +import { BookstoreTestModule } from '../../../test.module'; +import { UserMgmtDetailComponent } from 'app/admin/user-management/user-management-detail.component'; +import { User } from 'app/core'; + +describe('Component Tests', () => { + describe('User Management Detail Component', () => { + let comp: UserMgmtDetailComponent; + let fixture: ComponentFixture; + const route = ({ + data: of({ user: new User(1, 'user', 'first', 'last', 'first@last.com', true, 'en', ['ROLE_USER'], 'admin', null, null, null) }) + } as any) as ActivatedRoute; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [BookstoreTestModule], + declarations: [UserMgmtDetailComponent], + providers: [ + { + provide: ActivatedRoute, + useValue: route + } + ] + }) + .overrideTemplate(UserMgmtDetailComponent, '') + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(UserMgmtDetailComponent); + comp = fixture.componentInstance; + }); + + describe('OnInit', () => { + it('Should call load all on init', () => { + // GIVEN + + // WHEN + comp.ngOnInit(); + + // THEN + expect(comp.user).toEqual( + jasmine.objectContaining({ + id: 1, + login: 'user', + firstName: 'first', + lastName: 'last', + email: 'first@last.com', + activated: true, + langKey: 'en', + authorities: ['ROLE_USER'], + createdBy: 'admin', + createdDate: null, + lastModifiedBy: null, + lastModifiedDate: null, + password: null + }) + ); + }); + }); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/user-management/user-management-update.component.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/user-management/user-management-update.component.spec.ts new file mode 100644 index 0000000000..c98694ba82 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/user-management/user-management-update.component.spec.ts @@ -0,0 +1,99 @@ +import { ComponentFixture, TestBed, async, inject, fakeAsync, tick } from '@angular/core/testing'; +import { HttpResponse } from '@angular/common/http'; +import { ActivatedRoute } from '@angular/router'; +import { Observable, of } from 'rxjs'; + +import { BookstoreTestModule } from '../../../test.module'; +import { UserMgmtUpdateComponent } from 'app/admin/user-management/user-management-update.component'; +import { UserService, User } from 'app/core'; + +describe('Component Tests', () => { + describe('User Management Update Component', () => { + let comp: UserMgmtUpdateComponent; + let fixture: ComponentFixture; + let service: UserService; + const route = ({ + data: of({ user: new User(1, 'user', 'first', 'last', 'first@last.com', true, 'en', ['ROLE_USER'], 'admin', null, null, null) }) + } as any) as ActivatedRoute; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [BookstoreTestModule], + declarations: [UserMgmtUpdateComponent], + providers: [ + { + provide: ActivatedRoute, + useValue: route + } + ] + }) + .overrideTemplate(UserMgmtUpdateComponent, '') + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(UserMgmtUpdateComponent); + comp = fixture.componentInstance; + service = fixture.debugElement.injector.get(UserService); + }); + + describe('OnInit', () => { + it('Should load authorities and language on init', inject( + [], + fakeAsync(() => { + // GIVEN + spyOn(service, 'authorities').and.returnValue(of(['USER'])); + + // WHEN + comp.ngOnInit(); + + // THEN + expect(service.authorities).toHaveBeenCalled(); + expect(comp.authorities).toEqual(['USER']); + }) + )); + }); + + describe('save', () => { + it('Should call update service on save for existing user', inject( + [], + fakeAsync(() => { + // GIVEN + const entity = new User(123); + spyOn(service, 'update').and.returnValue( + of( + new HttpResponse({ + body: entity + }) + ) + ); + comp.user = entity; + // WHEN + comp.save(); + tick(); // simulate async + + // THEN + expect(service.update).toHaveBeenCalledWith(entity); + expect(comp.isSaving).toEqual(false); + }) + )); + + it('Should call create service on save for new user', inject( + [], + fakeAsync(() => { + // GIVEN + const entity = new User(); + spyOn(service, 'create').and.returnValue(of(new HttpResponse({ body: entity }))); + comp.user = entity; + // WHEN + comp.save(); + tick(); // simulate async + + // THEN + expect(service.create).toHaveBeenCalledWith(entity); + expect(comp.isSaving).toEqual(false); + }) + )); + }); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/user-management/user-management.component.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/user-management/user-management.component.spec.ts new file mode 100644 index 0000000000..31fea387b8 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/user-management/user-management.component.spec.ts @@ -0,0 +1,85 @@ +import { ComponentFixture, TestBed, async, inject, fakeAsync, tick } from '@angular/core/testing'; +import { Observable, of } from 'rxjs'; +import { HttpHeaders, HttpResponse } from '@angular/common/http'; + +import { BookstoreTestModule } from '../../../test.module'; +import { UserMgmtComponent } from 'app/admin/user-management/user-management.component'; +import { UserService, User } from 'app/core'; + +describe('Component Tests', () => { + describe('User Management Component', () => { + let comp: UserMgmtComponent; + let fixture: ComponentFixture; + let service: UserService; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [BookstoreTestModule], + declarations: [UserMgmtComponent] + }) + .overrideTemplate(UserMgmtComponent, '') + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(UserMgmtComponent); + comp = fixture.componentInstance; + service = fixture.debugElement.injector.get(UserService); + }); + + describe('OnInit', () => { + it('Should call load all on init', inject( + [], + fakeAsync(() => { + // GIVEN + const headers = new HttpHeaders().append('link', 'link;link'); + spyOn(service, 'query').and.returnValue( + of( + new HttpResponse({ + body: [new User(123)], + headers + }) + ) + ); + + // WHEN + comp.ngOnInit(); + tick(); // simulate async + + // THEN + expect(service.query).toHaveBeenCalled(); + expect(comp.users[0]).toEqual(jasmine.objectContaining({ id: 123 })); + }) + )); + }); + + describe('setActive', () => { + it('Should update user and call load all', inject( + [], + fakeAsync(() => { + // GIVEN + const headers = new HttpHeaders().append('link', 'link;link'); + const user = new User(123); + spyOn(service, 'query').and.returnValue( + of( + new HttpResponse({ + body: [user], + headers + }) + ) + ); + spyOn(service, 'update').and.returnValue(of(new HttpResponse({ status: 200 }))); + + // WHEN + comp.setActive(user, true); + tick(); // simulate async + + // THEN + expect(service.update).toHaveBeenCalledWith(user); + expect(service.query).toHaveBeenCalled(); + expect(comp.users[0]).toEqual(jasmine.objectContaining({ id: 123 })); + }) + )); + }); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/core/user/account.service.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/core/user/account.service.spec.ts new file mode 100644 index 0000000000..01ed421f57 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/core/user/account.service.spec.ts @@ -0,0 +1,102 @@ +import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; +import { TestBed } from '@angular/core/testing'; +import { SERVER_API_URL } from 'app/app.constants'; +import { AccountService } from 'app/core'; +import { JhiDateUtils } from 'ng-jhipster'; +import { SessionStorageService } from 'ngx-webstorage'; + +describe('Service Tests', () => { + describe('Account Service', () => { + let service: AccountService; + let httpMock; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule], + providers: [JhiDateUtils, SessionStorageService] + }); + + service = TestBed.get(AccountService); + httpMock = TestBed.get(HttpTestingController); + }); + + afterEach(() => { + httpMock.verify(); + }); + + describe('Service methods', () => { + it('should call /account if user is undefined', () => { + service.identity().then(() => {}); + const req = httpMock.expectOne({ method: 'GET' }); + const resourceUrl = SERVER_API_URL + 'api/account'; + + expect(req.request.url).toEqual(`${resourceUrl}`); + }); + + it('should call /account only once', () => { + service.identity().then(() => service.identity().then(() => {})); + const req = httpMock.expectOne({ method: 'GET' }); + const resourceUrl = SERVER_API_URL + 'api/account'; + + expect(req.request.url).toEqual(`${resourceUrl}`); + req.flush({ + firstName: 'John' + }); + }); + + describe('hasAuthority', () => { + it('should return false if user is not logged', async () => { + const hasAuthority = await service.hasAuthority('ROLE_USER'); + expect(hasAuthority).toBeFalsy(); + }); + + it('should return false if user is logged and has not authority', async () => { + service.authenticate({ + authorities: ['ROLE_USER'] + }); + + const hasAuthority = await service.hasAuthority('ROLE_ADMIN'); + + expect(hasAuthority).toBeFalsy(); + }); + + it('should return true if user is logged and has authority', async () => { + service.authenticate({ + authorities: ['ROLE_USER'] + }); + + const hasAuthority = await service.hasAuthority('ROLE_USER'); + + expect(hasAuthority).toBeTruthy(); + }); + }); + + describe('hasAnyAuthority', () => { + it('should return false if user is not logged', async () => { + const hasAuthority = await service.hasAnyAuthority(['ROLE_USER']); + expect(hasAuthority).toBeFalsy(); + }); + + it('should return false if user is logged and has not authority', async () => { + service.authenticate({ + authorities: ['ROLE_USER'] + }); + + const hasAuthority = await service.hasAnyAuthority(['ROLE_ADMIN']); + + expect(hasAuthority).toBeFalsy(); + }); + + it('should return true if user is logged and has authority', async () => { + service.authenticate({ + authorities: ['ROLE_USER'] + }); + + const hasAuthority = await service.hasAnyAuthority(['ROLE_USER', 'ROLE_ADMIN']); + + expect(hasAuthority).toBeTruthy(); + }); + }); + }); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/core/user/user.service.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/core/user/user.service.spec.ts new file mode 100644 index 0000000000..9c05839a57 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/core/user/user.service.spec.ts @@ -0,0 +1,66 @@ +import { TestBed } from '@angular/core/testing'; +import { JhiDateUtils } from 'ng-jhipster'; + +import { UserService, User } from 'app/core'; +import { SERVER_API_URL } from 'app/app.constants'; +import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; + +describe('Service Tests', () => { + describe('User Service', () => { + let service: UserService; + let httpMock; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule], + providers: [JhiDateUtils] + }); + + service = TestBed.get(UserService); + httpMock = TestBed.get(HttpTestingController); + }); + + afterEach(() => { + httpMock.verify(); + }); + + describe('Service methods', () => { + it('should call correct URL', () => { + service.find('user').subscribe(() => {}); + + const req = httpMock.expectOne({ method: 'GET' }); + const resourceUrl = SERVER_API_URL + 'api/users'; + expect(req.request.url).toEqual(`${resourceUrl}/user`); + }); + it('should return User', () => { + service.find('user').subscribe(received => { + expect(received.body.login).toEqual('user'); + }); + + const req = httpMock.expectOne({ method: 'GET' }); + req.flush(new User(1, 'user')); + }); + + it('should return Authorities', () => { + service.authorities().subscribe(_authorities => { + expect(_authorities).toEqual(['ROLE_USER', 'ROLE_ADMIN']); + }); + const req = httpMock.expectOne({ method: 'GET' }); + + req.flush(['ROLE_USER', 'ROLE_ADMIN']); + }); + + it('should propagate not found response', () => { + service.find('user').subscribe(null, (_error: any) => { + expect(_error.status).toEqual(404); + }); + + const req = httpMock.expectOne({ method: 'GET' }); + req.flush('Invalid request parameters', { + status: 404, + statusText: 'Bad Request' + }); + }); + }); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/entities/book/book-delete-dialog.component.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/entities/book/book-delete-dialog.component.spec.ts new file mode 100644 index 0000000000..6ffba6ee1e --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/entities/book/book-delete-dialog.component.spec.ts @@ -0,0 +1,52 @@ +/* tslint:disable max-line-length */ +import { ComponentFixture, TestBed, inject, fakeAsync, tick } from '@angular/core/testing'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { Observable, of } from 'rxjs'; +import { JhiEventManager } from 'ng-jhipster'; + +import { BookstoreTestModule } from '../../../test.module'; +import { BookDeleteDialogComponent } from 'app/entities/book/book-delete-dialog.component'; +import { BookService } from 'app/entities/book/book.service'; + +describe('Component Tests', () => { + describe('Book Management Delete Component', () => { + let comp: BookDeleteDialogComponent; + let fixture: ComponentFixture; + let service: BookService; + let mockEventManager: any; + let mockActiveModal: any; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [BookstoreTestModule], + declarations: [BookDeleteDialogComponent] + }) + .overrideTemplate(BookDeleteDialogComponent, '') + .compileComponents(); + fixture = TestBed.createComponent(BookDeleteDialogComponent); + comp = fixture.componentInstance; + service = fixture.debugElement.injector.get(BookService); + mockEventManager = fixture.debugElement.injector.get(JhiEventManager); + mockActiveModal = fixture.debugElement.injector.get(NgbActiveModal); + }); + + describe('confirmDelete', () => { + it('Should call delete service on confirmDelete', inject( + [], + fakeAsync(() => { + // GIVEN + spyOn(service, 'delete').and.returnValue(of({})); + + // WHEN + comp.confirmDelete(123); + tick(); + + // THEN + expect(service.delete).toHaveBeenCalledWith(123); + expect(mockActiveModal.dismissSpy).toHaveBeenCalled(); + expect(mockEventManager.broadcastSpy).toHaveBeenCalled(); + }) + )); + }); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/entities/book/book-detail.component.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/entities/book/book-detail.component.spec.ts new file mode 100644 index 0000000000..b0ff94b3ea --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/entities/book/book-detail.component.spec.ts @@ -0,0 +1,40 @@ +/* tslint:disable max-line-length */ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ActivatedRoute } from '@angular/router'; +import { of } from 'rxjs'; + +import { BookstoreTestModule } from '../../../test.module'; +import { BookDetailComponent } from 'app/entities/book/book-detail.component'; +import { Book } from 'app/shared/model/book.model'; + +describe('Component Tests', () => { + describe('Book Management Detail Component', () => { + let comp: BookDetailComponent; + let fixture: ComponentFixture; + const route = ({ data: of({ book: new Book(123) }) } as any) as ActivatedRoute; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [BookstoreTestModule], + declarations: [BookDetailComponent], + providers: [{ provide: ActivatedRoute, useValue: route }] + }) + .overrideTemplate(BookDetailComponent, '') + .compileComponents(); + fixture = TestBed.createComponent(BookDetailComponent); + comp = fixture.componentInstance; + }); + + describe('OnInit', () => { + it('Should call load all on init', () => { + // GIVEN + + // WHEN + comp.ngOnInit(); + + // THEN + expect(comp.book).toEqual(jasmine.objectContaining({ id: 123 })); + }); + }); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/entities/book/book-update.component.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/entities/book/book-update.component.spec.ts new file mode 100644 index 0000000000..336a2e2397 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/entities/book/book-update.component.spec.ts @@ -0,0 +1,60 @@ +/* tslint:disable max-line-length */ +import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing'; +import { HttpResponse } from '@angular/common/http'; +import { Observable, of } from 'rxjs'; + +import { BookstoreTestModule } from '../../../test.module'; +import { BookUpdateComponent } from 'app/entities/book/book-update.component'; +import { BookService } from 'app/entities/book/book.service'; +import { Book } from 'app/shared/model/book.model'; + +describe('Component Tests', () => { + describe('Book Management Update Component', () => { + let comp: BookUpdateComponent; + let fixture: ComponentFixture; + let service: BookService; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [BookstoreTestModule], + declarations: [BookUpdateComponent] + }) + .overrideTemplate(BookUpdateComponent, '') + .compileComponents(); + + fixture = TestBed.createComponent(BookUpdateComponent); + comp = fixture.componentInstance; + service = fixture.debugElement.injector.get(BookService); + }); + + describe('save', () => { + it('Should call update service on save for existing entity', fakeAsync(() => { + // GIVEN + const entity = new Book(123); + spyOn(service, 'update').and.returnValue(of(new HttpResponse({ body: entity }))); + comp.book = entity; + // WHEN + comp.save(); + tick(); // simulate async + + // THEN + expect(service.update).toHaveBeenCalledWith(entity); + expect(comp.isSaving).toEqual(false); + })); + + it('Should call create service on save for new entity', fakeAsync(() => { + // GIVEN + const entity = new Book(); + spyOn(service, 'create').and.returnValue(of(new HttpResponse({ body: entity }))); + comp.book = entity; + // WHEN + comp.save(); + tick(); // simulate async + + // THEN + expect(service.create).toHaveBeenCalledWith(entity); + expect(comp.isSaving).toEqual(false); + })); + }); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/entities/book/book.component.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/entities/book/book.component.spec.ts new file mode 100644 index 0000000000..3b3d472650 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/entities/book/book.component.spec.ts @@ -0,0 +1,51 @@ +/* tslint:disable max-line-length */ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { Observable, of } from 'rxjs'; +import { HttpHeaders, HttpResponse } from '@angular/common/http'; + +import { BookstoreTestModule } from '../../../test.module'; +import { BookComponent } from 'app/entities/book/book.component'; +import { BookService } from 'app/entities/book/book.service'; +import { Book } from 'app/shared/model/book.model'; + +describe('Component Tests', () => { + describe('Book Management Component', () => { + let comp: BookComponent; + let fixture: ComponentFixture; + let service: BookService; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [BookstoreTestModule], + declarations: [BookComponent], + providers: [] + }) + .overrideTemplate(BookComponent, '') + .compileComponents(); + + fixture = TestBed.createComponent(BookComponent); + comp = fixture.componentInstance; + service = fixture.debugElement.injector.get(BookService); + }); + + it('Should call load all on init', () => { + // GIVEN + const headers = new HttpHeaders().append('link', 'link;link'); + spyOn(service, 'query').and.returnValue( + of( + new HttpResponse({ + body: [new Book(123)], + headers + }) + ) + ); + + // WHEN + comp.ngOnInit(); + + // THEN + expect(service.query).toHaveBeenCalled(); + expect(comp.books[0]).toEqual(jasmine.objectContaining({ id: 123 })); + }); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/entities/book/book.service.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/entities/book/book.service.spec.ts new file mode 100644 index 0000000000..cd0c5b7318 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/entities/book/book.service.spec.ts @@ -0,0 +1,137 @@ +/* tslint:disable max-line-length */ +import { TestBed, getTestBed } from '@angular/core/testing'; +import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; +import { HttpClient, HttpResponse } from '@angular/common/http'; +import { of } from 'rxjs'; +import { take, map } from 'rxjs/operators'; +import * as moment from 'moment'; +import { DATE_FORMAT } from 'app/shared/constants/input.constants'; +import { BookService } from 'app/entities/book/book.service'; +import { IBook, Book } from 'app/shared/model/book.model'; + +describe('Service Tests', () => { + describe('Book Service', () => { + let injector: TestBed; + let service: BookService; + let httpMock: HttpTestingController; + let elemDefault: IBook; + let currentDate: moment.Moment; + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule] + }); + injector = getTestBed(); + service = injector.get(BookService); + httpMock = injector.get(HttpTestingController); + currentDate = moment(); + + elemDefault = new Book(0, 'AAAAAAA', 'AAAAAAA', currentDate, 0, 0); + }); + + describe('Service methods', async () => { + it('should find an element', async () => { + const returnedFromService = Object.assign( + { + published: currentDate.format(DATE_FORMAT) + }, + elemDefault + ); + service + .find(123) + .pipe(take(1)) + .subscribe(resp => expect(resp).toMatchObject({ body: elemDefault })); + + const req = httpMock.expectOne({ method: 'GET' }); + req.flush(JSON.stringify(returnedFromService)); + }); + + it('should create a Book', async () => { + const returnedFromService = Object.assign( + { + id: 0, + published: currentDate.format(DATE_FORMAT) + }, + elemDefault + ); + const expected = Object.assign( + { + published: currentDate + }, + returnedFromService + ); + service + .create(new Book(null)) + .pipe(take(1)) + .subscribe(resp => expect(resp).toMatchObject({ body: expected })); + const req = httpMock.expectOne({ method: 'POST' }); + req.flush(JSON.stringify(returnedFromService)); + }); + + it('should update a Book', async () => { + const returnedFromService = Object.assign( + { + title: 'BBBBBB', + author: 'BBBBBB', + published: currentDate.format(DATE_FORMAT), + quantity: 1, + price: 1 + }, + elemDefault + ); + + const expected = Object.assign( + { + published: currentDate + }, + returnedFromService + ); + service + .update(expected) + .pipe(take(1)) + .subscribe(resp => expect(resp).toMatchObject({ body: expected })); + const req = httpMock.expectOne({ method: 'PUT' }); + req.flush(JSON.stringify(returnedFromService)); + }); + + it('should return a list of Book', async () => { + const returnedFromService = Object.assign( + { + title: 'BBBBBB', + author: 'BBBBBB', + published: currentDate.format(DATE_FORMAT), + quantity: 1, + price: 1 + }, + elemDefault + ); + const expected = Object.assign( + { + published: currentDate + }, + returnedFromService + ); + service + .query(expected) + .pipe( + take(1), + map(resp => resp.body) + ) + .subscribe(body => expect(body).toContainEqual(expected)); + const req = httpMock.expectOne({ method: 'GET' }); + req.flush(JSON.stringify([returnedFromService])); + httpMock.verify(); + }); + + it('should delete a Book', async () => { + const rxPromise = service.delete(123).subscribe(resp => expect(resp.ok)); + + const req = httpMock.expectOne({ method: 'DELETE' }); + req.flush({ status: 200 }); + }); + }); + + afterEach(() => { + httpMock.verify(); + }); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/shared/alert/alert-error.component.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/shared/alert/alert-error.component.spec.ts new file mode 100644 index 0000000000..93f344e633 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/shared/alert/alert-error.component.spec.ts @@ -0,0 +1,134 @@ +import { ComponentFixture, TestBed, async, inject, fakeAsync, tick } from '@angular/core/testing'; +import { HttpErrorResponse, HttpHeaders } from '@angular/common/http'; +import { JhiAlertService, JhiEventManager } from 'ng-jhipster'; + +import { BookstoreTestModule } from '../../../test.module'; +import { JhiAlertErrorComponent } from 'app/shared/alert/alert-error.component'; +import { MockAlertService } from '../../../helpers/mock-alert.service'; + +describe('Component Tests', () => { + describe('Alert Error Component', () => { + let comp: JhiAlertErrorComponent; + let fixture: ComponentFixture; + let eventManager: JhiEventManager; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [BookstoreTestModule], + declarations: [JhiAlertErrorComponent], + providers: [ + JhiEventManager, + { + provide: JhiAlertService, + useClass: MockAlertService + } + ] + }) + .overrideTemplate(JhiAlertErrorComponent, '') + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(JhiAlertErrorComponent); + comp = fixture.componentInstance; + eventManager = fixture.debugElement.injector.get(JhiEventManager); + }); + + describe('Error Handling', () => { + it('Should display an alert on status 0', () => { + // GIVEN + eventManager.broadcast({ name: 'bookstoreApp.httpError', content: { status: 0 } }); + // THEN + expect(comp.alerts.length).toBe(1); + expect(comp.alerts[0].msg).toBe('Server not reachable'); + }); + it('Should display an alert on status 404', () => { + // GIVEN + eventManager.broadcast({ name: 'bookstoreApp.httpError', content: { status: 404 } }); + // THEN + expect(comp.alerts.length).toBe(1); + expect(comp.alerts[0].msg).toBe('Not found'); + }); + it('Should display an alert on generic error', () => { + // GIVEN + eventManager.broadcast({ name: 'bookstoreApp.httpError', content: { error: { message: 'Error Message' } } }); + eventManager.broadcast({ name: 'bookstoreApp.httpError', content: { error: 'Second Error Message' } }); + // THEN + expect(comp.alerts.length).toBe(2); + expect(comp.alerts[0].msg).toBe('Error Message'); + expect(comp.alerts[1].msg).toBe('Second Error Message'); + }); + it('Should display an alert on status 400 for generic error', () => { + // GIVEN + const response = new HttpErrorResponse({ + url: 'http://localhost:8080/api/foos', + headers: new HttpHeaders(), + status: 400, + statusText: 'Bad Request', + error: { + type: 'https://www.jhipster.tech/problem/constraint-violation', + title: 'Bad Request', + status: 400, + path: '/api/foos', + message: 'error.validation' + } + }); + eventManager.broadcast({ name: 'bookstoreApp.httpError', content: response }); + // THEN + expect(comp.alerts.length).toBe(1); + expect(comp.alerts[0].msg).toBe('error.validation'); + }); + it('Should display an alert on status 400 for generic error without message', () => { + // GIVEN + const response = new HttpErrorResponse({ + url: 'http://localhost:8080/api/foos', + headers: new HttpHeaders(), + status: 400, + error: 'Bad Request' + }); + eventManager.broadcast({ name: 'bookstoreApp.httpError', content: response }); + // THEN + expect(comp.alerts.length).toBe(1); + expect(comp.alerts[0].msg).toBe('Bad Request'); + }); + it('Should display an alert on status 400 for invalid parameters', () => { + // GIVEN + const response = new HttpErrorResponse({ + url: 'http://localhost:8080/api/foos', + headers: new HttpHeaders(), + status: 400, + statusText: 'Bad Request', + error: { + type: 'https://www.jhipster.tech/problem/constraint-violation', + title: 'Method argument not valid', + status: 400, + path: '/api/foos', + message: 'error.validation', + fieldErrors: [{ objectName: 'foo', field: 'minField', message: 'Min' }] + } + }); + eventManager.broadcast({ name: 'bookstoreApp.httpError', content: response }); + // THEN + expect(comp.alerts.length).toBe(1); + expect(comp.alerts[0].msg).toBe('Error on field "MinField"'); + }); + it('Should display an alert on status 400 for error headers', () => { + // GIVEN + const response = new HttpErrorResponse({ + url: 'http://localhost:8080/api/foos', + headers: new HttpHeaders().append('app-error', 'Error Message').append('app-params', 'foo'), + status: 400, + statusText: 'Bad Request', + error: { + status: 400, + message: 'error.validation' + } + }); + eventManager.broadcast({ name: 'bookstoreApp.httpError', content: response }); + // THEN + expect(comp.alerts.length).toBe(1); + expect(comp.alerts[0].msg).toBe('Error Message'); + }); + }); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/shared/login/login.component.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/shared/login/login.component.spec.ts new file mode 100644 index 0000000000..814af64610 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/shared/login/login.component.spec.ts @@ -0,0 +1,157 @@ +import { ComponentFixture, TestBed, async, inject, fakeAsync, tick } from '@angular/core/testing'; +import { Router } from '@angular/router'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { JhiEventManager } from 'ng-jhipster'; + +import { LoginService } from 'app/core/login/login.service'; +import { JhiLoginModalComponent } from 'app/shared/login/login.component'; +import { StateStorageService } from 'app/core/auth/state-storage.service'; +import { BookstoreTestModule } from '../../../test.module'; +import { MockLoginService } from '../../../helpers/mock-login.service'; +import { MockStateStorageService } from '../../../helpers/mock-state-storage.service'; + +describe('Component Tests', () => { + describe('LoginComponent', () => { + let comp: JhiLoginModalComponent; + let fixture: ComponentFixture; + let mockLoginService: any; + let mockStateStorageService: any; + let mockRouter: any; + let mockEventManager: any; + let mockActiveModal: any; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [BookstoreTestModule], + declarations: [JhiLoginModalComponent], + providers: [ + { + provide: LoginService, + useClass: MockLoginService + }, + { + provide: StateStorageService, + useClass: MockStateStorageService + } + ] + }) + .overrideTemplate(JhiLoginModalComponent, '') + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(JhiLoginModalComponent); + comp = fixture.componentInstance; + mockLoginService = fixture.debugElement.injector.get(LoginService); + mockStateStorageService = fixture.debugElement.injector.get(StateStorageService); + mockRouter = fixture.debugElement.injector.get(Router); + mockEventManager = fixture.debugElement.injector.get(JhiEventManager); + mockActiveModal = fixture.debugElement.injector.get(NgbActiveModal); + }); + + it('should authenticate the user upon login when previous state was set', inject( + [], + fakeAsync(() => { + // GIVEN + const credentials = { + username: 'admin', + password: 'admin', + rememberMe: true + }; + comp.username = 'admin'; + comp.password = 'admin'; + comp.rememberMe = true; + comp.credentials = credentials; + mockLoginService.setResponse({}); + mockStateStorageService.setResponse({ redirect: 'dummy' }); + + // WHEN/ + comp.login(); + tick(); // simulate async + + // THEN + expect(comp.authenticationError).toEqual(false); + expect(mockActiveModal.dismissSpy).toHaveBeenCalledWith('login success'); + expect(mockEventManager.broadcastSpy).toHaveBeenCalledTimes(1); + expect(mockLoginService.loginSpy).toHaveBeenCalledWith(credentials); + expect(mockStateStorageService.getUrlSpy).toHaveBeenCalledTimes(1); + expect(mockStateStorageService.storeUrlSpy).toHaveBeenCalledWith(null); + expect(mockRouter.navigateSpy).toHaveBeenCalledWith([{ redirect: 'dummy' }]); + }) + )); + + it('should authenticate the user upon login when previous state was not set', inject( + [], + fakeAsync(() => { + // GIVEN + const credentials = { + username: 'admin', + password: 'admin', + rememberMe: true + }; + comp.username = 'admin'; + comp.password = 'admin'; + comp.rememberMe = true; + comp.credentials = credentials; + mockLoginService.setResponse({}); + mockStateStorageService.setResponse(null); + + // WHEN + comp.login(); + tick(); // simulate async + + // THEN + expect(comp.authenticationError).toEqual(false); + expect(mockActiveModal.dismissSpy).toHaveBeenCalledWith('login success'); + expect(mockEventManager.broadcastSpy).toHaveBeenCalledTimes(1); + expect(mockLoginService.loginSpy).toHaveBeenCalledWith(credentials); + expect(mockStateStorageService.getUrlSpy).toHaveBeenCalledTimes(1); + expect(mockStateStorageService.storeUrlSpy).not.toHaveBeenCalled(); + expect(mockRouter.navigateSpy).not.toHaveBeenCalled(); + }) + )); + + it('should empty the credentials upon cancel', () => { + // GIVEN + const credentials = { + username: 'admin', + password: 'admin', + rememberMe: true + }; + + const expected = { + username: null, + password: null, + rememberMe: true + }; + + comp.credentials = credentials; + + // WHEN + comp.cancel(); + + // THEN + expect(comp.authenticationError).toEqual(false); + expect(comp.credentials).toEqual(expected); + expect(mockActiveModal.dismissSpy).toHaveBeenCalledWith('cancel'); + }); + + it('should redirect user when register', () => { + // WHEN + comp.register(); + + // THEN + expect(mockActiveModal.dismissSpy).toHaveBeenCalledWith('to state register'); + expect(mockRouter.navigateSpy).toHaveBeenCalledWith(['/register']); + }); + + it('should redirect user when request password', () => { + // WHEN + comp.requestResetPassword(); + + // THEN + expect(mockActiveModal.dismissSpy).toHaveBeenCalledWith('to state requestReset'); + expect(mockRouter.navigateSpy).toHaveBeenCalledWith(['/reset', 'request']); + }); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/helpers/mock-account.service.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/helpers/mock-account.service.ts new file mode 100644 index 0000000000..659bf4d379 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/helpers/mock-account.service.ts @@ -0,0 +1,35 @@ +import { SpyObject } from './spyobject'; +import { AccountService } from 'app/core/auth/account.service'; +import Spy = jasmine.Spy; + +export class MockAccountService extends SpyObject { + getSpy: Spy; + saveSpy: Spy; + fakeResponse: any; + identitySpy: Spy; + + constructor() { + super(AccountService); + + this.fakeResponse = null; + this.getSpy = this.spy('get').andReturn(this); + this.saveSpy = this.spy('save').andReturn(this); + this.setIdentitySpy({}); + } + + subscribe(callback: any) { + callback(this.fakeResponse); + } + + setResponse(json: any): void { + this.fakeResponse = json; + } + + setIdentitySpy(json: any): any { + this.identitySpy = this.spy('identity').andReturn(Promise.resolve(json)); + } + + setIdentityResponse(json: any): void { + this.setIdentitySpy(json); + } +} diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/helpers/mock-active-modal.service.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/helpers/mock-active-modal.service.ts new file mode 100644 index 0000000000..8bf0cc966f --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/helpers/mock-active-modal.service.ts @@ -0,0 +1,12 @@ +import { SpyObject } from './spyobject'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import Spy = jasmine.Spy; + +export class MockActiveModal extends SpyObject { + dismissSpy: Spy; + + constructor() { + super(NgbActiveModal); + this.dismissSpy = this.spy('dismiss').andReturn(this); + } +} diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/helpers/mock-alert.service.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/helpers/mock-alert.service.ts new file mode 100644 index 0000000000..87f36c71e2 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/helpers/mock-alert.service.ts @@ -0,0 +1,11 @@ +import { SpyObject } from './spyobject'; +import { JhiAlertService, JhiAlert } from 'ng-jhipster'; + +export class MockAlertService extends SpyObject { + constructor() { + super(JhiAlertService); + } + addAlert(alertOptions: JhiAlert) { + return alertOptions; + } +} diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/helpers/mock-event-manager.service.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/helpers/mock-event-manager.service.ts new file mode 100644 index 0000000000..a71b5d9314 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/helpers/mock-event-manager.service.ts @@ -0,0 +1,12 @@ +import { SpyObject } from './spyobject'; +import { JhiEventManager } from 'ng-jhipster'; +import Spy = jasmine.Spy; + +export class MockEventManager extends SpyObject { + broadcastSpy: Spy; + + constructor() { + super(JhiEventManager); + this.broadcastSpy = this.spy('broadcast').andReturn(this); + } +} diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/helpers/mock-login.service.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/helpers/mock-login.service.ts new file mode 100644 index 0000000000..93a8ca575f --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/helpers/mock-login.service.ts @@ -0,0 +1,29 @@ +import { SpyObject } from './spyobject'; +import { LoginService } from 'app/core/login/login.service'; +import Spy = jasmine.Spy; + +export class MockLoginService extends SpyObject { + loginSpy: Spy; + logoutSpy: Spy; + registerSpy: Spy; + requestResetPasswordSpy: Spy; + cancelSpy: Spy; + + constructor() { + super(LoginService); + + this.setLoginSpy({}); + this.logoutSpy = this.spy('logout').andReturn(this); + this.registerSpy = this.spy('register').andReturn(this); + this.requestResetPasswordSpy = this.spy('requestResetPassword').andReturn(this); + this.cancelSpy = this.spy('cancel').andReturn(this); + } + + setLoginSpy(json: any) { + this.loginSpy = this.spy('login').andReturn(Promise.resolve(json)); + } + + setResponse(json: any): void { + this.setLoginSpy(json); + } +} diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/helpers/mock-route.service.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/helpers/mock-route.service.ts new file mode 100644 index 0000000000..3465e05524 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/helpers/mock-route.service.ts @@ -0,0 +1,29 @@ +import { ActivatedRoute, Router } from '@angular/router'; +import { SpyObject } from './spyobject'; +import { Observable, of } from 'rxjs'; +import Spy = jasmine.Spy; + +export class MockActivatedRoute extends ActivatedRoute { + constructor(parameters?: any) { + super(); + this.queryParams = of(parameters); + this.params = of(parameters); + this.data = of({ + ...parameters, + pagingParams: { + page: 10, + ascending: false, + predicate: 'id' + } + }); + } +} + +export class MockRouter extends SpyObject { + navigateSpy: Spy; + + constructor() { + super(Router); + this.navigateSpy = this.spy('navigate'); + } +} diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/helpers/mock-state-storage.service.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/helpers/mock-state-storage.service.ts new file mode 100644 index 0000000000..1398c7b28b --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/helpers/mock-state-storage.service.ts @@ -0,0 +1,22 @@ +import { SpyObject } from './spyobject'; +import { StateStorageService } from 'app/core/auth/state-storage.service'; +import Spy = jasmine.Spy; + +export class MockStateStorageService extends SpyObject { + getUrlSpy: Spy; + storeUrlSpy: Spy; + + constructor() { + super(StateStorageService); + this.setUrlSpy({}); + this.storeUrlSpy = this.spy('storeUrl').andReturn(this); + } + + setUrlSpy(json) { + this.getUrlSpy = this.spy('getUrl').andReturn(json); + } + + setResponse(json: any): void { + this.setUrlSpy(json); + } +} diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/helpers/spyobject.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/helpers/spyobject.ts new file mode 100644 index 0000000000..949e067ef5 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/helpers/spyobject.ts @@ -0,0 +1,69 @@ +export interface GuinessCompatibleSpy extends jasmine.Spy { + /** By chaining the spy with and.returnValue, all calls to the function will return a specific + * value. */ + andReturn(val: any): void; + /** By chaining the spy with and.callFake, all calls to the spy will delegate to the supplied + * function. */ + andCallFake(fn: Function): GuinessCompatibleSpy; + /** removes all recorded calls */ + reset(); +} + +export class SpyObject { + static stub(object = null, config = null, overrides = null) { + if (!(object instanceof SpyObject)) { + overrides = config; + config = object; + object = new SpyObject(); + } + + const m = {}; + Object.keys(config).forEach(key => (m[key] = config[key])); + Object.keys(overrides).forEach(key => (m[key] = overrides[key])); + Object.keys(m).forEach(key => { + object.spy(key).andReturn(m[key]); + }); + return object; + } + + constructor(type = null) { + if (type) { + Object.keys(type.prototype).forEach(prop => { + let m = null; + try { + m = type.prototype[prop]; + } catch (e) { + // As we are creating spys for abstract classes, + // these classes might have getters that throw when they are accessed. + // As we are only auto creating spys for methods, this + // should not matter. + } + if (typeof m === 'function') { + this.spy(prop); + } + }); + } + } + + spy(name) { + if (!this[name]) { + this[name] = this._createGuinnessCompatibleSpy(name); + } + return this[name]; + } + + prop(name, value) { + this[name] = value; + } + + /** @internal */ + _createGuinnessCompatibleSpy(name): GuinessCompatibleSpy { + const newSpy: GuinessCompatibleSpy = jasmine.createSpy(name); + newSpy.andCallFake = newSpy.and.callFake; + newSpy.andReturn = newSpy.and.returnValue; + newSpy.reset = newSpy.calls.reset; + // revisit return null here (previously needed for rtts_assert). + newSpy.and.returnValue(null); + return newSpy; + } +} diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/test.module.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/test.module.ts new file mode 100644 index 0000000000..c66241f9bb --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/test.module.ts @@ -0,0 +1,63 @@ +import { DatePipe } from '@angular/common'; +import { ActivatedRoute, Router } from '@angular/router'; +import { NgModule, ElementRef, Renderer } from '@angular/core'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { NgbActiveModal, NgbModal } from '@ng-bootstrap/ng-bootstrap'; +import { JhiDataUtils, JhiDateUtils, JhiEventManager, JhiAlertService, JhiParseLinks } from 'ng-jhipster'; + +import { AccountService, LoginModalService } from 'app/core'; +import { MockAccountService } from './helpers/mock-account.service'; +import { MockActivatedRoute, MockRouter } from './helpers/mock-route.service'; +import { MockActiveModal } from './helpers/mock-active-modal.service'; +import { MockEventManager } from './helpers/mock-event-manager.service'; + +@NgModule({ + providers: [ + DatePipe, + JhiDataUtils, + JhiDateUtils, + JhiParseLinks, + { + provide: JhiEventManager, + useClass: MockEventManager + }, + { + provide: NgbActiveModal, + useClass: MockActiveModal + }, + { + provide: ActivatedRoute, + useValue: new MockActivatedRoute({ id: 123 }) + }, + { + provide: Router, + useClass: MockRouter + }, + { + provide: AccountService, + useClass: MockAccountService + }, + { + provide: LoginModalService, + useValue: null + }, + { + provide: ElementRef, + useValue: null + }, + { + provide: Renderer, + useValue: null + }, + { + provide: JhiAlertService, + useValue: null + }, + { + provide: NgbModal, + useValue: null + } + ], + imports: [HttpClientTestingModule] +}) +export class BookstoreTestModule {} diff --git a/jhipster-5/bookstore-monolith/src/test/resources/config/application.yml b/jhipster-5/bookstore-monolith/src/test/resources/config/application.yml new file mode 100644 index 0000000000..34c6ca3e15 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/resources/config/application.yml @@ -0,0 +1,105 @@ +# =================================================================== +# Spring Boot configuration. +# +# This configuration is used for unit/integration tests. +# +# More information on profiles: https://www.jhipster.tech/profiles/ +# More information on configuration properties: https://www.jhipster.tech/common-application-properties/ +# =================================================================== + +# =================================================================== +# Standard Spring Boot properties. +# Full reference is available at: +# http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html +# =================================================================== + + +spring: + application: + name: Bookstore + datasource: + type: com.zaxxer.hikari.HikariDataSource + url: jdbc:h2:mem:Bookstore;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE + name: + username: + password: + hikari: + auto-commit: false + jpa: + database-platform: io.github.jhipster.domain.util.FixedH2Dialect + database: H2 + open-in-view: false + show-sql: false + hibernate: + ddl-auto: none + naming: + physical-strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy + implicit-strategy: org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy + properties: + hibernate.id.new_generator_mappings: true + hibernate.connection.provider_disables_autocommit: true + hibernate.cache.use_second_level_cache: false + hibernate.cache.use_query_cache: false + hibernate.generate_statistics: false + hibernate.hbm2ddl.auto: validate + hibernate.jdbc.time_zone: UTC + liquibase: + contexts: test + mail: + host: localhost + messages: + basename: i18n/messages + mvc: + favicon: + enabled: false + thymeleaf: + mode: HTML + + +server: + port: 10344 + address: localhost + +# =================================================================== +# JHipster specific properties +# +# Full reference is available at: https://www.jhipster.tech/common-application-properties/ +# =================================================================== + +jhipster: + async: + core-pool-size: 1 + max-pool-size: 50 + queue-capacity: 10000 + # To test logstash appender + logging: + logstash: + enabled: true + host: localhost + port: 5000 + queue-size: 512 + mail: + from: test@localhost + base-url: http://127.0.0.1:8080 + security: + authentication: + jwt: + # This token must be encoded using Base64 (you can type `echo 'secret-key'|base64` on your command line) + base64-secret: NDJmOTVlZjI2NzhlZDRjNmVkNTM1NDE2NjkyNDljZDJiNzBlMjI5YmZjMjY3MzdjZmZlMjI3NjE4OTRkNzc5MWYzNDNlYWMzYmJjOWRmMjc5ZWQyZTZmOWZkOTMxZWZhNWE1MTVmM2U2NjFmYjhlNDc2Y2Q3NzliMGY0YzFkNmI= + # Token is valid 24 hours + token-validity-in-seconds: 86400 + metrics: + logs: # Reports metrics in the logs + enabled: true + report-frequency: 60 # in seconds + +# =================================================================== +# Application specific properties +# Add your own application properties here, see the ApplicationProperties class +# to have type-safe configuration, like in the JHipsterProperties above +# +# More documentation is available at: +# https://www.jhipster.tech/common-application-properties/ +# =================================================================== + +# application: diff --git a/jhipster-5/bookstore-monolith/src/test/resources/i18n/messages_en.properties b/jhipster-5/bookstore-monolith/src/test/resources/i18n/messages_en.properties new file mode 100644 index 0000000000..f19db8692f --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/resources/i18n/messages_en.properties @@ -0,0 +1 @@ +email.test.title=test title diff --git a/jhipster-5/bookstore-monolith/src/test/resources/logback.xml b/jhipster-5/bookstore-monolith/src/test/resources/logback.xml new file mode 100644 index 0000000000..6244807dfa --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/resources/logback.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jhipster-5/bookstore-monolith/src/test/resources/templates/mail/testEmail.html b/jhipster-5/bookstore-monolith/src/test/resources/templates/mail/testEmail.html new file mode 100644 index 0000000000..a4ca16a79f --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/resources/templates/mail/testEmail.html @@ -0,0 +1 @@ + diff --git a/jhipster-5/bookstore-monolith/tsconfig-aot.json b/jhipster-5/bookstore-monolith/tsconfig-aot.json new file mode 100644 index 0000000000..110cde9fd6 --- /dev/null +++ b/jhipster-5/bookstore-monolith/tsconfig-aot.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "es2015", + "moduleResolution": "node", + "sourceMap": false, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "removeComments": false, + "noImplicitAny": false, + "suppressImplicitAnyIndexErrors": true, + "skipLibCheck": true, + "outDir": "target/www/app", + "lib": ["es7", "dom"], + "typeRoots": ["node_modules/@types"], + "baseUrl": "./", + "paths": { + "app/*": ["src/main/webapp/app/*"] + }, + "importHelpers": true + }, + "angularCompilerOptions": { + "genDir": "target/aot", + "skipMetadataEmit": true, + "fullTemplateTypeCheck": true, + "preserveWhitespaces": true + } +} diff --git a/jhipster-5/bookstore-monolith/tsconfig.json b/jhipster-5/bookstore-monolith/tsconfig.json new file mode 100644 index 0000000000..dd6343ab62 --- /dev/null +++ b/jhipster-5/bookstore-monolith/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "commonjs", + "moduleResolution": "node", + "sourceMap": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "removeComments": false, + "noImplicitAny": false, + "skipLibCheck": true, + "suppressImplicitAnyIndexErrors": true, + "outDir": "target/www/app", + "lib": ["es7", "dom"], + "typeRoots": ["node_modules/@types"], + "baseUrl": "./", + "paths": { + "app/*": ["src/main/webapp/app/*"] + }, + "importHelpers": true, + "allowJs": true + }, + "include": ["src/main/webapp/app", "src/test/javascript/"], + "exclude": ["node_modules"] +} diff --git a/jhipster-5/bookstore-monolith/tslint.json b/jhipster-5/bookstore-monolith/tslint.json new file mode 100644 index 0000000000..3b8456d2fd --- /dev/null +++ b/jhipster-5/bookstore-monolith/tslint.json @@ -0,0 +1,76 @@ +{ + "rulesDirectory": ["node_modules/codelyzer"], + "extends": ["tslint-config-prettier"], + "rules": { + "class-name": true, + "comment-format": [true, "check-space"], + "curly": true, + "eofline": true, + "forin": true, + "indent": [true, "spaces"], + "label-position": true, + "member-access": false, + "member-ordering": [true, "static-before-instance", "variables-before-functions"], + "no-arg": true, + "no-bitwise": true, + "no-console": [true, "debug", "info", "time", "timeEnd", "trace"], + "no-construct": true, + "no-debugger": true, + "no-duplicate-variable": true, + "no-empty": false, + "no-eval": true, + "no-inferrable-types": [true], + "no-shadowed-variable": true, + "no-string-literal": false, + "no-switch-case-fall-through": true, + "no-trailing-whitespace": true, + "no-unused-expression": true, + "no-var-keyword": true, + "object-literal-sort-keys": false, + "one-line": [true, "check-open-brace", "check-catch", "check-else", "check-whitespace"], + "quotemark": [true, "single", "avoid-escape"], + "radix": true, + "semicolon": [true, "always", "ignore-bound-class-methods"], + "triple-equals": [true, "allow-null-check"], + "typedef-whitespace": [ + true, + { + "call-signature": "nospace", + "index-signature": "nospace", + "parameter": "nospace", + "property-declaration": "nospace", + "variable-declaration": "nospace" + } + ], + "variable-name": false, + "whitespace": [true, "check-branch", "check-decl", "check-operator", "check-separator", "check-type"], + "prefer-const": true, + "arrow-parens": [true, "ban-single-arg-parens"], + "arrow-return-shorthand": [true], + "import-spacing": true, + "no-consecutive-blank-lines": [true], + "object-literal-shorthand": true, + "space-before-function-paren": [ + true, + { + "asyncArrow": "always", + "anonymous": "never", + "constructor": "never", + "method": "never", + "named": "never" + } + ], + + "directive-selector": [true, "attribute", "jhi", "camelCase"], + "component-selector": [true, "element", "jhi", "kebab-case"], + "use-input-property-decorator": true, + "use-output-property-decorator": true, + "use-host-property-decorator": true, + "no-input-rename": true, + "no-output-rename": true, + "use-life-cycle-interface": true, + "use-pipe-transform-interface": false, + "component-class-suffix": true, + "directive-class-suffix": true + } +} diff --git a/jhipster-5/bookstore-monolith/webpack/logo-jhipster.png b/jhipster-5/bookstore-monolith/webpack/logo-jhipster.png new file mode 100644 index 0000000000..d8eb48da05 Binary files /dev/null and b/jhipster-5/bookstore-monolith/webpack/logo-jhipster.png differ diff --git a/jhipster-5/bookstore-monolith/webpack/utils.js b/jhipster-5/bookstore-monolith/webpack/utils.js new file mode 100644 index 0000000000..2fce772341 --- /dev/null +++ b/jhipster-5/bookstore-monolith/webpack/utils.js @@ -0,0 +1,44 @@ +const fs = require('fs'); +const path = require('path'); + +module.exports = { + parseVersion, + root, + isExternalLib +}; + +const parseString = require('xml2js').parseString; +// return the version number from `pom.xml` file +function parseVersion() { + let version = null; + const pomXml = fs.readFileSync('pom.xml', 'utf8'); + parseString(pomXml, (err, result) => { + if (err) { + throw new Error('Failed to parse pom.xml: ' + err); + } + if (result.project.version && result.project.version[0]) { + version = result.project.version[0]; + } else if (result.project.parent && result.project.parent[0] && result.project.parent[0].version && result.project.parent[0].version[0]) { + version = result.project.parent[0].version[0]; + } + }); + if (version === null) { + throw new Error('pom.xml is malformed. No version is defined'); + } + return version; +} + +const _root = path.resolve(__dirname, '..'); + +function root(args) { + args = Array.prototype.slice.call(arguments, 0); + return path.join.apply(path, [_root].concat(args)); +} + +function isExternalLib(module, check = /node_modules/) { + const req = module.userRequest; + if (typeof req !== 'string') { + return false; + } + return req.search(check) >= 0; +} diff --git a/jhipster-5/bookstore-monolith/webpack/webpack.common.js b/jhipster-5/bookstore-monolith/webpack/webpack.common.js new file mode 100644 index 0000000000..d8fd26c157 --- /dev/null +++ b/jhipster-5/bookstore-monolith/webpack/webpack.common.js @@ -0,0 +1,86 @@ +const webpack = require('webpack'); +const CopyWebpackPlugin = require('copy-webpack-plugin'); +const HtmlWebpackPlugin = require('html-webpack-plugin'); +const rxPaths = require('rxjs/_esm5/path-mapping'); + +const utils = require('./utils.js'); + +module.exports = (options) => ({ + resolve: { + extensions: ['.ts', '.js'], + modules: ['node_modules'], + alias: { + app: utils.root('src/main/webapp/app/'), + ...rxPaths() + } + }, + stats: { + children: false + }, + module: { + rules: [ + { + test: /\.html$/, + loader: 'html-loader', + options: { + minimize: true, + caseSensitive: true, + removeAttributeQuotes:false, + minifyJS:false, + minifyCSS:false + }, + exclude: /(src\/main\/webapp\/index.html)/ + }, + { + test: /\.(jpe?g|png|gif|svg|woff2?|ttf|eot)$/i, + loader: 'file-loader', + options: { + digest: 'hex', + hash: 'sha512', + name: 'content/[hash].[ext]' + } + }, + { + test: /manifest.webapp$/, + loader: 'file-loader', + options: { + name: 'manifest.webapp' + } + }, + // Ignore warnings about System.import in Angular + { test: /[\/\\]@angular[\/\\].+\.js$/, parser: { system: true } }, + ] + }, + plugins: [ + new webpack.DefinePlugin({ + 'process.env': { + NODE_ENV: `'${options.env}'`, + BUILD_TIMESTAMP: `'${new Date().getTime()}'`, + VERSION: `'${utils.parseVersion()}'`, + DEBUG_INFO_ENABLED: options.env === 'development', + // The root URL for API calls, ending with a '/' - for example: `"https://www.jhipster.tech:8081/myservice/"`. + // If this URL is left empty (""), then it will be relative to the current context. + // If you use an API server, in `prod` mode, you will need to enable CORS + // (see the `jhipster.cors` common JHipster property in the `application-*.yml` configurations) + SERVER_API_URL: `''` + } + }), + new CopyWebpackPlugin([ + { from: './node_modules/swagger-ui/dist/css', to: 'swagger-ui/dist/css' }, + { from: './node_modules/swagger-ui/dist/lib', to: 'swagger-ui/dist/lib' }, + { from: './node_modules/swagger-ui/dist/swagger-ui.min.js', to: 'swagger-ui/dist/swagger-ui.min.js' }, + { from: './src/main/webapp/swagger-ui/', to: 'swagger-ui' }, + { from: './src/main/webapp/content/', to: 'content' }, + { from: './src/main/webapp/favicon.ico', to: 'favicon.ico' }, + { from: './src/main/webapp/manifest.webapp', to: 'manifest.webapp' }, + // jhipster-needle-add-assets-to-webpack - JHipster will add/remove third-party resources in this array + { from: './src/main/webapp/robots.txt', to: 'robots.txt' } + ]), + new HtmlWebpackPlugin({ + template: './src/main/webapp/index.html', + chunks: ['vendors', 'polyfills', 'main', 'global'], + chunksSortMode: 'manual', + inject: 'body' + }) + ] +}); diff --git a/jhipster-5/bookstore-monolith/webpack/webpack.dev.js b/jhipster-5/bookstore-monolith/webpack/webpack.dev.js new file mode 100644 index 0000000000..d05a7ddea8 --- /dev/null +++ b/jhipster-5/bookstore-monolith/webpack/webpack.dev.js @@ -0,0 +1,148 @@ +const webpack = require('webpack'); +const writeFilePlugin = require('write-file-webpack-plugin'); +const webpackMerge = require('webpack-merge'); +const BrowserSyncPlugin = require('browser-sync-webpack-plugin'); +const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin'); +const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin'); +const SimpleProgressWebpackPlugin = require('simple-progress-webpack-plugin'); +const WebpackNotifierPlugin = require('webpack-notifier'); +const path = require('path'); +const sass = require('sass'); + +const utils = require('./utils.js'); +const commonConfig = require('./webpack.common.js'); + +const ENV = 'development'; + +module.exports = (options) => webpackMerge(commonConfig({ env: ENV }), { + devtool: 'eval-source-map', + devServer: { + contentBase: './target/www', + proxy: [{ + context: [ + /* jhipster-needle-add-entity-to-webpack - JHipster will add entity api paths here */ + '/api', + '/management', + '/swagger-resources', + '/v2/api-docs', + '/h2-console', + '/auth' + ], + target: `http${options.tls ? 's' : ''}://127.0.0.1:8080`, + secure: false, + changeOrigin: options.tls, + headers: { host: 'localhost:9000' } + }], + stats: options.stats, + watchOptions: { + ignored: /node_modules/ + } + }, + entry: { + polyfills: './src/main/webapp/app/polyfills', + global: './src/main/webapp/content/scss/global.scss', + main: './src/main/webapp/app/app.main' + }, + output: { + path: utils.root('target/www'), + filename: 'app/[name].bundle.js', + chunkFilename: 'app/[id].chunk.js' + }, + module: { + rules: [{ + test: /\.ts$/, + enforce: 'pre', + loader: 'tslint-loader', + exclude: [/(node_modules)/, new RegExp('reflect-metadata\\' + path.sep + 'Reflect\\.ts')] + }, + { + test: /\.ts$/, + use: [ + 'angular2-template-loader', + { + loader: 'cache-loader', + options: { + cacheDirectory: path.resolve('target/cache-loader') + } + }, + { + loader: 'thread-loader', + options: { + // there should be 1 cpu for the fork-ts-checker-webpack-plugin + workers: require('os').cpus().length - 1 + } + }, + { + loader: 'ts-loader', + options: { + transpileOnly: true, + happyPackMode: true + } + }, + 'angular-router-loader' + ], + exclude: /(node_modules)/ + }, + { + test: /\.scss$/, + use: ['to-string-loader', 'css-loader', { + loader: 'sass-loader', + options: { implementation: sass } + }], + exclude: /(vendor\.scss|global\.scss)/ + }, + { + test: /(vendor\.scss|global\.scss)/, + use: ['style-loader', 'css-loader', 'postcss-loader', { + loader: 'sass-loader', + options: { implementation: sass } + }] + }, + { + test: /\.css$/, + use: ['to-string-loader', 'css-loader'], + exclude: /(vendor\.css|global\.css)/ + }, + { + test: /(vendor\.css|global\.css)/, + use: ['style-loader', 'css-loader'] + }] + }, + stats: process.env.JHI_DISABLE_WEBPACK_LOGS ? 'none' : options.stats, + plugins: [ + process.env.JHI_DISABLE_WEBPACK_LOGS + ? null + : new SimpleProgressWebpackPlugin({ + format: options.stats === 'minimal' ? 'compact' : 'expanded' + }), + new FriendlyErrorsWebpackPlugin(), + new ForkTsCheckerWebpackPlugin(), + new BrowserSyncPlugin({ + host: 'localhost', + port: 9000, + proxy: { + target: 'http://localhost:9060' + }, + socket: { + clients: { + heartbeatTimeout: 60000 + } + } + }, { + reload: false + }), + new webpack.ContextReplacementPlugin( + /angular(\\|\/)core(\\|\/)/, + path.resolve(__dirname, './src/main/webapp') + ), + new writeFilePlugin(), + new webpack.WatchIgnorePlugin([ + utils.root('src/test'), + ]), + new WebpackNotifierPlugin({ + title: 'JHipster', + contentImage: path.join(__dirname, 'logo-jhipster.png') + }) + ].filter(Boolean), + mode: 'development' +}); diff --git a/jhipster-5/bookstore-monolith/webpack/webpack.prod.js b/jhipster-5/bookstore-monolith/webpack/webpack.prod.js new file mode 100644 index 0000000000..ebafa2f631 --- /dev/null +++ b/jhipster-5/bookstore-monolith/webpack/webpack.prod.js @@ -0,0 +1,144 @@ +const webpack = require('webpack'); +const webpackMerge = require('webpack-merge'); +const MiniCssExtractPlugin = require('mini-css-extract-plugin'); +const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin"); +const Visualizer = require('webpack-visualizer-plugin'); +const MomentLocalesPlugin = require('moment-locales-webpack-plugin'); +const TerserPlugin = require('terser-webpack-plugin'); +const WorkboxPlugin = require('workbox-webpack-plugin'); +const AngularCompilerPlugin = require('@ngtools/webpack').AngularCompilerPlugin; +const path = require('path'); + +const utils = require('./utils.js'); +const commonConfig = require('./webpack.common.js'); + +const ENV = 'production'; +const sass = require('sass'); + +module.exports = webpackMerge(commonConfig({ env: ENV }), { + // Enable source maps. Please note that this will slow down the build. + // You have to enable it in UglifyJSPlugin config below and in tsconfig-aot.json as well + // devtool: 'source-map', + entry: { + polyfills: './src/main/webapp/app/polyfills', + global: './src/main/webapp/content/scss/global.scss', + main: './src/main/webapp/app/app.main' + }, + output: { + path: utils.root('target/www'), + filename: 'app/[name].[hash].bundle.js', + chunkFilename: 'app/[id].[hash].chunk.js' + }, + module: { + rules: [{ + test: /(?:\.ngfactory\.js|\.ngstyle\.js|\.ts)$/, + loader: '@ngtools/webpack' + }, + { + test: /\.scss$/, + use: ['to-string-loader', 'css-loader', { + loader: 'sass-loader', + options: { implementation: sass } + }], + exclude: /(vendor\.scss|global\.scss)/ + }, + { + test: /(vendor\.scss|global\.scss)/, + use: [ + MiniCssExtractPlugin.loader, + 'css-loader', + 'postcss-loader', + { + loader: 'sass-loader', + options: { implementation: sass } + } + ] + }, + { + test: /\.css$/, + use: ['to-string-loader', 'css-loader'], + exclude: /(vendor\.css|global\.css)/ + }, + { + test: /(vendor\.css|global\.css)/, + use: [ + MiniCssExtractPlugin.loader, + 'css-loader', + 'postcss-loader' + ] + }] + }, + optimization: { + runtimeChunk: false, + splitChunks: { + cacheGroups: { + commons: { + test: /[\\/]node_modules[\\/]/, + name: 'vendors', + chunks: 'all' + } + } + }, + minimizer: [ + new TerserPlugin({ + parallel: true, + cache: true, + terserOptions: { + ie8: false, + // sourceMap: true, // Enable source maps. Please note that this will slow down the build + compress: { + dead_code: true, + warnings: false, + properties: true, + drop_debugger: true, + conditionals: true, + booleans: true, + loops: true, + unused: true, + toplevel: true, + if_return: true, + inline: true, + join_vars: true + }, + output: { + comments: false, + beautify: false, + indent_level: 2 + } + } + }), + new OptimizeCSSAssetsPlugin({}) + ] + }, + plugins: [ + new MiniCssExtractPlugin({ + // Options similar to the same options in webpackOptions.output + // both options are optional + filename: '[name].[contenthash].css', + chunkFilename: '[id].css' + }), + new MomentLocalesPlugin({ + localesToKeep: [ + // jhipster-needle-i18n-language-moment-webpack - JHipster will add/remove languages in this array + ] + }), + new Visualizer({ + // Webpack statistics in target folder + filename: '../stats.html' + }), + new AngularCompilerPlugin({ + mainPath: utils.root('src/main/webapp/app/app.main.ts'), + tsConfigPath: utils.root('tsconfig-aot.json'), + sourceMap: true + }), + new webpack.LoaderOptionsPlugin({ + minimize: true, + debug: false + }), + new WorkboxPlugin.GenerateSW({ + clientsClaim: true, + skipWaiting: true, + }) + ], + mode: 'production' +}); diff --git a/jhipster-5/pom.xml b/jhipster-5/pom.xml new file mode 100644 index 0000000000..df60b01317 --- /dev/null +++ b/jhipster-5/pom.xml @@ -0,0 +1,22 @@ + + + 4.0.0 + com.baeldung.jhipster + jhipster-5 + 1.0.0-SNAPSHOT + JHipster + pom + + + parent-boot-1 + com.baeldung + 0.0.1-SNAPSHOT + ../parent-boot-1 + + + + bookstore-monolith + + + diff --git a/jhipster/pom.xml b/jhipster/pom.xml index 3fcc53b354..c50aac0c7a 100644 --- a/jhipster/pom.xml +++ b/jhipster/pom.xml @@ -15,6 +15,13 @@ ../parent-boot-1 + + + org.hibernate + hibernate-java8 + + + jhipster-monolithic jhipster-microservice diff --git a/jjwt/README.md b/jjwt/README.md index 54a5226056..ed18363dfc 100644 --- a/jjwt/README.md +++ b/jjwt/README.md @@ -42,7 +42,6 @@ Available commands (assumes httpie - https://github.com/jkbrzt/httpie): Parse passed in JWT enforcing the 'iss' registered claim and the 'hasMotorcycle' custom claim ``` -The Baeldung post that compliments this repo can be found [here](http://www.baeldung.com/) ## Relevant articles: diff --git a/json/README.md b/json/README.md index c0ca4b00ef..7ef4cc9b01 100644 --- a/json/README.md +++ b/json/README.md @@ -12,4 +12,4 @@ - [Introduction to the JSON Binding API (JSR 367) in Java](http://www.baeldung.com/java-json-binding-api) - [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) -- [Testing Web APIs with Postman Collections](https://www.baeldung.com/postman-testing-collections) +- [Escape JSON String in Java](https://www.baeldung.com/java-json-escaping) diff --git a/kotlin-libraries-2/.gitignore b/kotlin-libraries-2/.gitignore new file mode 100644 index 0000000000..0c017e8f8c --- /dev/null +++ b/kotlin-libraries-2/.gitignore @@ -0,0 +1,14 @@ +/bin/ + +#ignore gradle +.gradle/ + + +#ignore build and generated files +build/ +node/ +out/ + +#ignore installed node modules and package lock file +node_modules/ +package-lock.json diff --git a/kotlin-libraries-2/README.md b/kotlin-libraries-2/README.md new file mode 100644 index 0000000000..ff12555376 --- /dev/null +++ b/kotlin-libraries-2/README.md @@ -0,0 +1 @@ +## Relevant articles: diff --git a/kotlin-libraries-2/pom.xml b/kotlin-libraries-2/pom.xml new file mode 100644 index 0000000000..e2e261cb1b --- /dev/null +++ b/kotlin-libraries-2/pom.xml @@ -0,0 +1,34 @@ + + + 4.0.0 + kotlin-libraries-2 + kotlin-libraries-2 + jar + + + com.baeldung + parent-kotlin + 1.0.0-SNAPSHOT + ../parent-kotlin + + + + + com.fasterxml.jackson.module + jackson-module-kotlin + + + junit + junit + test + + + + + + + + + + diff --git a/kotlin-libraries-2/resources/logback.xml b/kotlin-libraries-2/resources/logback.xml new file mode 100644 index 0000000000..9452207268 --- /dev/null +++ b/kotlin-libraries-2/resources/logback.xml @@ -0,0 +1,11 @@ + + + + %d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + \ No newline at end of file diff --git a/kotlin-libraries-2/src/main/kotlin/com/baeldung/kotlin/jackson/Book.kt b/kotlin-libraries-2/src/main/kotlin/com/baeldung/kotlin/jackson/Book.kt new file mode 100644 index 0000000000..4ff47ea987 --- /dev/null +++ b/kotlin-libraries-2/src/main/kotlin/com/baeldung/kotlin/jackson/Book.kt @@ -0,0 +1,8 @@ +package com.baeldung.kotlin.jackson + +import com.fasterxml.jackson.annotation.* + +@JsonInclude(JsonInclude.Include.NON_EMPTY) +data class Book(var title: String, @JsonProperty("author") var authorName: String) { + var genres: List? = emptyList() +} \ No newline at end of file diff --git a/kotlin-libraries-2/src/main/kotlin/com/baeldung/kotlin/jackson/Movie.kt b/kotlin-libraries-2/src/main/kotlin/com/baeldung/kotlin/jackson/Movie.kt new file mode 100644 index 0000000000..445b6013d5 --- /dev/null +++ b/kotlin-libraries-2/src/main/kotlin/com/baeldung/kotlin/jackson/Movie.kt @@ -0,0 +1,3 @@ +package com.baeldung.kotlin.jackson + +data class Movie(var name: String, var studio: String, var rating: Float? = 1f) \ No newline at end of file diff --git a/kotlin-libraries-2/src/test/kotlin/com/baeldung/kotlin/jackson/JacksonUnitTest.kt b/kotlin-libraries-2/src/test/kotlin/com/baeldung/kotlin/jackson/JacksonUnitTest.kt new file mode 100644 index 0000000000..84171d9019 --- /dev/null +++ b/kotlin-libraries-2/src/test/kotlin/com/baeldung/kotlin/jackson/JacksonUnitTest.kt @@ -0,0 +1,114 @@ +package com.baeldung.kotlin.jackson + +import org.junit.Test +import kotlin.test.assertTrue +import kotlin.test.assertFalse +import kotlin.test.assertEquals +import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper +import com.fasterxml.jackson.module.kotlin.readValue +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.module.kotlin.KotlinModule + +class JacksonUnitTest { + //val mapper = jacksonObjectMapper() + val mapper = ObjectMapper().registerModule(KotlinModule()) + + + @Test + fun whenSerializeMovie_thenSuccess() { + val movie = Movie("Endgame", "Marvel", 9.2f) + val serialized = mapper.writeValueAsString(movie) + + val json = """{"name":"Endgame","studio":"Marvel","rating":9.2}""" + assertEquals(serialized, json) + } + + @Test + fun whenDeserializeMovie_thenSuccess() { + val json = """{"name":"Endgame","studio":"Marvel","rating":9.2}""" + // val movie: Movie = mapper.readValue(json) + val movie = mapper.readValue(json) + + assertEquals(movie.name, "Endgame") + assertEquals(movie.studio, "Marvel") + assertEquals(movie.rating, 9.2f) + } + + @Test + fun whenDeserializeMovieWithMissingValue_thenUseDefaultValue() { + val json = """{"name":"Endgame","studio":"Marvel"}""" + val movie: Movie = mapper.readValue(json) + + assertEquals(movie.name, "Endgame") + assertEquals(movie.studio, "Marvel") + assertEquals(movie.rating, 1f) + } + + @Test + fun whenSerializeMap_thenSuccess() { + val map = mapOf(1 to "one", 2 to "two") + val serialized = mapper.writeValueAsString(map) + + val json = """{"1":"one","2":"two"}""" + assertEquals(serialized, json) + } + + @Test + fun whenDeserializeMap_thenSuccess() { + val json = """{"1":"one","2":"two"}""" + val aMap: Map = mapper.readValue(json) + + assertEquals(aMap[1], "one") + assertEquals(aMap[2], "two") + } + + @Test + fun whenSerializeList_thenSuccess() { + val movie1 = Movie("Endgame", "Marvel", 9.2f) + val movie2 = Movie("Shazam", "Warner Bros", 7.6f) + val movieList = listOf(movie1, movie2) + val serialized = mapper.writeValueAsString(movieList) + + val json = """[{"name":"Endgame","studio":"Marvel","rating":9.2},{"name":"Shazam","studio":"Warner Bros","rating":7.6}]""" + assertEquals(serialized, json) + } + + @Test + fun whenDeserializeList_thenSuccess() { + val json = """[{"name":"Endgame","studio":"Marvel","rating":9.2},{"name":"Shazam","studio":"Warner Bros","rating":7.6}]""" + val movieList: List = mapper.readValue(json) + + val movie1 = Movie("Endgame", "Marvel", 9.2f) + val movie2 = Movie("Shazam", "Warner Bros", 7.6f) + assertTrue(movieList.contains(movie1)) + assertTrue(movieList.contains(movie2)) + } + + @Test + fun whenSerializeBook_thenSuccess() { + val book = Book("Oliver Twist", "Charles Dickens") + val serialized = mapper.writeValueAsString(book) + + val json = """{"title":"Oliver Twist","author":"Charles Dickens"}""" + assertEquals(serialized, json) + } + + @Test + fun whenDeserializeBook_thenSuccess() { + val json = """{"title":"Oliver Twist","author":"Charles Dickens"}""" + val book: Book = mapper.readValue(json) + + assertEquals(book.title, "Oliver Twist") + assertEquals(book.authorName, "Charles Dickens") + } + + @Test + fun givenJsonInclude_whenSerializeBook_thenEmptyFieldExcluded() { + val book = Book("Oliver Twist", "Charles Dickens") + val serialized = mapper.writeValueAsString(book) + + val json = """{"title":"Oliver Twist","author":"Charles Dickens"}""" + assertEquals(serialized, json) + } + +} \ No newline at end of file diff --git a/kotlin-libraries/README.md b/kotlin-libraries/README.md index 5e2526e64e..94359193b6 100644 --- a/kotlin-libraries/README.md +++ b/kotlin-libraries/README.md @@ -10,3 +10,5 @@ - [Introduction to Arrow in Kotlin](https://www.baeldung.com/kotlin-arrow) - [Kotlin with Ktor](https://www.baeldung.com/kotlin-ktor) - [REST API With Kotlin and Kovert](https://www.baeldung.com/kotlin-kovert) +- [MockK: A Mocking Library for Kotlin](https://www.baeldung.com/kotlin-mockk) +- [Kotlin Immutable Collections](https://www.baeldung.com/kotlin-immutable-collections) \ No newline at end of file diff --git a/kotlin-libraries/pom.xml b/kotlin-libraries/pom.xml index 507e5820d4..3d2c7337b0 100644 --- a/kotlin-libraries/pom.xml +++ b/kotlin-libraries/pom.xml @@ -19,6 +19,14 @@ exposed https://dl.bintray.com/kotlin/exposed + + + false + + kotlinx + bintray + https://dl.bintray.com/kotlin/kotlinx + @@ -112,9 +120,56 @@ 3.3.0 pom + + + + junit + junit + ${junit.version} + test + + + + com.google.guava + guava + 27.1-jre + + + + org.jetbrains.kotlinx + kotlinx-collections-immutable + 0.1 + + + + + io.mockk + mockk + ${mockk.version} + test + + + net.bytebuddy + byte-buddy + 1.8.13 + compile + + + net.bytebuddy + byte-buddy-agent + 1.8.13 + compile + + + org.objenesis + objenesis + 2.6 + compile + + 4.12 1.5.0 4.1.0 3.0.4 @@ -125,6 +180,7 @@ 3.10.0 1.4.197 0.10.4 + 1.9.3 diff --git a/kotlin-libraries/src/test/kotlin/com/baeldung/kotlin/immutable/KotlinxImmutablesUnitTest.kt b/kotlin-libraries/src/test/kotlin/com/baeldung/kotlin/immutable/KotlinxImmutablesUnitTest.kt new file mode 100644 index 0000000000..971f2de4c2 --- /dev/null +++ b/kotlin-libraries/src/test/kotlin/com/baeldung/kotlin/immutable/KotlinxImmutablesUnitTest.kt @@ -0,0 +1,27 @@ +package com.baeldung.kotlin.immutable + +import junit.framework.Assert.assertEquals +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.immutableListOf +import org.junit.Rule +import org.junit.Test +import org.junit.rules.ExpectedException + +class KotlinxImmutablesUnitTest{ + + + @Rule + @JvmField + var ee : ExpectedException = ExpectedException.none() + + @Test + fun givenKICLList_whenAddTried_checkExceptionThrown(){ + + val list: ImmutableList = immutableListOf("I", "am", "immutable") + + list.add("My new item") + + assertEquals(listOf("I", "am", "immutable"), list) + + } +} \ No newline at end of file diff --git a/kotlin-libraries/src/test/kotlin/com/baeldung/kotlin/immutable/ReadOnlyUnitTest.kt b/kotlin-libraries/src/test/kotlin/com/baeldung/kotlin/immutable/ReadOnlyUnitTest.kt new file mode 100644 index 0000000000..62c4a4eb88 --- /dev/null +++ b/kotlin-libraries/src/test/kotlin/com/baeldung/kotlin/immutable/ReadOnlyUnitTest.kt @@ -0,0 +1,73 @@ +package com.baeldung.kotlin.immutable + +import com.google.common.collect.ImmutableList +import com.google.common.collect.ImmutableSet +import junit.framework.Assert.assertEquals +import org.junit.Rule +import org.junit.Test +import org.junit.rules.ExpectedException + +class ReadOnlyUnitTest{ + + @Test + fun givenReadOnlyList_whenCastToMutableList_checkNewElementsAdded(){ + + val list: List = listOf("This", "Is", "Totally", "Immutable") + + (list as MutableList)[2] = "Not" + + assertEquals(listOf("This", "Is", "Not", "Immutable"), list) + + } + + @Rule + @JvmField + var ee : ExpectedException = ExpectedException.none() + + @Test + fun givenImmutableList_whenAddTried_checkExceptionThrown(){ + + val list: List = ImmutableList.of("I", "am", "actually", "immutable") + + ee.expect(UnsupportedOperationException::class.java) + + (list as MutableList).add("Oops") + + } + + @Test + fun givenMutableList_whenCopiedAndAddTried_checkExceptionThrown(){ + + val mutableList : List = listOf("I", "Am", "Definitely", "Immutable") + + (mutableList as MutableList)[2] = "100% Not" + + assertEquals(listOf("I", "Am", "100% Not", "Immutable"), mutableList) + + val list: List = ImmutableList.copyOf(mutableList) + + ee.expect(UnsupportedOperationException::class.java) + + (list as MutableList)[2] = "Really?" + + } + + @Test + fun givenImmutableSetBuilder_whenAddTried_checkExceptionThrown(){ + + val mutableList : List = listOf("Hello", "Baeldung") + val set: ImmutableSet = ImmutableSet.builder() + .add("I","am","immutable") + .addAll(mutableList) + .build() + + assertEquals(setOf("Hello", "Baeldung", "I", "am", "immutable"), set) + + ee.expect(UnsupportedOperationException::class.java) + + (set as MutableSet).add("Oops") + + } + + +} \ No newline at end of file diff --git a/kotlin-libraries/src/test/kotlin/com/baeldung/mockk/AnnotationMockKUnitTest.kt b/kotlin-libraries/src/test/kotlin/com/baeldung/mockk/AnnotationMockKUnitTest.kt new file mode 100644 index 0000000000..56cd8b43eb --- /dev/null +++ b/kotlin-libraries/src/test/kotlin/com/baeldung/mockk/AnnotationMockKUnitTest.kt @@ -0,0 +1,44 @@ +package com.baeldung.mockk + +import io.mockk.MockKAnnotations +import io.mockk.every +import io.mockk.impl.annotations.InjectMockKs +import io.mockk.impl.annotations.MockK +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import kotlin.test.assertEquals + +class InjectTestService { + lateinit var service1: TestableService + lateinit var service2: TestableService + + fun invokeService1(): String { + return service1.getDataFromDb("Test Param") + } +} + +class AnnotationMockKUnitTest { + + @MockK + lateinit var service1: TestableService + + @MockK + lateinit var service2: TestableService + + @InjectMockKs + var objectUnderTest = InjectTestService() + + @BeforeEach + fun setUp() = MockKAnnotations.init(this) + + @Test + fun givenServiceMock_whenCallingMockedMethod_thenCorrectlyVerified() { + // given + every { service1.getDataFromDb("Test Param") } returns "No" + // when + val result = objectUnderTest.invokeService1() + // then + assertEquals("No", result) + } + +} \ No newline at end of file diff --git a/kotlin-libraries/src/test/kotlin/com/baeldung/mockk/BasicMockKUnitTest.kt b/kotlin-libraries/src/test/kotlin/com/baeldung/mockk/BasicMockKUnitTest.kt new file mode 100644 index 0000000000..df4c03be09 --- /dev/null +++ b/kotlin-libraries/src/test/kotlin/com/baeldung/mockk/BasicMockKUnitTest.kt @@ -0,0 +1,92 @@ +package com.baeldung.mockk + +import io.mockk.* +import org.junit.jupiter.api.Test +import kotlin.test.assertEquals + + +class BasicMockKUnitTest { + + @Test + fun givenServiceMock_whenCallingMockedMethod_thenCorrectlyVerified() { + // given + val service = mockk() + every { service.getDataFromDb("Expected Param") } returns "Expected Output" + // when + val result = service.getDataFromDb("Expected Param") + // then + verify { service.getDataFromDb("Expected Param") } + assertEquals("Expected Output", result) + } + + @Test + fun givenServiceSpy_whenMockingOnlyOneMethod_thenOtherMethodsShouldBehaveAsOriginalObject() { + // given + val service = spyk() + every { service.getDataFromDb(any()) } returns "Mocked Output" + // when checking mocked method + val firstResult = service.getDataFromDb("Any Param") + // then + assertEquals("Mocked Output", firstResult) + // when checking not mocked method + val secondResult = service.doSomethingElse("Any Param") + // then + assertEquals("I don't want to!", secondResult) + } + + @Test + fun givenRelaxedMock_whenCallingNotMockedMethod_thenReturnDefaultValue() { + // given + val service = mockk(relaxed = true) + // when + val result = service.getDataFromDb("Any Param") + // then + assertEquals("", result) + } + + @Test + fun givenObject_whenMockingIt_thenMockedMethodShouldReturnProperValue() { + // given + val service = TestableService() + mockkObject(service) + // when calling not mocked method + val firstResult = service.getDataFromDb("Any Param") + // then return real response + assertEquals("Value from DB", firstResult) + + // when calling mocked method + every { service.getDataFromDb(any()) } returns "Mocked Output" + val secondResult = service.getDataFromDb("Any Param") + // then return mocked response + assertEquals("Mocked Output", secondResult) + } + + @Test + fun givenMock_whenCapturingParamValue_thenProperValueShouldBeCaptured() { + // given + val service = mockk() + val slot = slot() + every { service.getDataFromDb(capture(slot)) } returns "Expected Output" + // when + service.getDataFromDb("Expected Param") + // then + assertEquals("Expected Param", slot.captured) + } + + @Test + fun givenMock_whenCapturingParamsValues_thenProperValuesShouldBeCaptured() { + // given + val service = mockk() + val list = mutableListOf() + every { service.getDataFromDb(capture(list)) } returns "Expected Output" + // when + service.getDataFromDb("Expected Param 1") + service.getDataFromDb("Expected Param 2") + // then + assertEquals(2, list.size) + assertEquals("Expected Param 1", list[0]) + assertEquals("Expected Param 2", list[1]) + } + + +} \ No newline at end of file diff --git a/kotlin-libraries/src/test/kotlin/com/baeldung/mockk/HierarchicalMockKUnitTest.kt b/kotlin-libraries/src/test/kotlin/com/baeldung/mockk/HierarchicalMockKUnitTest.kt new file mode 100644 index 0000000000..e9ef133663 --- /dev/null +++ b/kotlin-libraries/src/test/kotlin/com/baeldung/mockk/HierarchicalMockKUnitTest.kt @@ -0,0 +1,33 @@ +package com.baeldung.mockk + +import io.mockk.* +import org.junit.jupiter.api.Test +import kotlin.test.assertEquals + +class Foo { + lateinit var name: String + lateinit var bar: Bar +} + +class Bar { + lateinit var nickname: String +} + +class HierarchicalMockKUnitTest { + + @Test + fun givenHierarchicalClass_whenMockingIt_thenReturnProperValue() { + // given + val foo = mockk { + every { name } returns "Karol" + every { bar } returns mockk { + every { nickname } returns "Tomato" + } + } + // when + val result = foo.bar.nickname + // then + assertEquals("Tomato", result) + } + +} \ No newline at end of file diff --git a/kotlin-libraries/src/test/kotlin/com/baeldung/mockk/TestableService.kt b/kotlin-libraries/src/test/kotlin/com/baeldung/mockk/TestableService.kt new file mode 100644 index 0000000000..d6f57e5fb0 --- /dev/null +++ b/kotlin-libraries/src/test/kotlin/com/baeldung/mockk/TestableService.kt @@ -0,0 +1,12 @@ +package com.baeldung.mockk + +class TestableService { + fun getDataFromDb(testParameter: String): String { + // query database and return matching value + return "Value from DB" + } + + fun doSomethingElse(testParameter: String): String { + return "I don't want to!" + } +} \ No newline at end of file diff --git a/libraries-2/pom.xml b/libraries-2/pom.xml new file mode 100644 index 0000000000..965cb195bf --- /dev/null +++ b/libraries-2/pom.xml @@ -0,0 +1,55 @@ + + + + 4.0.0 + libraries2 + libraries2 + + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + + + + + jboss-public-repository-group + JBoss Public Repository Group + http://repository.jboss.org/nexus/content/groups/public/ + + true + never + + + true + daily + + + + + + + org.assertj + assertj-core + ${assertj.version} + + + io.github.classgraph + classgraph + ${classgraph.version} + + + org.jbpm + jbpm-test + ${jbpm.version} + + + + + 3.6.2 + 4.8.22 + 6.0.0.Final + + diff --git a/libraries-2/src/main/java/com/baeldung/jbpm/WorkflowProcessMain.java b/libraries-2/src/main/java/com/baeldung/jbpm/WorkflowProcessMain.java new file mode 100644 index 0000000000..8e54ff892e --- /dev/null +++ b/libraries-2/src/main/java/com/baeldung/jbpm/WorkflowProcessMain.java @@ -0,0 +1,19 @@ +package com.baeldung.jbpm; + +import org.kie.api.runtime.manager.Context; +import org.kie.internal.runtime.manager.context.EmptyContext; + +import com.baeldung.jbpm.engine.WorkflowEngine; +import com.baeldung.jbpm.engine.WorkflowEngineImpl; + +public class WorkflowProcessMain { + + public static void main(String[] args) { + WorkflowEngine workflowEngine = new WorkflowEngineImpl(); + String processId = "com.baeldung.bpmn.helloworld"; + String kbaseId = "kbase"; + String persistenceUnit = "org.jbpm.persistence.jpa"; + Context initialContext = EmptyContext.get(); + workflowEngine.runjBPMEngineForProcess(processId, initialContext, kbaseId, persistenceUnit); + } +} \ No newline at end of file diff --git a/libraries-2/src/main/java/com/baeldung/jbpm/engine/WorkflowEngine.java b/libraries-2/src/main/java/com/baeldung/jbpm/engine/WorkflowEngine.java new file mode 100644 index 0000000000..b47a4cc8c1 --- /dev/null +++ b/libraries-2/src/main/java/com/baeldung/jbpm/engine/WorkflowEngine.java @@ -0,0 +1,10 @@ +package com.baeldung.jbpm.engine; + +import org.kie.api.runtime.manager.Context; +import org.kie.api.runtime.process.ProcessInstance; + +public interface WorkflowEngine { + + public ProcessInstance runjBPMEngineForProcess(String processId, Context initialContext, String kbaseId, String persistenceUnit); + +} diff --git a/libraries-2/src/main/java/com/baeldung/jbpm/engine/WorkflowEngineImpl.java b/libraries-2/src/main/java/com/baeldung/jbpm/engine/WorkflowEngineImpl.java new file mode 100644 index 0000000000..7871241bef --- /dev/null +++ b/libraries-2/src/main/java/com/baeldung/jbpm/engine/WorkflowEngineImpl.java @@ -0,0 +1,66 @@ +package com.baeldung.jbpm.engine; + +import javax.persistence.EntityManagerFactory; +import javax.persistence.Persistence; + +import org.jbpm.test.JBPMHelper; +import org.kie.api.KieBase; +import org.kie.api.KieServices; +import org.kie.api.runtime.KieContainer; +import org.kie.api.runtime.KieSession; +import org.kie.api.runtime.manager.Context; +import org.kie.api.runtime.manager.RuntimeEngine; +import org.kie.api.runtime.manager.RuntimeEnvironment; +import org.kie.api.runtime.manager.RuntimeEnvironmentBuilder; +import org.kie.api.runtime.manager.RuntimeManager; +import org.kie.api.runtime.manager.RuntimeManagerFactory; +import org.kie.api.runtime.process.ProcessInstance; + +public class WorkflowEngineImpl implements WorkflowEngine { + + @Override + public ProcessInstance runjBPMEngineForProcess(String processId, Context initialContext, String kbaseId, String persistenceUnit) { + RuntimeManager manager = null; + RuntimeEngine engine = null; + ProcessInstance pInstance = null; + try { + KieBase kbase = getKieBase(kbaseId); + manager = createJBPMRuntimeManager(kbase, persistenceUnit); + engine = manager.getRuntimeEngine(initialContext); + pInstance = executeProcessInstance(processId, manager, initialContext, engine); + } catch (Exception ex) { + ex.printStackTrace(); + } finally { + if (manager != null && engine != null) + manager.disposeRuntimeEngine(engine); + System.exit(0); + } + return pInstance; + } + + private ProcessInstance executeProcessInstance(String processId, RuntimeManager manager, Context initialContext, RuntimeEngine engine) { + KieSession ksession = engine.getKieSession(); + ProcessInstance pInstance = ksession.startProcess(processId); + return pInstance; + } + + private KieBase getKieBase(String kbaseId) { + KieServices ks = KieServices.Factory.get(); + KieContainer kContainer = ks.getKieClasspathContainer(); + KieBase kbase = kContainer.getKieBase(kbaseId); + return kbase; + } + + private RuntimeManager createJBPMRuntimeManager(KieBase kbase, String persistenceUnit) { + JBPMHelper.startH2Server(); + JBPMHelper.setupDataSource(); + EntityManagerFactory emf = Persistence.createEntityManagerFactory(persistenceUnit); + RuntimeEnvironmentBuilder runtimeEnvironmentBuilder = RuntimeEnvironmentBuilder.Factory.get() + .newDefaultBuilder(); + RuntimeEnvironment runtimeEnvironment = runtimeEnvironmentBuilder.entityManagerFactory(emf) + .knowledgeBase(kbase) + .get(); + return RuntimeManagerFactory.Factory.get() + .newSingletonRuntimeManager(runtimeEnvironment); + } +} diff --git a/libraries-2/src/main/resources/META-INF/kmodule.xml b/libraries-2/src/main/resources/META-INF/kmodule.xml new file mode 100644 index 0000000000..1b9ce1ce71 --- /dev/null +++ b/libraries-2/src/main/resources/META-INF/kmodule.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/libraries-2/src/main/resources/com/baeldung/process/helloworld.bpmn b/libraries-2/src/main/resources/com/baeldung/process/helloworld.bpmn new file mode 100644 index 0000000000..30813b2057 --- /dev/null +++ b/libraries-2/src/main/resources/com/baeldung/process/helloworld.bpmn @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libraries-2/src/test/java/com/baeldung/classgraph/ClassGraphUnitTest.java b/libraries-2/src/test/java/com/baeldung/classgraph/ClassGraphUnitTest.java new file mode 100644 index 0000000000..3dc99e6a32 --- /dev/null +++ b/libraries-2/src/test/java/com/baeldung/classgraph/ClassGraphUnitTest.java @@ -0,0 +1,74 @@ +package com.baeldung.classgraph; + +import io.github.classgraph.*; +import org.junit.Test; + +import java.io.IOException; +import java.util.function.Consumer; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ClassGraphUnitTest { + + @Test + public void whenClassAnnotationFilterIsDefined_thenTargetClassesCanBeFound() { + doTest(result -> { + ClassInfoList classInfos = result.getClassesWithAnnotation(TestAnnotation.class.getName()); + assertThat(classInfos).extracting(ClassInfo::getName).contains(ClassWithAnnotation.class.getName()); + }); + } + + @Test + public void whenMethodAnnotationFilterIsDefined_thenTargetClassesCanBeFound() { + doTest(result -> { + ClassInfoList classInfos = result.getClassesWithMethodAnnotation(TestAnnotation.class.getName()); + assertThat(classInfos).extracting(ClassInfo::getName).contains(MethodWithAnnotation.class.getName()); + }); + } + + @Test + public void whenMethodAnnotationValueFilterIsDefined_thenTargetClassesCanBeFound() { + doTest(result -> { + ClassInfoList classInfos = result.getClassesWithMethodAnnotation(TestAnnotation.class.getName()); + ClassInfoList filteredClassInfos = classInfos.filter(classInfo -> { + return classInfo.getMethodInfo().stream().anyMatch(methodInfo -> { + AnnotationInfo annotationInfo = methodInfo.getAnnotationInfo(TestAnnotation.class.getName()); + if (annotationInfo == null) { + return false; + } + + return "web".equals(annotationInfo.getParameterValues().getValue("value")); + }); + }); + assertThat(filteredClassInfos) + .extracting(ClassInfo::getName) + .contains(MethodWithAnnotationParameterWeb.class.getName()); + }); + } + + @Test + public void whenFieldAnnotationFilterIsDefined_thenTargetClassesCanBeFound() { + doTest(result -> { + ClassInfoList classInfos = result.getClassesWithFieldAnnotation(TestAnnotation.class.getName()); + assertThat(classInfos).extracting(ClassInfo::getName).contains(FieldWithAnnotation.class.getName()); + }); + } + + @Test + public void whenResourceIsUsed_thenItCanBeFoundAndLoaded() throws IOException { + try (ScanResult result = new ClassGraph().whitelistPaths("classgraph").scan()) { + ResourceList resources = result.getResourcesWithExtension("config"); + assertThat(resources).extracting(Resource::getPath).containsOnly("classgraph/my.config"); + assertThat(resources.get(0).getContentAsString()).isEqualTo("my data"); + } + } + + private void doTest(Consumer checker) { + try (ScanResult result = new ClassGraph().enableAllInfo() + .whitelistPackages(getClass().getPackage().getName()) + .scan()) + { + checker.accept(result); + } + } +} \ No newline at end of file diff --git a/libraries-2/src/test/java/com/baeldung/classgraph/ClassWithAnnotation.java b/libraries-2/src/test/java/com/baeldung/classgraph/ClassWithAnnotation.java new file mode 100644 index 0000000000..fe476769a6 --- /dev/null +++ b/libraries-2/src/test/java/com/baeldung/classgraph/ClassWithAnnotation.java @@ -0,0 +1,5 @@ +package com.baeldung.classgraph; + +@TestAnnotation +public class ClassWithAnnotation { +} \ No newline at end of file diff --git a/libraries-2/src/test/java/com/baeldung/classgraph/FieldWithAnnotation.java b/libraries-2/src/test/java/com/baeldung/classgraph/FieldWithAnnotation.java new file mode 100644 index 0000000000..f72a7621f9 --- /dev/null +++ b/libraries-2/src/test/java/com/baeldung/classgraph/FieldWithAnnotation.java @@ -0,0 +1,7 @@ +package com.baeldung.classgraph; + +public class FieldWithAnnotation { + + @TestAnnotation + private String s; +} \ No newline at end of file diff --git a/libraries-2/src/test/java/com/baeldung/classgraph/MethodWithAnnotation.java b/libraries-2/src/test/java/com/baeldung/classgraph/MethodWithAnnotation.java new file mode 100644 index 0000000000..29a59c09ea --- /dev/null +++ b/libraries-2/src/test/java/com/baeldung/classgraph/MethodWithAnnotation.java @@ -0,0 +1,8 @@ +package com.baeldung.classgraph; + +public class MethodWithAnnotation { + + @TestAnnotation + public void service() { + } +} \ No newline at end of file diff --git a/libraries-2/src/test/java/com/baeldung/classgraph/MethodWithAnnotationParameterDao.java b/libraries-2/src/test/java/com/baeldung/classgraph/MethodWithAnnotationParameterDao.java new file mode 100644 index 0000000000..f01c2743eb --- /dev/null +++ b/libraries-2/src/test/java/com/baeldung/classgraph/MethodWithAnnotationParameterDao.java @@ -0,0 +1,8 @@ +package com.baeldung.classgraph; + +public class MethodWithAnnotationParameterDao { + + @TestAnnotation("dao") + public void service() { + } +} \ No newline at end of file diff --git a/libraries-2/src/test/java/com/baeldung/classgraph/MethodWithAnnotationParameterWeb.java b/libraries-2/src/test/java/com/baeldung/classgraph/MethodWithAnnotationParameterWeb.java new file mode 100644 index 0000000000..bf01f7d23c --- /dev/null +++ b/libraries-2/src/test/java/com/baeldung/classgraph/MethodWithAnnotationParameterWeb.java @@ -0,0 +1,8 @@ +package com.baeldung.classgraph; + +public class MethodWithAnnotationParameterWeb { + + @TestAnnotation("web") + public void service() { + } +} \ No newline at end of file diff --git a/libraries-2/src/test/java/com/baeldung/classgraph/TestAnnotation.java b/libraries-2/src/test/java/com/baeldung/classgraph/TestAnnotation.java new file mode 100644 index 0000000000..e3f5df92ed --- /dev/null +++ b/libraries-2/src/test/java/com/baeldung/classgraph/TestAnnotation.java @@ -0,0 +1,14 @@ +package com.baeldung.classgraph; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.*; + +@Target({TYPE, METHOD, FIELD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface TestAnnotation { + + String value() default ""; +} \ No newline at end of file diff --git a/libraries-2/src/test/java/com/baeldung/jbpm/WorkflowEngineIntegrationTest.java b/libraries-2/src/test/java/com/baeldung/jbpm/WorkflowEngineIntegrationTest.java new file mode 100644 index 0000000000..ded46d7639 --- /dev/null +++ b/libraries-2/src/test/java/com/baeldung/jbpm/WorkflowEngineIntegrationTest.java @@ -0,0 +1,52 @@ +package com.baeldung.jbpm; + +import org.jbpm.test.JbpmJUnitBaseTestCase; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.kie.api.runtime.KieSession; +import org.kie.api.runtime.manager.RuntimeEngine; +import org.kie.api.runtime.manager.RuntimeManager; +import org.kie.api.runtime.process.ProcessInstance; +import org.kie.internal.runtime.manager.context.ProcessInstanceIdContext; + +public class WorkflowEngineIntegrationTest extends JbpmJUnitBaseTestCase { + + private String[] triggeredNodesArray = { "Start", "HelloWorld", "End" }; + private RuntimeManager manager = null; + private RuntimeEngine runtimeEngine = null; + private KieSession ksession = null; + private ProcessInstance processInstance = null; + + @Before + public void setup() { + manager = createRuntimeManager(Strategy.SINGLETON, "manager", "com/baeldung/process/helloworld.bpmn"); + runtimeEngine = getRuntimeEngine(ProcessInstanceIdContext.get()); + ksession = runtimeEngine.getKieSession(); + processInstance = ksession.startProcess("com.baeldung.bpmn.helloworld"); + } + + @After + public void cleanup() { + manager.disposeRuntimeEngine(runtimeEngine); + } + + @Test + public void givenProcessInstance_whenExecutionCompleted_thenVerifyNodesExecutionOrder() { + assertNodeTriggered(processInstance.getId(), triggeredNodesArray); + } + + @Test + public void givenProcessInstance_whenExecutionCompleted_thenVerifyKnowledgeSessionId() { + int ksessionID = ksession.getId(); + runtimeEngine = getRuntimeEngine(ProcessInstanceIdContext.get(processInstance.getId())); + ksession = runtimeEngine.getKieSession(); + assertEquals(ksessionID, ksession.getId()); + } + + @Test + public void givenProcessInstance_whenExecutionCompleted_thenVerifyProcessInstanceStatus() { + assertProcessInstanceCompleted(processInstance.getId(), ksession); + assertTrue("ProcessInstance completed with status 2", processInstance.getState() == 2); + } +} diff --git a/libraries-2/src/test/resources/classgraph/my.config b/libraries-2/src/test/resources/classgraph/my.config new file mode 100644 index 0000000000..b99df573f6 --- /dev/null +++ b/libraries-2/src/test/resources/classgraph/my.config @@ -0,0 +1 @@ +my data \ No newline at end of file diff --git a/libraries-apache-commons/src/main/java/com/baeldung/commons/beanutils/CourseService.java b/libraries-apache-commons/src/main/java/com/baeldung/commons/beanutils/CourseService.java index 538fa3accb..2c7644fd64 100644 --- a/libraries-apache-commons/src/main/java/com/baeldung/commons/beanutils/CourseService.java +++ b/libraries-apache-commons/src/main/java/com/baeldung/commons/beanutils/CourseService.java @@ -29,6 +29,6 @@ public class CourseService { } public static void copyProperties(Course course, CourseEntity courseEntity) throws IllegalAccessException, InvocationTargetException { - BeanUtils.copyProperties(course, courseEntity); + BeanUtils.copyProperties(courseEntity, course); } } diff --git a/libraries-apache-commons/src/test/java/com/baeldung/commons/beanutils/CourseServiceUnitTest.java b/libraries-apache-commons/src/test/java/com/baeldung/commons/beanutils/CourseServiceUnitTest.java index 833d91b2c4..224ee8404c 100644 --- a/libraries-apache-commons/src/test/java/com/baeldung/commons/beanutils/CourseServiceUnitTest.java +++ b/libraries-apache-commons/src/test/java/com/baeldung/commons/beanutils/CourseServiceUnitTest.java @@ -44,6 +44,8 @@ public class CourseServiceUnitTest { CourseEntity courseEntity = new CourseEntity(); CourseService.copyProperties(course, courseEntity); + Assert.assertNotNull(course.getName()); + Assert.assertNotNull(courseEntity.getName()); Assert.assertEquals(course.getName(), courseEntity.getName()); Assert.assertEquals(course.getCodes(), courseEntity.getCodes()); Assert.assertNull(courseEntity.getStudent("ST-1")); diff --git a/libraries-primitive/pom.xml b/libraries-primitive/pom.xml new file mode 100644 index 0000000000..9bb58470b2 --- /dev/null +++ b/libraries-primitive/pom.xml @@ -0,0 +1,39 @@ + + + 4.0.0 + + com.baeldung + libraries-primitive + 1.0-SNAPSHOT + + + + + it.unimi.dsi + fastutil + 8.2.2 + + + + junit + junit + 4.12 + test + + + + org.openjdk.jmh + jmh-core + 1.19 + test + + + org.openjdk.jmh + jmh-generator-annprocess + 1.19 + test + + + diff --git a/libraries-primitive/src/test/java/com/baeldung/BigArraysUnitTest.java b/libraries-primitive/src/test/java/com/baeldung/BigArraysUnitTest.java new file mode 100644 index 0000000000..a794d1a2f6 --- /dev/null +++ b/libraries-primitive/src/test/java/com/baeldung/BigArraysUnitTest.java @@ -0,0 +1,23 @@ +package com.baeldung; + +import it.unimi.dsi.fastutil.ints.IntBigArrays; +import org.junit.Test; + +import static junit.framework.Assert.assertEquals; + +public class BigArraysUnitTest { + + @Test + public void givenValidAray_whenWrapped_checkAccessFromIntBigArraysMethodsCorrect() { + int[] oneDArray = new int[] { 2, 1, 5, 2, 1, 7 }; + int[][] twoDArray = IntBigArrays.wrap(oneDArray.clone()); + + int firstIndex = IntBigArrays.get(twoDArray, 0); + int lastIndex = IntBigArrays.get(twoDArray, IntBigArrays.length(twoDArray)-1); + + assertEquals(2, firstIndex); + assertEquals(7, lastIndex); + + } + +} diff --git a/libraries-primitive/src/test/java/com/baeldung/FastUtilTypeSpecificBenchmarkUnitTest.java b/libraries-primitive/src/test/java/com/baeldung/FastUtilTypeSpecificBenchmarkUnitTest.java new file mode 100644 index 0000000000..2c77989fe5 --- /dev/null +++ b/libraries-primitive/src/test/java/com/baeldung/FastUtilTypeSpecificBenchmarkUnitTest.java @@ -0,0 +1,58 @@ +package com.baeldung; + +import it.unimi.dsi.fastutil.ints.IntOpenHashSet; +import it.unimi.dsi.fastutil.ints.IntSet; +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.Blackhole; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.RunnerException; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +import java.util.*; +import java.util.concurrent.TimeUnit; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.MICROSECONDS) +@State(Scope.Benchmark) +public class FastUtilTypeSpecificBenchmarkUnitTest { + + @Param({"100", "1000", "10000", "100000"}) + public int setSize; + + @Benchmark + public IntSet givenFastUtilsIntSetWithInitialSizeSet_whenPopulated_checkTimeTaken() { + IntSet intSet = new IntOpenHashSet(setSize); + for(int i = 0; i < setSize; i++){ + intSet.add(i); + } + return intSet; + } + + + @Benchmark + public Set givenCollectionsHashSetWithInitialSizeSet_whenPopulated_checkTimeTaken() { + Set intSet = new HashSet(setSize); + for(int i = 0; i < setSize; i++){ + intSet.add(i); + } + return intSet; + } + + public static void main(String... args) throws RunnerException { + Options opts = new OptionsBuilder() + .include(".*") + .warmupIterations(1) + .measurementIterations(2) + .jvmArgs("-Xms2g", "-Xmx2g") + .shouldDoGC(true) + .forks(1) + .build(); + + new Runner(opts).run(); + } + + + + +} diff --git a/libraries-primitive/src/test/java/com/baeldung/FastUtilTypeSpecificUnitTest.java b/libraries-primitive/src/test/java/com/baeldung/FastUtilTypeSpecificUnitTest.java new file mode 100644 index 0000000000..61295cc6f1 --- /dev/null +++ b/libraries-primitive/src/test/java/com/baeldung/FastUtilTypeSpecificUnitTest.java @@ -0,0 +1,20 @@ +package com.baeldung; + +import it.unimi.dsi.fastutil.doubles.Double2DoubleMap; +import it.unimi.dsi.fastutil.doubles.Double2DoubleOpenHashMap; +import org.junit.Test; + +import static junit.framework.Assert.assertEquals; + + +public class FastUtilTypeSpecificUnitTest { + + @Test + public void givenValidDouble2DoubleMap_whenContentsQueried_checkCorrect(){ + Double2DoubleMap d2dMap = new Double2DoubleOpenHashMap(); + d2dMap.put(2.0, 5.5); + d2dMap.put(3.0, 6.6); + assertEquals(5.5, d2dMap.get(2.0)); + } + +} diff --git a/libraries-security/README.md b/libraries-security/README.md index 6923e0474e..b9bbf11cdf 100644 --- a/libraries-security/README.md +++ b/libraries-security/README.md @@ -2,3 +2,4 @@ - [Guide to ScribeJava](https://www.baeldung.com/scribejava) - [Guide to Passay](https://www.baeldung.com/java-passay) +- [Guide to Google Tink](https://www.baeldung.com/google-tink) diff --git a/libraries-security/pom.xml b/libraries-security/pom.xml index 9f125361ba..17d57fe203 100644 --- a/libraries-security/pom.xml +++ b/libraries-security/pom.xml @@ -32,6 +32,12 @@ ${scribejava.version} + + com.google.crypto.tink + tink + ${tink.version} + + junit junit @@ -55,6 +61,7 @@ 5.6.0 2.3.3.RELEASE 1.3.1 + 1.2.2 1.2.2 diff --git a/libraries-security/src/test/java/com/baeldung/tink/TinkUnitTest.java b/libraries-security/src/test/java/com/baeldung/tink/TinkUnitTest.java new file mode 100644 index 0000000000..b98c698016 --- /dev/null +++ b/libraries-security/src/test/java/com/baeldung/tink/TinkUnitTest.java @@ -0,0 +1,101 @@ +package com.baeldung.tink; + +import com.google.crypto.tink.*; +import com.google.crypto.tink.aead.AeadConfig; +import com.google.crypto.tink.aead.AeadFactory; +import com.google.crypto.tink.aead.AeadKeyTemplates; +import com.google.crypto.tink.config.TinkConfig; +import com.google.crypto.tink.hybrid.HybridDecryptFactory; +import com.google.crypto.tink.hybrid.HybridEncryptFactory; +import com.google.crypto.tink.hybrid.HybridKeyTemplates; +import com.google.crypto.tink.mac.MacFactory; +import com.google.crypto.tink.mac.MacKeyTemplates; +import com.google.crypto.tink.signature.PublicKeySignFactory; +import com.google.crypto.tink.signature.PublicKeyVerifyFactory; +import com.google.crypto.tink.signature.SignatureKeyTemplates; +import org.junit.Assert; +import org.junit.Test; + +import java.security.GeneralSecurityException; + +public class TinkUnitTest { + + private static final String PLAINTEXT = "BAELDUNG"; + private static final String DATA = "TINK"; + + @Test + public void givenPlaintext_whenEncryptWithAead_thenPlaintextIsEncrypted() throws GeneralSecurityException { + + AeadConfig.register(); + + KeysetHandle keysetHandle = KeysetHandle.generateNew( + AeadKeyTemplates.AES256_GCM); + + Aead aead = AeadFactory.getPrimitive(keysetHandle); + + byte[] ciphertext = aead.encrypt(PLAINTEXT.getBytes(), + DATA.getBytes()); + + Assert.assertNotEquals(PLAINTEXT, new String(ciphertext)); + } + + @Test + public void givenData_whenComputeMAC_thenVerifyMAC() throws GeneralSecurityException { + + TinkConfig.register(); + + KeysetHandle keysetHandle = KeysetHandle.generateNew( + MacKeyTemplates.HMAC_SHA256_128BITTAG); + + Mac mac = MacFactory.getPrimitive(keysetHandle); + + byte[] tag = mac.computeMac(DATA.getBytes()); + + mac.verifyMac(tag, DATA.getBytes()); + } + + @Test + public void givenData_whenSignData_thenVerifySignature() throws GeneralSecurityException { + + TinkConfig.register(); + + KeysetHandle privateKeysetHandle = KeysetHandle.generateNew( + SignatureKeyTemplates.ECDSA_P256); + + PublicKeySign signer = PublicKeySignFactory.getPrimitive(privateKeysetHandle); + + byte[] signature = signer.sign(DATA.getBytes()); + + KeysetHandle publicKeysetHandle = + privateKeysetHandle.getPublicKeysetHandle(); + + PublicKeyVerify verifier = PublicKeyVerifyFactory.getPrimitive(publicKeysetHandle); + + verifier.verify(signature, DATA.getBytes()); + } + + @Test + public void givenPlaintext_whenEncryptWithHybridEncryption_thenVerifyDecryptedIsEqual() throws GeneralSecurityException { + + TinkConfig.register(); + + KeysetHandle privateKeysetHandle = KeysetHandle.generateNew( + HybridKeyTemplates.ECIES_P256_HKDF_HMAC_SHA256_AES128_CTR_HMAC_SHA256); + + KeysetHandle publicKeysetHandle = privateKeysetHandle.getPublicKeysetHandle(); + + HybridEncrypt hybridEncrypt = HybridEncryptFactory.getPrimitive(publicKeysetHandle); + + HybridDecrypt hybridDecrypt = HybridDecryptFactory.getPrimitive(privateKeysetHandle); + + String contextInfo = "Tink"; + + byte[] ciphertext = hybridEncrypt.encrypt(PLAINTEXT.getBytes(), contextInfo.getBytes()); + + byte[] plaintextDecrypted = hybridDecrypt.decrypt(ciphertext, contextInfo.getBytes()); + + Assert.assertEquals(PLAINTEXT,new String(plaintextDecrypted)); + } +} + + diff --git a/libraries-server/README.md b/libraries-server/README.md index 75c12fd61a..dc6bcd0716 100644 --- a/libraries-server/README.md +++ b/libraries-server/README.md @@ -3,7 +3,7 @@ - [Embedded Jetty Server in Java](http://www.baeldung.com/jetty-embedded) - [Introduction to Netty](http://www.baeldung.com/netty) - [Exceptions in Netty](http://www.baeldung.com/netty-exception-handling) -- [Programatically Create, Configure, and Run a Tomcat Server](http://www.baeldung.com/tomcat-programmatic-setup) +- [Programmatically Create, Configure and Run a Tomcat Server](http://www.baeldung.com/tomcat-programmatic-setup) - [Creating and Configuring Jetty 9 Server in Java](http://www.baeldung.com/jetty-java-programmatic) - [Testing Netty with EmbeddedChannel](http://www.baeldung.com/testing-netty-embedded-channel) - [MQTT Client in Java](https://www.baeldung.com/java-mqtt-client) diff --git a/libraries/README.md b/libraries/README.md index 57f22631f1..f6a39daef1 100644 --- a/libraries/README.md +++ b/libraries/README.md @@ -6,7 +6,7 @@ - [Introduction to Apache Flink with Java](http://www.baeldung.com/apache-flink) - [Introduction to JSONassert](http://www.baeldung.com/jsonassert) - [Intro to JaVers](http://www.baeldung.com/javers) -- [Intro to Serenity BDD](http://www.baeldung.com/serenity-bdd) +- [Introduction to Serenity BDD](http://www.baeldung.com/serenity-bdd) - [Merging Streams in Java](http://www.baeldung.com/java-merge-streams) - [Serenity BDD and Screenplay](http://www.baeldung.com/serenity-screenplay) - [Introduction to Quartz](http://www.baeldung.com/quartz) @@ -14,14 +14,14 @@ - [Software Transactional Memory in Java Using Multiverse](http://www.baeldung.com/java-multiverse-stm) - [Serenity BDD with Spring and JBehave](http://www.baeldung.com/serenity-spring-jbehave) - [Locality-Sensitive Hashing in Java Using Java-LSH](http://www.baeldung.com/locality-sensitive-hashing) -- [Introduction to Awaitility](http://www.baeldung.com/awaitlity-testing) +- [Introduction to Awaitlity](http://www.baeldung.com/awaitlity-testing) - [Guide to the HyperLogLog Algorithm](http://www.baeldung.com/java-hyperloglog) - [Introduction to Neuroph](http://www.baeldung.com/neuroph) - [Quick Guide to RSS with Rome](http://www.baeldung.com/rome-rss) - [Introduction to PCollections](http://www.baeldung.com/java-pcollections) - [Introduction to Hoverfly in Java](http://www.baeldung.com/hoverfly) - [Introduction to Eclipse Collections](http://www.baeldung.com/eclipse-collections) -- [DistinctBy in Java Stream API](http://www.baeldung.com/java-streams-distinct-by) +- [DistinctBy in the Java Stream API](http://www.baeldung.com/java-streams-distinct-by) - [Introduction to NoException](http://www.baeldung.com/no-exception) - [Introduction to Conflict-Free Replicated Data Types](http://www.baeldung.com/java-conflict-free-replicated-data-types) - [Introduction to javax.measure](http://www.baeldung.com/javax-measure) @@ -36,7 +36,7 @@ - [Introduction To Docx4J](http://www.baeldung.com/docx4j) - [Introduction to StreamEx](http://www.baeldung.com/streamex) - [Introduction to BouncyCastle with Java](http://www.baeldung.com/java-bouncy-castle) -- [Guide to google-http-client](http://www.baeldung.com/google-http-client) +- [A Guide to Google-Http-Client](http://www.baeldung.com/google-http-client) - [Interact with Google Sheets from Java](http://www.baeldung.com/google-sheets-java-client) - [A Docker Guide for Java](http://www.baeldung.com/docker-java-api) - [Introduction To OpenCSV](http://www.baeldung.com/opencsv) diff --git a/logging-modules/README.md b/logging-modules/README.md index 0f12d7eb22..17405847b1 100644 --- a/logging-modules/README.md +++ b/logging-modules/README.md @@ -4,5 +4,4 @@ ### Relevant Articles: - [Creating a Custom Logback Appender](http://www.baeldung.com/custom-logback-appender) -- [Get Log Output in JSON Format](http://www.baeldung.com/java-log-json-output) - [A Guide To Logback](http://www.baeldung.com/logback) diff --git a/logging-modules/log4j/README.md b/logging-modules/log4j/README.md index 9f4184ccba..a7a7ea9643 100644 --- a/logging-modules/log4j/README.md +++ b/logging-modules/log4j/README.md @@ -1,7 +1,5 @@ ### Relevant Articles: - [Introduction to Java Logging](http://www.baeldung.com/java-logging-intro) - [Introduction to SLF4J](http://www.baeldung.com/slf4j-with-log4j2-logback) -- [Generate equals() and hashCode() with Eclipse](http://www.baeldung.com/java-eclipse-equals-and-hashcode) -- [Introduction to SLF4J](http://www.baeldung.com/slf4j-with-log4j2-logback) - [A Guide to Rolling File Appenders](http://www.baeldung.com/java-logging-rolling-file-appenders) - [Logging Exceptions Using SLF4J](https://www.baeldung.com/slf4j-log-exceptions) diff --git a/logging-modules/log4j2/README.md b/logging-modules/log4j2/README.md index 2cf6f9768f..dd326bc7a1 100644 --- a/logging-modules/log4j2/README.md +++ b/logging-modules/log4j2/README.md @@ -4,3 +4,4 @@ - [Log4j 2 and Lambda Expressions](http://www.baeldung.com/log4j-2-lazy-logging) - [Programmatic Configuration with Log4j 2](http://www.baeldung.com/log4j2-programmatic-config) - [Creating a Custom Log4j2 Appender](https://www.baeldung.com/log4j2-custom-appender) +- [Get Log Output in JSON](http://www.baeldung.com/java-log-json-output) diff --git a/logging-modules/logback/README.md b/logging-modules/logback/README.md index e69de29bb2..df55492b69 100644 --- a/logging-modules/logback/README.md +++ b/logging-modules/logback/README.md @@ -0,0 +1,3 @@ +### Relevant Articles: + +- [Get Log Output in JSON](https://www.baeldung.com/java-log-json-output) diff --git a/logging-modules/logback/pom.xml b/logging-modules/logback/pom.xml index 845424af0c..41a28ffd17 100644 --- a/logging-modules/logback/pom.xml +++ b/logging-modules/logback/pom.xml @@ -37,12 +37,29 @@ jackson-databind ${jackson.version} + + org.docx4j + docx4j + ${docx4j.version} + + + org.slf4j + slf4j-log4j12 + + + log4j + log4j + + + + 1.2.3 0.1.5 2.9.7 + 3.3.5 diff --git a/lombok/README.md b/lombok/README.md index e3d08d4e26..4ff7ca7921 100644 --- a/lombok/README.md +++ b/lombok/README.md @@ -6,4 +6,5 @@ - [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) +- [Using the @Singular Annotation with Lombok Builders](https://www.baeldung.com/lombok-builder-singular) diff --git a/lombok/src/main/java/com/baeldung/lombok/builder/singular/Person.java b/lombok/src/main/java/com/baeldung/lombok/builder/singular/Person.java new file mode 100644 index 0000000000..d7d95feb66 --- /dev/null +++ b/lombok/src/main/java/com/baeldung/lombok/builder/singular/Person.java @@ -0,0 +1,25 @@ +package com.baeldung.lombok.builder.singular; + +import lombok.Builder; +import lombok.Getter; +import lombok.Singular; + +import java.time.LocalDate; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Set; + +@Getter +@Builder +public class Person { + + private final String givenName; + private final String additionalName; + private final String familyName; + + private final List tags; + @Singular private final List interests; + @Singular private final Set skills; + @Singular private final Map awards; +} diff --git a/lombok/src/main/java/com/baeldung/lombok/builder/singular/Sea.java b/lombok/src/main/java/com/baeldung/lombok/builder/singular/Sea.java new file mode 100644 index 0000000000..8cf38e5f1a --- /dev/null +++ b/lombok/src/main/java/com/baeldung/lombok/builder/singular/Sea.java @@ -0,0 +1,14 @@ +package com.baeldung.lombok.builder.singular; + +import java.util.List; +import lombok.Builder; +import lombok.Getter; +import lombok.Singular; + +@Getter +@Builder +public class Sea { + + @Singular private final List grasses; + @Singular("oneFish") private final List fish; +} diff --git a/lombok/src/test/java/com/baeldung/lombok/builder/singular/BuilderWithSingularSupportForCollectionsUnitTest.java b/lombok/src/test/java/com/baeldung/lombok/builder/singular/BuilderWithSingularSupportForCollectionsUnitTest.java new file mode 100644 index 0000000000..41d5b19df7 --- /dev/null +++ b/lombok/src/test/java/com/baeldung/lombok/builder/singular/BuilderWithSingularSupportForCollectionsUnitTest.java @@ -0,0 +1,192 @@ +package com.baeldung.lombok.builder.singular; + +import org.junit.Test; + +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; + +public class BuilderWithSingularSupportForCollectionsUnitTest { + + @Test + public void canAddMultipleElementsAsNewCollection() throws Exception { + Person person = Person.builder() + .givenName("Aaron") + .additionalName("A") + .familyName("Aardvark") + .tags(Arrays.asList("fictional", "incidental")) + .build(); + + assertThat(person.getTags(), containsInAnyOrder("fictional", "incidental")); + } + + @Test + public void canUpdateCollectionAfterBuildIfMutableCollectionPassedToBuilder() throws Exception { + + List tags = new ArrayList(); + tags.add("fictional"); + tags.add("incidental"); + Person person = Person.builder() + .givenName("Aaron") + .additionalName("A") + .familyName("Aardvark") + .tags(tags) + .build(); + person.getTags() + .clear(); + person.getTags() + .add("non-fictional"); + person.getTags() + .add("important"); + + assertThat(person.getTags(), containsInAnyOrder("non-fictional", "important")); + } + + @Test(expected = UnsupportedOperationException.class) + public void cannotUpdateCollectionAfterBuildIfImmutableCollectionPassedToBuilder() throws Exception { + List tags = Arrays.asList("fictional", "incidental"); + Person person = Person.builder() + .givenName("Aaron") + .additionalName("A") + .familyName("Aardvark") + .tags(tags) + .build(); + person.getTags() + .clear(); + } + + @Test + public void canAssignToSingularAnnotatedCollectionOneByOne() throws Exception { + + Person person = Person.builder() + .givenName("Aaron") + .additionalName("A") + .familyName("Aardvark") + .interest("history") + .interest("sport") + .build(); + + assertThat(person.getInterests(), containsInAnyOrder("sport", "history")); + } + + @Test(expected = UnsupportedOperationException.class) + public void singularAnnotatedBuilderCreatesImmutableCollection() throws Exception { + + Person person = Person.builder() + .givenName("Aaron") + .additionalName("A") + .familyName("Aardvark") + .interest("history") + .interest("sport") + .build(); + person.getInterests() + .clear(); + } + + @Test + public void unpopulatedListsCreatedAsNullIfNotSingularButEmptyArrayIfSingular() throws Exception { + + Person person = Person.builder() + .givenName("Aaron") + .additionalName("A") + .familyName("Aardvark") + .build(); + assertThat(person.getInterests(), hasSize(0)); + assertThat(person.getSkills(), hasSize(0)); + assertThat(person.getAwards() + .keySet(), hasSize(0)); + assertThat(person.getTags(), is(nullValue())); + } + + @Test + public void singularSupportsSetsToo() throws Exception { + + Person person = Person.builder() + .givenName("Aaron") + .additionalName("A") + .familyName("Aardvark") + .skill("singing") + .skill("dancing") + .build(); + assertThat(person.getSkills(), contains("singing", "dancing")); + } + + @Test + public void singularSetsAreLenientWithDuplicates() throws Exception { + + Person person = Person.builder() + .givenName("Aaron") + .additionalName("A") + .familyName("Aardvark") + .interest("singing") + .interest("singing") + .skill("singing") + .skill("singing") + .build(); + assertThat(person.getInterests(), contains("singing", "singing")); + assertThat(person.getSkills(), contains("singing")); + } + + @Test + public void singularSupportsMapsToo() throws Exception { + + Person person = Person.builder() + .givenName("Aaron") + .additionalName("A") + .familyName("Aardvark") + .award("Singer of the Year", LocalDate.now() + .minusYears(5)) + .award("Best Dancer", LocalDate.now() + .minusYears(2)) + .build(); + assertThat(person.getAwards() + .keySet(), contains("Singer of the Year", "Best Dancer")); + assertThat(person.getAwards() + .get("Best Dancer"), + is(LocalDate.now() + .minusYears(2))); + } + + @Test + public void singularIsLenientWithMapKeys() throws Exception { + + Person person = Person.builder() + .givenName("Aaron") + .additionalName("A") + .familyName("Aardvark") + .award("Best Dancer", LocalDate.now() + .minusYears(5)) + .award("Best Dancer", LocalDate.now() + .minusYears(4)) + .award("Best Dancer", LocalDate.now() + .minusYears(3)) + .award("Best Dancer", LocalDate.now() + .minusYears(2)) + .award("Best Dancer", LocalDate.now() + .minusYears(1)) + .build(); + assertThat(person.getAwards() + .keySet(), hasSize(1)); + assertThat(person.getAwards() + .get("Best Dancer"), + is(LocalDate.now() + .minusYears(1))); + } + + @Test + public void wordsWithNonStandardPlurals() throws Exception { + Sea sea = Sea.builder() + .grass("Dulse") + .grass("Kelp") + .oneFish("Cod") + .oneFish("Mackerel") + .build(); + assertThat(sea.getGrasses(), contains("Dulse", "Kelp")); + assertThat(sea.getFish(), contains("Cod", "Mackerel")); + } + +} diff --git a/maven-java-11/multimodule-maven-project/daomodule/pom.xml b/maven-java-11/multimodule-maven-project/daomodule/pom.xml new file mode 100644 index 0000000000..de9be656d4 --- /dev/null +++ b/maven-java-11/multimodule-maven-project/daomodule/pom.xml @@ -0,0 +1,14 @@ + + + 4.0.0 + + com.baeldung.multimodule-maven-project + multimodule-maven-project + 1.0 + + com.baeldung.daomodule + daomodule + jar + 1.0 + daomodule + diff --git a/maven-java-11/multimodule-maven-project/daomodule/src/main/java/com/baeldung/dao/Dao.java b/maven-java-11/multimodule-maven-project/daomodule/src/main/java/com/baeldung/dao/Dao.java new file mode 100644 index 0000000000..f86ae8abb3 --- /dev/null +++ b/maven-java-11/multimodule-maven-project/daomodule/src/main/java/com/baeldung/dao/Dao.java @@ -0,0 +1,12 @@ +package com.baeldung.dao; + +import java.util.List; +import java.util.Optional; + +public interface Dao { + + Optional findById(int id); + + List findAll(); + +} diff --git a/maven-java-11/multimodule-maven-project/daomodule/src/main/java/module-info.java b/maven-java-11/multimodule-maven-project/daomodule/src/main/java/module-info.java new file mode 100644 index 0000000000..072d7ad007 --- /dev/null +++ b/maven-java-11/multimodule-maven-project/daomodule/src/main/java/module-info.java @@ -0,0 +1,3 @@ +module com.baeldung.dao { + exports com.baeldung.dao; +} diff --git a/maven-java-11/multimodule-maven-project/entitiymodule/pom.xml b/maven-java-11/multimodule-maven-project/entitiymodule/pom.xml new file mode 100644 index 0000000000..8e700e62b5 --- /dev/null +++ b/maven-java-11/multimodule-maven-project/entitiymodule/pom.xml @@ -0,0 +1,18 @@ + + + 4.0.0 + + com.baeldung.multimodule-maven-project + multimodule-maven-project + 1.0 + + com.baeldung.entitymodule + entitymodule + jar + 1.0 + entitymodule + + 11 + 11 + + diff --git a/maven-java-11/multimodule-maven-project/entitiymodule/src/main/java/com/baeldung/entity/User.java b/maven-java-11/multimodule-maven-project/entitiymodule/src/main/java/com/baeldung/entity/User.java new file mode 100644 index 0000000000..22022a2e6d --- /dev/null +++ b/maven-java-11/multimodule-maven-project/entitiymodule/src/main/java/com/baeldung/entity/User.java @@ -0,0 +1,19 @@ +package com.baeldung.entity; + +public class User { + + private final String name; + + public User(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + @Override + public String toString() { + return "User{" + "name=" + name + '}'; + } +} diff --git a/maven-java-11/multimodule-maven-project/entitiymodule/src/main/java/module-info.java b/maven-java-11/multimodule-maven-project/entitiymodule/src/main/java/module-info.java new file mode 100644 index 0000000000..67a3097352 --- /dev/null +++ b/maven-java-11/multimodule-maven-project/entitiymodule/src/main/java/module-info.java @@ -0,0 +1,3 @@ +module com.baeldung.entity { + exports com.baeldung.entity; +} diff --git a/maven-java-11/multimodule-maven-project/mainppmodule/pom.xml b/maven-java-11/multimodule-maven-project/mainppmodule/pom.xml new file mode 100644 index 0000000000..d2c94527f1 --- /dev/null +++ b/maven-java-11/multimodule-maven-project/mainppmodule/pom.xml @@ -0,0 +1,32 @@ + + + 4.0.0 + + com.baeldung.multimodule-maven-project + multimodule-maven-project + 1.0 + + com.baeldung.mainappmodule + mainappmodule + 1.0 + jar + mainappmodule + + + + com.baeldung.entitymodule + entitymodule + 1.0 + + + com.baeldung.daomodule + daomodule + 1.0 + + + com.baeldung.userdaomodule + userdaomodule + 1.0 + + + diff --git a/maven-java-11/multimodule-maven-project/mainppmodule/src/main/java/com/baeldung/mainapp/Application.java b/maven-java-11/multimodule-maven-project/mainppmodule/src/main/java/com/baeldung/mainapp/Application.java new file mode 100644 index 0000000000..0c0df7461b --- /dev/null +++ b/maven-java-11/multimodule-maven-project/mainppmodule/src/main/java/com/baeldung/mainapp/Application.java @@ -0,0 +1,19 @@ +package com.baeldung.mainapp; + +import com.baeldung.dao.Dao; +import com.baeldung.entity.User; +import com.baeldung.userdao.UserDao; +import java.util.HashMap; +import java.util.Map; + +public class Application { + + public static void main(String[] args) { + Map users = new HashMap<>(); + users.put(1, new User("Julie")); + users.put(2, new User("David")); + Dao userDao = new UserDao(users); + userDao.findAll().forEach(System.out::println); + } + +} diff --git a/maven-java-11/multimodule-maven-project/mainppmodule/src/main/java/module-info.java b/maven-java-11/multimodule-maven-project/mainppmodule/src/main/java/module-info.java new file mode 100644 index 0000000000..c688fcf7de --- /dev/null +++ b/maven-java-11/multimodule-maven-project/mainppmodule/src/main/java/module-info.java @@ -0,0 +1,6 @@ +module com.baeldung.mainapp { + requires com.baeldung.entity; + requires com.baeldung.userdao; + requires com.baeldung.dao; + uses com.baeldung.dao.Dao; +} diff --git a/maven-java-11/multimodule-maven-project/pom.xml b/maven-java-11/multimodule-maven-project/pom.xml new file mode 100644 index 0000000000..f22541738c --- /dev/null +++ b/maven-java-11/multimodule-maven-project/pom.xml @@ -0,0 +1,58 @@ + + + 4.0.0 + com.baeldung.multimodule-maven-project + multimodule-maven-project + 1.0 + pom + multimodule-maven-project + + com.baeldung.maven-java-11 + maven-java-11 + 1.0 + + + + + + junit + junit + 4.12 + test + + + org.assertj + assertj-core + 3.12.2 + test + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + 11 + 11 + + + + + + + + entitymodule + daomodule + userdaomodule + mainappmodule + + + + UTF-8 + + diff --git a/maven-java-11/multimodule-maven-project/userdaomodule/pom.xml b/maven-java-11/multimodule-maven-project/userdaomodule/pom.xml new file mode 100644 index 0000000000..b4fe7f0398 --- /dev/null +++ b/maven-java-11/multimodule-maven-project/userdaomodule/pom.xml @@ -0,0 +1,31 @@ + + + 4.0.0 + + com.baeldung.multimodule-maven-project + multimodule-maven-project + 1.0 + + com.baeldung.userdaomodule + userdaomodule + 1.0 + jar + userdaomodule + + + com.baeldung.entitymodule + entitymodule + 1.0 + + + com.baeldung.daomodule + daomodule + 1.0 + + + junit + junit + test + + + diff --git a/maven-java-11/multimodule-maven-project/userdaomodule/src/main/java/com/baeldung/userdao/UserDao.java b/maven-java-11/multimodule-maven-project/userdaomodule/src/main/java/com/baeldung/userdao/UserDao.java new file mode 100644 index 0000000000..1f1ea38a60 --- /dev/null +++ b/maven-java-11/multimodule-maven-project/userdaomodule/src/main/java/com/baeldung/userdao/UserDao.java @@ -0,0 +1,32 @@ +package com.baeldung.userdao; + +import com.baeldung.dao.Dao; +import com.baeldung.entity.User; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class UserDao implements Dao { + + private final Map users; + + public UserDao() { + users = new HashMap<>(); + } + + public UserDao(Map users) { + this.users = users; + } + + @Override + public List findAll() { + return new ArrayList<>(users.values()); + } + + @Override + public Optional findById(int id) { + return Optional.ofNullable(users.get(id)); + } +} \ No newline at end of file diff --git a/maven-java-11/multimodule-maven-project/userdaomodule/src/main/java/module-info.java b/maven-java-11/multimodule-maven-project/userdaomodule/src/main/java/module-info.java new file mode 100644 index 0000000000..f1cb217e23 --- /dev/null +++ b/maven-java-11/multimodule-maven-project/userdaomodule/src/main/java/module-info.java @@ -0,0 +1,6 @@ +module com.baeldung.userdao { + requires com.baeldung.entity; + requires com.baeldung.dao; + provides com.baeldung.dao.Dao with com.baeldung.userdao.UserDao; + exports com.baeldung.userdao; +} diff --git a/maven-java-11/multimodule-maven-project/userdaomodule/src/test/java/com/baeldung/userdao/test/UserDaoUnitTest.java b/maven-java-11/multimodule-maven-project/userdaomodule/src/test/java/com/baeldung/userdao/test/UserDaoUnitTest.java new file mode 100644 index 0000000000..191d17ff32 --- /dev/null +++ b/maven-java-11/multimodule-maven-project/userdaomodule/src/test/java/com/baeldung/userdao/test/UserDaoUnitTest.java @@ -0,0 +1,36 @@ +package com.baeldung.userdao.test; + +import com.baeldung.dao.Dao; +import com.baeldung.entity.User; +import com.baeldung.userdao.UserDao; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import static org.junit.Assert.*; +import static org.hamcrest.CoreMatchers.*; +import org.junit.Before; +import org.junit.Test; + +public class UserDaoUnitTest { + + private Dao userDao; + + @Before + public void setUpUserDaoInstance() { + Map users = new HashMap<>(); + users.put(1, new User("Julie")); + users.put(2, new User("David")); + userDao = new UserDao(users); + } + + @Test + public void givenUserDaoIntance_whenCalledFindById_thenCorrect() { + assertThat(userDao.findById(1), isA(Optional.class)); + } + + @Test + public void givenUserDaoIntance_whenCalledFindAll_thenCorrect() { + assertThat(userDao.findAll(), isA(List.class)); + } +} diff --git a/maven-java-11/pom.xml b/maven-java-11/pom.xml new file mode 100644 index 0000000000..ff95840523 --- /dev/null +++ b/maven-java-11/pom.xml @@ -0,0 +1,22 @@ + + + 4.0.0 + com.baeldung.maven-java-11 + maven-java-11 + 1.0 + pom + maven-java-11 + + parent-modules + com.baeldung + 1.0.0-SNAPSHOT + + + multimodule-maven-project + + + UTF-8 + 11 + 11 + + diff --git a/maven/README.md b/maven/README.md index 1352a2a10f..ca648ec203 100644 --- a/maven/README.md +++ b/maven/README.md @@ -15,3 +15,4 @@ - [Use the Latest Version of a Dependency in Maven](https://www.baeldung.com/maven-dependency-latest-version) - [Multi-Module Project with Maven](https://www.baeldung.com/maven-multi-module) - [Maven Enforcer Plugin](https://www.baeldung.com/maven-enforcer-plugin) +- [Eclipse Error: web.xml is missing and failOnMissingWebXml is set to true](https://www.baeldung.com/eclipse-error-web-xml-missing) diff --git a/maven/custom-rule/pom.xml b/maven/custom-rule/pom.xml index 25a3489fb9..2fbeb18922 100644 --- a/maven/custom-rule/pom.xml +++ b/maven/custom-rule/pom.xml @@ -2,20 +2,15 @@ + 4.0.0 + custom-rule + custom-rule + maven com.baeldung 0.0.1-SNAPSHOT - 4.0.0 - custom-rule - custom-rule - - - 3.0.0-M2 - 2.0.9 - - @@ -47,7 +42,7 @@ org.codehaus.plexus plexus-container-default - 1.0-alpha-9 + ${plexus-container-default.version} @@ -64,7 +59,9 @@ - - - - \ No newline at end of file + + 3.0.0-M2 + 2.0.9 + 1.0-alpha-9 + + diff --git a/maven/maven-enforcer/pom.xml b/maven/maven-enforcer/pom.xml index 9826beb0d9..b18be4f43d 100644 --- a/maven/maven-enforcer/pom.xml +++ b/maven/maven-enforcer/pom.xml @@ -2,14 +2,15 @@ + 4.0.0 + maven-enforcer + maven-enforcer + maven com.baeldung 0.0.1-SNAPSHOT - 4.0.0 - maven-enforcer - maven-enforcer diff --git a/maven/maven-war-plugin/pom.xml b/maven/maven-war-plugin/pom.xml new file mode 100644 index 0000000000..517c08978f --- /dev/null +++ b/maven/maven-war-plugin/pom.xml @@ -0,0 +1,29 @@ + + 4.0.0 + com.baeldung + maven-war-plugin-property + 0.0.1-SNAPSHOT + war + maven-war-plugin-property + + + + + maven-war-plugin + + 3.1.0 + + + false + + + + + + + + false + + \ No newline at end of file diff --git a/maven/profiles/pom.xml b/maven/profiles/pom.xml new file mode 100644 index 0000000000..110016f3a2 --- /dev/null +++ b/maven/profiles/pom.xml @@ -0,0 +1,88 @@ + + 4.0.0 + com.baeldung + profiles + 0.0.1-SNAPSHOT + profiles + + + + no-tests + + true + + + + integration-tests + + true + + + + mutation-tests + + + active-on-jdk-11 + + 11 + + + + active-on-windows-10 + + + windows 10 + Windows + amd64 + 10.0 + + + + + active-on-property-environment + + + environment + !test + + + + + active-on-missing-file + + + target/testreport.html + + + + + active-on-present-file + + + target/artifact.jar + + + + + + + + + org.apache.maven.plugins + maven-help-plugin + 3.2.0 + + + show-profiles + compile + + active-profiles + + + + + + + \ No newline at end of file diff --git a/noexception/README.md b/noexception/README.md deleted file mode 100644 index 9dd4c11190..0000000000 --- a/noexception/README.md +++ /dev/null @@ -1,2 +0,0 @@ -### Relevant Articles: -- [Introduction to NoException](http://www.baeldung.com/introduction-to-noexception) diff --git a/noexception/pom.xml b/noexception/pom.xml deleted file mode 100644 index f632f1e3a9..0000000000 --- a/noexception/pom.xml +++ /dev/null @@ -1,27 +0,0 @@ - - 4.0.0 - com.baeldung - noexception - 1.0 - noexception - - - com.baeldung - parent-modules - 1.0.0-SNAPSHOT - - - - - com.machinezoo.noexception - noexception - ${noexception.version} - - - - - 1.1.0 - - - diff --git a/noexception/src/main/java/com/baeldung/noexception/CustomExceptionHandler.java b/noexception/src/main/java/com/baeldung/noexception/CustomExceptionHandler.java deleted file mode 100644 index 59e13efaa0..0000000000 --- a/noexception/src/main/java/com/baeldung/noexception/CustomExceptionHandler.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.baeldung.noexception; - -import com.machinezoo.noexception.ExceptionHandler; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class CustomExceptionHandler extends ExceptionHandler { - - private Logger logger = LoggerFactory.getLogger(CustomExceptionHandler.class); - - @Override - public boolean handle(Throwable throwable) { - - if (throwable.getClass() - .isAssignableFrom(RuntimeException.class) - || throwable.getClass() - .isAssignableFrom(Error.class)) { - return false; - } else { - logger.error("Caught Exception ", throwable); - return true; - } - } -} diff --git a/noexception/src/test/java/com/baeldung/noexception/NoExceptionUnitTest.java b/noexception/src/test/java/com/baeldung/noexception/NoExceptionUnitTest.java deleted file mode 100644 index 690ea43520..0000000000 --- a/noexception/src/test/java/com/baeldung/noexception/NoExceptionUnitTest.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.baeldung.noexception; - -import com.machinezoo.noexception.Exceptions; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class NoExceptionUnitTest { - - private static Logger logger = LoggerFactory.getLogger(NoExceptionUnitTest.class); - - @Test - public void whenStdExceptionHandling_thenCatchAndLog() { - try { - System.out.println("Result is " + Integer.parseInt("foobar")); - } catch (Throwable exception) { - logger.error("Caught exception:", exception); - } - } - - @Test - public void whenDefaultNoException_thenCatchAndLog() { - - Exceptions.log().run(() -> System.out.println("Result is " + Integer.parseInt("foobar"))); - } - - @Test - public void givenLogger_whenDefaultNoException_thenCatchAndLogWithClassName() { - System.out.println("Result is " + Exceptions.log(logger).get(() -> +Integer.parseInt("foobar")).orElse(-1)); - } - - @Test - public void givenLoggerAndMessage_whenDefaultNoException_thenCatchAndLogWithClassNameAndMessage() { - System.out.println("Result is " + Exceptions.log(logger, "Something went wrong:").get(() -> +Integer.parseInt("foobar")).orElse(-1)); - } - - @Test - public void givenDefaultValue_whenDefaultNoException_thenCatchAndLogPrintDefault() { - System.out.println("Result is " + Exceptions.log(logger, "Something went wrong:").get(() -> +Integer.parseInt("foobar")).orElse(-1)); - } - - @Test(expected = Error.class) - public void givenCustomHandler_whenError_thenRethrowError() { - CustomExceptionHandler customExceptionHandler = new CustomExceptionHandler(); - customExceptionHandler.run(() -> throwError()); - } - - @Test - public void givenCustomHandler_whenException_thenCatchAndLog() { - CustomExceptionHandler customExceptionHandler = new CustomExceptionHandler(); - customExceptionHandler.run(() -> throwException()); - } - - private static void throwError() { - throw new Error("This is very bad."); - } - - private static void throwException() { - String testString = "foo"; - testString.charAt(5); - } - -} diff --git a/parent-kotlin/pom.xml b/parent-kotlin/pom.xml index 7a3a8b10ca..6f7fe6c102 100644 --- a/parent-kotlin/pom.xml +++ b/parent-kotlin/pom.xml @@ -108,6 +108,9 @@ ${project.basedir}/src/main/java ${java.version} + + -Xjvm-default=enable + @@ -202,10 +205,10 @@ - 1.3.10 + 1.3.30 1.0.0 0.9.5 - 3.11.0 - 1.2.0 + 3.12.0 + 1.3.2 diff --git a/parent-spring-5/pom.xml b/parent-spring-5/pom.xml index 5d7a3b66b3..3178682d34 100644 --- a/parent-spring-5/pom.xml +++ b/parent-spring-5/pom.xml @@ -29,10 +29,10 @@ - 5.1.2.RELEASE + 5.1.4.RELEASE 5.0.2 2.9.6 - 5.1.2.RELEASE + 5.1.4.RELEASE \ No newline at end of file diff --git a/patterns/README.md b/patterns/README.md index 9a15cdff02..f627251aa4 100644 --- a/patterns/README.md +++ b/patterns/README.md @@ -1,3 +1,6 @@ ### Relevant Articles: - [A Guide to the Front Controller Pattern in Java](http://www.baeldung.com/java-front-controller-pattern) - [Introduction to Intercepting Filter Pattern in Java](http://www.baeldung.com/intercepting-filter-pattern-in-java) +- [Introduction to the Null Object Pattern](https://www.baeldung.com/java-null-object-pattern) +- [The Dependency Inversion Principle in Java](https://www.baeldung.com/java-dependency-inversion-principle) +- [Avoid Check for Null Statement in Java](https://www.baeldung.com/java-avoid-null-check) diff --git a/patterns/design-patterns-2/README.md b/patterns/design-patterns-2/README.md new file mode 100644 index 0000000000..c2a75d4680 --- /dev/null +++ b/patterns/design-patterns-2/README.md @@ -0,0 +1,3 @@ +### Relevant Articles + +- [The Mediator Pattern in Java](https://www.baeldung.com/java-mediator-pattern) diff --git a/patterns/design-patterns-2/pom.xml b/patterns/design-patterns-2/pom.xml index 2a0213065b..5c3e70b046 100644 --- a/patterns/design-patterns-2/pom.xml +++ b/patterns/design-patterns-2/pom.xml @@ -15,11 +15,29 @@ + + org.jetbrains + annotations + ${intellij.annotations.version} + + + org.projectlombok + lombok + ${lombok.version} + provided + + + org.apache.commons + commons-lang3 + ${commons-lang3.version} + UTF-8 1.8 1.8 + 16.0.2 + 3.5 diff --git a/patterns/design-patterns-2/src/main/java/com/baeldung/mediator/Button.java b/patterns/design-patterns-2/src/main/java/com/baeldung/mediator/Button.java new file mode 100644 index 0000000000..0507d27872 --- /dev/null +++ b/patterns/design-patterns-2/src/main/java/com/baeldung/mediator/Button.java @@ -0,0 +1,13 @@ +package com.baeldung.mediator; + +public class Button { + private Mediator mediator; + + public void setMediator(Mediator mediator) { + this.mediator = mediator; + } + + public void press() { + this.mediator.press(); + } +} diff --git a/patterns/design-patterns-2/src/main/java/com/baeldung/mediator/Fan.java b/patterns/design-patterns-2/src/main/java/com/baeldung/mediator/Fan.java new file mode 100644 index 0000000000..b7862f42d5 --- /dev/null +++ b/patterns/design-patterns-2/src/main/java/com/baeldung/mediator/Fan.java @@ -0,0 +1,24 @@ +package com.baeldung.mediator; + +public class Fan { + private Mediator mediator; + private boolean isOn = false; + + public void setMediator(Mediator mediator) { + this.mediator = mediator; + } + + public boolean isOn() { + return isOn; + } + + public void turnOn() { + this.mediator.start(); + isOn = true; + } + + public void turnOff() { + isOn = false; + this.mediator.stop(); + } +} diff --git a/patterns/design-patterns-2/src/main/java/com/baeldung/mediator/Mediator.java b/patterns/design-patterns-2/src/main/java/com/baeldung/mediator/Mediator.java new file mode 100644 index 0000000000..08cd023748 --- /dev/null +++ b/patterns/design-patterns-2/src/main/java/com/baeldung/mediator/Mediator.java @@ -0,0 +1,37 @@ +package com.baeldung.mediator; + +public class Mediator { + private Button button; + private Fan fan; + private PowerSupplier powerSupplier; + + public void setButton(Button button) { + this.button = button; + this.button.setMediator(this); + } + + public void setFan(Fan fan) { + this.fan = fan; + this.fan.setMediator(this); + } + + public void setPowerSupplier(PowerSupplier powerSupplier) { + this.powerSupplier = powerSupplier; + } + + public void press() { + if (fan.isOn()) { + fan.turnOff(); + } else { + fan.turnOn(); + } + } + + public void start() { + powerSupplier.turnOn(); + } + + public void stop() { + powerSupplier.turnOff(); + } +} diff --git a/patterns/design-patterns-2/src/main/java/com/baeldung/mediator/PowerSupplier.java b/patterns/design-patterns-2/src/main/java/com/baeldung/mediator/PowerSupplier.java new file mode 100644 index 0000000000..b4a05816c7 --- /dev/null +++ b/patterns/design-patterns-2/src/main/java/com/baeldung/mediator/PowerSupplier.java @@ -0,0 +1,11 @@ +package com.baeldung.mediator; + +public class PowerSupplier { + public void turnOn() { + // implementation + } + + public void turnOff() { + // implementation + } +} diff --git a/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/APIContracts.java b/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/APIContracts.java new file mode 100644 index 0000000000..7d6abf53b8 --- /dev/null +++ b/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/APIContracts.java @@ -0,0 +1,30 @@ +package com.baeldung.nulls; + +public class APIContracts { + + /** + * Prints the value of {@code param} if not null. Prints {@code null} otherwise. + * + * @param param + */ + public void print(Object param) { + System.out.println("Printing " + param); + } + + /** + * @return non null result + * @throws Exception - if result is null + */ + public Object process() throws Exception { + Object result = doSomething(); + if (result == null) { + throw new Exception("Processing fail. Got a null response"); + } else { + return result; + } + } + + private Object doSomething() { + return null; + } +} diff --git a/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/Assertions.java b/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/Assertions.java new file mode 100644 index 0000000000..a0d692623f --- /dev/null +++ b/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/Assertions.java @@ -0,0 +1,13 @@ +package com.baeldung.nulls; + +public class Assertions { + + public void accept(Object param){ + assert param != null; + + doSomething(param); + } + + private void doSomething(Object param) { + } +} diff --git a/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/EmptyCollections.java b/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/EmptyCollections.java new file mode 100644 index 0000000000..5958cf8dc6 --- /dev/null +++ b/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/EmptyCollections.java @@ -0,0 +1,25 @@ +package com.baeldung.nulls; + +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class EmptyCollections { + + public List names() { + if (userExist()) { + return Stream.of(readName()).collect(Collectors.toList()); + } else { + return Collections.emptyList(); + } + } + + private boolean userExist() { + return false; + } + + private String readName() { + return "test"; + } +} diff --git a/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/FindBugsAnnotations.java b/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/FindBugsAnnotations.java new file mode 100644 index 0000000000..697d5e4959 --- /dev/null +++ b/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/FindBugsAnnotations.java @@ -0,0 +1,30 @@ +package com.baeldung.nulls; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + + +public class FindBugsAnnotations { + + public void accept(@NotNull Object param) { + System.out.println(param.toString()); + } + + public void print(@Nullable Object param) { + System.out.println("Printing " + param); + } + + @NotNull + public Object process() throws Exception { + Object result = doSomething(); + if (result == null) { + throw new Exception("Processing fail. Got a null response"); + } else { + return result; + } + } + + private Object doSomething() { + return null; + } +} diff --git a/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/Preconditions.java b/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/Preconditions.java new file mode 100644 index 0000000000..9d9633a13e --- /dev/null +++ b/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/Preconditions.java @@ -0,0 +1,39 @@ +package com.baeldung.nulls; + +public class Preconditions { + + public void goodAccept(String one, String two, String three) { + if (one == null || two == null || three == null) { + throw new IllegalArgumentException(); + } + + process(one); + process(two); + process(three); + } + + public void badAccept(String one, String two, String three) { + if (one == null) { + throw new IllegalArgumentException(); + } else { + process(one); + } + + if (two == null) { + throw new IllegalArgumentException(); + } else { + process(two); + } + + if (three == null) { + throw new IllegalArgumentException(); + } else { + process(three); + } + + } + + private void process(String one) { + } + +} diff --git a/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/PrimitivesAndWrapper.java b/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/PrimitivesAndWrapper.java new file mode 100644 index 0000000000..c75918c486 --- /dev/null +++ b/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/PrimitivesAndWrapper.java @@ -0,0 +1,21 @@ +package com.baeldung.nulls; + +public class PrimitivesAndWrapper { + + public static int primitiveSum(int a, int b) { + return a + b; + } + + public static Integer wrapperSum(Integer a, Integer b) { + return a + b; + } + + public static Integer goodSum(Integer a, Integer b) { + if (a != null && b != null) { + return a + b; + } else { + throw new IllegalArgumentException(); + } + } + +} diff --git a/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/UsingLombok.java b/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/UsingLombok.java new file mode 100644 index 0000000000..73db0742c8 --- /dev/null +++ b/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/UsingLombok.java @@ -0,0 +1,10 @@ +package com.baeldung.nulls; + +import lombok.NonNull; + +public class UsingLombok { + + public void accept(@NonNull Object param){ + System.out.println(param); + } +} diff --git a/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/UsingObjects.java b/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/UsingObjects.java new file mode 100644 index 0000000000..5384edee5e --- /dev/null +++ b/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/UsingObjects.java @@ -0,0 +1,11 @@ +package com.baeldung.nulls; + +import java.util.Objects; + +public class UsingObjects { + + public void accept(Object param) { + Objects.requireNonNull(param); + // doSomething() + } +} diff --git a/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/UsingOptional.java b/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/UsingOptional.java new file mode 100644 index 0000000000..d5dd56e760 --- /dev/null +++ b/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/UsingOptional.java @@ -0,0 +1,23 @@ +package com.baeldung.nulls; + +import java.util.Optional; + +public class UsingOptional { + + public Optional process(boolean processed) { + + String response = doSomething(processed); + + return Optional.ofNullable(response); + } + + private String doSomething(boolean processed) { + + if (processed) { + return "passed"; + } else { + return null; + } + } + +} diff --git a/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/UsingStringUtils.java b/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/UsingStringUtils.java new file mode 100644 index 0000000000..c7c73b73eb --- /dev/null +++ b/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/UsingStringUtils.java @@ -0,0 +1,22 @@ +package com.baeldung.nulls; + +import org.apache.commons.lang3.StringUtils; + +public class UsingStringUtils { + + public void accept(String param) { + if (StringUtils.isNotEmpty(param)) { + System.out.println(param); + } else { + throw new IllegalArgumentException(); + } + } + + public void acceptOnlyNonBlank(String param) { + if (StringUtils.isNotBlank(param)) { + System.out.println(param); + } else { + throw new IllegalArgumentException(); + } + } +} diff --git a/patterns/design-patterns-2/src/test/java/com/baeldung/mediator/MediatorIntegrationTest.java b/patterns/design-patterns-2/src/test/java/com/baeldung/mediator/MediatorIntegrationTest.java new file mode 100644 index 0000000000..0bda659f3f --- /dev/null +++ b/patterns/design-patterns-2/src/test/java/com/baeldung/mediator/MediatorIntegrationTest.java @@ -0,0 +1,36 @@ +package com.baeldung.mediator; + +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class MediatorIntegrationTest { + + private Button button; + private Fan fan; + + @Before + public void setUp() { + this.button = new Button(); + this.fan = new Fan(); + PowerSupplier powerSupplier = new PowerSupplier(); + Mediator mediator = new Mediator(); + + mediator.setButton(this.button); + mediator.setFan(fan); + mediator.setPowerSupplier(powerSupplier); + } + + @Test + public void givenTurnedOffFan_whenPressingButtonTwice_fanShouldTurnOnAndOff() { + assertFalse(fan.isOn()); + + button.press(); + assertTrue(fan.isOn()); + + button.press(); + assertFalse(fan.isOn()); + } +} \ No newline at end of file diff --git a/patterns/design-patterns-2/src/test/java/com/baeldung/nulls/PrimitivesAndWrapperUnitTest.java b/patterns/design-patterns-2/src/test/java/com/baeldung/nulls/PrimitivesAndWrapperUnitTest.java new file mode 100644 index 0000000000..49655619f6 --- /dev/null +++ b/patterns/design-patterns-2/src/test/java/com/baeldung/nulls/PrimitivesAndWrapperUnitTest.java @@ -0,0 +1,35 @@ +package com.baeldung.nulls; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +class PrimitivesAndWrapperUnitTest { + + @Test + public void givenBothArgsNonNull_whenCallingWrapperSum_thenReturnSum() { + + Integer sum = PrimitivesAndWrapper.wrapperSum(0, 0); + + assertEquals(0, sum.intValue()); + } + + @Test() + public void givenOneArgIsNull_whenCallingWrapperSum_thenThrowNullPointerException() { + assertThrows(NullPointerException.class, () -> PrimitivesAndWrapper.wrapperSum(null, 2)); + } + + @Test() + public void givenBothArgsNull_whenCallingWrapperSum_thenThrowNullPointerException() { + assertThrows(NullPointerException.class, () -> PrimitivesAndWrapper.wrapperSum(null, null)); + } + + @Test() + public void givenOneArgNull_whenCallingGoodSum_thenThrowIllegalArgumentException() { + assertThrows(IllegalArgumentException.class, () -> PrimitivesAndWrapper.goodSum(null, 2)); + } + + + +} \ No newline at end of file diff --git a/patterns/design-patterns-2/src/test/java/com/baeldung/nulls/UsingLombokUnitTest.java b/patterns/design-patterns-2/src/test/java/com/baeldung/nulls/UsingLombokUnitTest.java new file mode 100644 index 0000000000..b322344aba --- /dev/null +++ b/patterns/design-patterns-2/src/test/java/com/baeldung/nulls/UsingLombokUnitTest.java @@ -0,0 +1,24 @@ +package com.baeldung.nulls; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +class UsingLombokUnitTest { + + private UsingLombok classUnderTest; + + @BeforeEach + public void setup() { + classUnderTest = new UsingLombok(); + } + + @Test + public void whenNullArg_thenThrowNullPointerException() { + + assertThrows(NullPointerException.class, () -> classUnderTest.accept(null)); + + } + +} \ No newline at end of file diff --git a/patterns/design-patterns-2/src/test/java/com/baeldung/nulls/UsingObjectsUnitTest.java b/patterns/design-patterns-2/src/test/java/com/baeldung/nulls/UsingObjectsUnitTest.java new file mode 100644 index 0000000000..e1f5a288e6 --- /dev/null +++ b/patterns/design-patterns-2/src/test/java/com/baeldung/nulls/UsingObjectsUnitTest.java @@ -0,0 +1,30 @@ +package com.baeldung.nulls; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertThrows; + +class UsingObjectsUnitTest { + + private UsingObjects classUnderTest; + + @BeforeEach + public void setup() { + classUnderTest = new UsingObjects(); + } + + @Test + public void whenArgIsNull_thenThrowException() { + + assertThrows(NullPointerException.class, () -> classUnderTest.accept(null)); + } + + @Test + public void whenArgIsNonNull_thenDoesNotThrowException() { + + assertDoesNotThrow(() -> classUnderTest.accept("test ")); + } + +} \ No newline at end of file diff --git a/patterns/design-patterns-2/src/test/java/com/baeldung/nulls/UsingOptionalUnitTest.java b/patterns/design-patterns-2/src/test/java/com/baeldung/nulls/UsingOptionalUnitTest.java new file mode 100644 index 0000000000..8f896cedfa --- /dev/null +++ b/patterns/design-patterns-2/src/test/java/com/baeldung/nulls/UsingOptionalUnitTest.java @@ -0,0 +1,42 @@ +package com.baeldung.nulls; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class UsingOptionalUnitTest { + + private UsingOptional classUnderTest; + + @BeforeEach + public void setup() { + classUnderTest = new UsingOptional(); + } + + @Test + public void whenArgIsFalse_thenReturnEmptyResponse() { + + Optional result = classUnderTest.process(false); + + assertFalse(result.isPresent()); + } + + @Test + public void whenArgIsTrue_thenReturnValidResponse() { + + Optional result = classUnderTest.process(true); + + assertTrue(result.isPresent()); + } + + @Test + public void whenArgIsFalse_thenChainResponseAndThrowException() { + + assertThrows(Exception.class, () -> classUnderTest.process(false).orElseThrow(() -> new Exception())); + } +} \ No newline at end of file diff --git a/patterns/design-patterns-2/src/test/java/com/baeldung/nulls/UsingStringUtilsUnitTest.java b/patterns/design-patterns-2/src/test/java/com/baeldung/nulls/UsingStringUtilsUnitTest.java new file mode 100644 index 0000000000..f7c51a7dc5 --- /dev/null +++ b/patterns/design-patterns-2/src/test/java/com/baeldung/nulls/UsingStringUtilsUnitTest.java @@ -0,0 +1,42 @@ +package com.baeldung.nulls; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +class UsingStringUtilsUnitTest { + + private UsingStringUtils classUnderTest; + + @BeforeEach + public void setup() { + classUnderTest = new UsingStringUtils(); + } + + @Test + public void givenArgIsNull_whenCallingAccept_throwIllegalArgumentException() { + assertThrows(IllegalArgumentException.class, () -> classUnderTest.accept(null)); + } + + @Test + public void givenArgIsEmpty_whenCallingAccept_throwIllegalArgumentException() { + assertThrows(IllegalArgumentException.class, () -> classUnderTest.accept("")); + } + + @Test + public void givenArgIsNull_whenCallingAcceptOnlyNonBlank_throwIllegalArgumentException() { + assertThrows(IllegalArgumentException.class, () -> classUnderTest.acceptOnlyNonBlank(null)); + } + + @Test + public void givenArgIsEmpty_whenCallingAcceptOnlyNonBlank_throwIllegalArgumentException() { + assertThrows(IllegalArgumentException.class, () -> classUnderTest.acceptOnlyNonBlank("")); + } + + @Test + public void givenArgIsBlank_whenCallingAcceptOnlyNonBlank_throwIllegalArgumentException() { + assertThrows(IllegalArgumentException.class, () -> classUnderTest.acceptOnlyNonBlank(" ")); + } + +} \ No newline at end of file diff --git a/patterns/design-patterns/README.md b/patterns/design-patterns/README.md index a4513b7d95..605fdc0d6e 100644 --- a/patterns/design-patterns/README.md +++ b/patterns/design-patterns/README.md @@ -19,3 +19,4 @@ - [The Command Pattern in Java](http://www.baeldung.com/java-command-pattern) - [Java Constructors vs Static Factory Methods](https://www.baeldung.com/java-constructors-vs-static-factory-methods) - [The Adapter Pattern in Java](https://www.baeldung.com/java-adapter-pattern) +- [Currying in Java](https://www.baeldung.com/java-currying) diff --git a/patterns/design-patterns/src/main/java/com/baeldung/currying/Letter.java b/patterns/design-patterns/src/main/java/com/baeldung/currying/Letter.java new file mode 100644 index 0000000000..0939569d3c --- /dev/null +++ b/patterns/design-patterns/src/main/java/com/baeldung/currying/Letter.java @@ -0,0 +1,110 @@ +package com.baeldung.currying; + +import java.time.LocalDate; +import java.util.Objects; +import java.util.function.BiFunction; +import java.util.function.Function; + +public class Letter { + private String returningAddress; + private String insideAddress; + private LocalDate dateOfLetter; + private String salutation; + private String body; + private String closing; + + Letter(String returningAddress, String insideAddress, LocalDate dateOfLetter, String salutation, String body, String closing) { + this.returningAddress = returningAddress; + this.insideAddress = insideAddress; + this.dateOfLetter = dateOfLetter; + this.salutation = salutation; + this.body = body; + this.closing = closing; + } + + Letter(String salutation, String body) { + this(null, null, LocalDate.now(), salutation, body, null); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Letter letter = (Letter) o; + return Objects.equals(returningAddress, letter.returningAddress) && + Objects.equals(insideAddress, letter.insideAddress) && + Objects.equals(dateOfLetter, letter.dateOfLetter) && + Objects.equals(salutation, letter.salutation) && + Objects.equals(body, letter.body) && + Objects.equals(closing, letter.closing); + } + + @Override + public int hashCode() { + return Objects.hash(returningAddress, insideAddress, dateOfLetter, salutation, body, closing); + } + + @Override + public String toString() { + return "Letter{" + "returningAddress='" + returningAddress + '\'' + ", insideAddress='" + insideAddress + '\'' + + ", dateOfLetter=" + dateOfLetter + ", salutation='" + salutation + '\'' + ", body='" + body + '\'' + + ", closing='" + closing + '\'' + '}'; + } + + static Letter createLetter(String salutation, String body) { + return new Letter(salutation, body); + } + + static BiFunction SIMPLE_LETTER_CREATOR = // + (salutation, body) -> new Letter(salutation, body); + + static Function> SIMPLE_CURRIED_LETTER_CREATOR = // + saluation -> body -> new Letter(saluation, body); + + static Function>>>>> LETTER_CREATOR = // + returnAddress + -> closing + -> dateOfLetter + -> insideAddress + -> salutation + -> body + -> new Letter(returnAddress, insideAddress, dateOfLetter, salutation, body, closing); + + static AddReturnAddress builder() { + return returnAddress + -> closing + -> dateOfLetter + -> insideAddress + -> salutation + -> body + -> new Letter(returnAddress, insideAddress, dateOfLetter, salutation, body, closing); + } + + interface AddReturnAddress { + Letter.AddClosing withReturnAddress(String returnAddress); + } + + interface AddClosing { + Letter.AddDateOfLetter withClosing(String closing); + } + + interface AddDateOfLetter { + Letter.AddInsideAddress withDateOfLetter(LocalDate dateOfLetter); + } + + interface AddInsideAddress { + Letter.AddSalutation withInsideAddress(String insideAddress); + } + + interface AddSalutation { + Letter.AddBody withSalutation(String salutation); + } + + interface AddBody { + Letter withBody(String body); + } +} \ No newline at end of file diff --git a/patterns/design-patterns/src/test/java/com/baeldung/currying/LetterUnitTest.java b/patterns/design-patterns/src/test/java/com/baeldung/currying/LetterUnitTest.java new file mode 100644 index 0000000000..bf1bafe72c --- /dev/null +++ b/patterns/design-patterns/src/test/java/com/baeldung/currying/LetterUnitTest.java @@ -0,0 +1,58 @@ +package com.baeldung.currying; + +import org.junit.Test; + +import java.time.LocalDate; + +import static com.baeldung.currying.Letter.LETTER_CREATOR; +import static com.baeldung.currying.Letter.SIMPLE_CURRIED_LETTER_CREATOR; +import static com.baeldung.currying.Letter.SIMPLE_LETTER_CREATOR; +import static org.junit.Assert.assertEquals; + +public class LetterUnitTest { + private static final String BODY = "BODY"; + private static final String SALUTATION = "SALUTATION"; + private static final String RETURNING_ADDRESS = "RETURNING ADDRESS"; + private static final String INSIDE_ADDRESS = "INSIDE ADDRESS"; + private static final LocalDate DATE_OF_LETTER = LocalDate.of(2013, 3, 1); + private static final String CLOSING = "CLOSING"; + private static final Letter SIMPLE_LETTER = new Letter(SALUTATION, BODY); + private static final Letter LETTER = new Letter(RETURNING_ADDRESS, INSIDE_ADDRESS, DATE_OF_LETTER, SALUTATION, BODY, CLOSING); + + @Test + public void whenStaticCreateMethodIsCalled_thenaSimpleLetterIsCreated() { + assertEquals(SIMPLE_LETTER, Letter.createLetter(SALUTATION, BODY)); + } + + @Test + public void whenStaticBiFunctionIsCalled_thenaSimpleLetterIsCreated() { + assertEquals(SIMPLE_LETTER, SIMPLE_LETTER_CREATOR.apply(SALUTATION, BODY)); + } + + @Test + public void whenStaticSimpleCurriedFunctionIsCalled_thenaSimpleLetterIsCreated() { + assertEquals(SIMPLE_LETTER, SIMPLE_CURRIED_LETTER_CREATOR.apply(SALUTATION).apply(BODY)); + } + + @Test + public void whenStaticCurriedFunctionIsCalled_thenaLetterIsCreated() { + assertEquals(LETTER, LETTER_CREATOR + .apply(RETURNING_ADDRESS) + .apply(CLOSING) + .apply(DATE_OF_LETTER) + .apply(INSIDE_ADDRESS) + .apply(SALUTATION) + .apply(BODY)); + } + + @Test + public void whenStaticBuilderIsCalled_thenaLetterIsCreated() { + assertEquals(LETTER, Letter.builder() + .withReturnAddress(RETURNING_ADDRESS) + .withClosing(CLOSING) + .withDateOfLetter(DATE_OF_LETTER) + .withInsideAddress(INSIDE_ADDRESS) + .withSalutation(SALUTATION) + .withBody(BODY)); + } +} \ No newline at end of file diff --git a/patterns/dip/pom.xml b/patterns/dip/pom.xml new file mode 100644 index 0000000000..dac3f824f2 --- /dev/null +++ b/patterns/dip/pom.xml @@ -0,0 +1,39 @@ + + + 4.0.0 + com.baeldung.dip + dip + dip + 1.0-SNAPSHOT + + + com.baeldung + patterns + 1.0.0-SNAPSHOT + .. + + + + + junit + junit + 4.12 + test + + + org.assertj + assertj-core + 3.12.1 + test + + + + + UTF-8 + 11 + 11 + + + diff --git a/patterns/dip/src/main/java/com/baeldung/dip/application/Application.java b/patterns/dip/src/main/java/com/baeldung/dip/application/Application.java new file mode 100644 index 0000000000..8cc8901f70 --- /dev/null +++ b/patterns/dip/src/main/java/com/baeldung/dip/application/Application.java @@ -0,0 +1,18 @@ +package com.baeldung.dip.application; + +import com.baeldung.dip.daoimplementations.SimpleCustomerDao; +import com.baeldung.dip.entities.Customer; +import com.baeldung.dip.services.CustomerService; +import java.util.Map; +import java.util.HashMap; + +public class Application { + + public static void main(String[] args) { + Map customers = new HashMap<>(); + customers.put(1, new Customer("John")); + customers.put(2, new Customer("Susan")); + CustomerService customerService = new CustomerService(new SimpleCustomerDao(customers)); + customerService.findAll().forEach(System.out::println); + } +} diff --git a/patterns/dip/src/main/java/com/baeldung/dip/daoimplementations/SimpleCustomerDao.java b/patterns/dip/src/main/java/com/baeldung/dip/daoimplementations/SimpleCustomerDao.java new file mode 100644 index 0000000000..ea2bf3f00a --- /dev/null +++ b/patterns/dip/src/main/java/com/baeldung/dip/daoimplementations/SimpleCustomerDao.java @@ -0,0 +1,28 @@ +package com.baeldung.dip.daoimplementations; + +import com.baeldung.dip.entities.Customer; +import com.baeldung.dip.daointerfaces.CustomerDao; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class SimpleCustomerDao implements CustomerDao { + + private Map customers = new HashMap<>(); + + public SimpleCustomerDao(Map customers) { + this.customers = customers; + } + + @Override + public Optional findById(int id) { + return Optional.ofNullable(customers.get(id)); + } + + @Override + public List findAll() { + return new ArrayList<>(customers.values()); + } +} diff --git a/patterns/dip/src/main/java/com/baeldung/dip/daointerfaces/CustomerDao.java b/patterns/dip/src/main/java/com/baeldung/dip/daointerfaces/CustomerDao.java new file mode 100644 index 0000000000..8ea83673b0 --- /dev/null +++ b/patterns/dip/src/main/java/com/baeldung/dip/daointerfaces/CustomerDao.java @@ -0,0 +1,13 @@ +package com.baeldung.dip.daointerfaces; + +import com.baeldung.dip.entities.Customer; +import java.util.List; +import java.util.Optional; + +public interface CustomerDao { + + Optional findById(int id); + + List findAll(); + +} diff --git a/patterns/dip/src/main/java/com/baeldung/dip/entities/Customer.java b/patterns/dip/src/main/java/com/baeldung/dip/entities/Customer.java new file mode 100644 index 0000000000..f8d5d82102 --- /dev/null +++ b/patterns/dip/src/main/java/com/baeldung/dip/entities/Customer.java @@ -0,0 +1,19 @@ +package com.baeldung.dip.entities; + +public class Customer { + + private final String name; + + public Customer(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + @Override + public String toString() { + return "Customer{" + "name=" + name + '}'; + } +} diff --git a/patterns/dip/src/main/java/com/baeldung/dip/services/CustomerService.java b/patterns/dip/src/main/java/com/baeldung/dip/services/CustomerService.java new file mode 100644 index 0000000000..4566186ced --- /dev/null +++ b/patterns/dip/src/main/java/com/baeldung/dip/services/CustomerService.java @@ -0,0 +1,23 @@ +package com.baeldung.dip.services; + +import com.baeldung.dip.daointerfaces.CustomerDao; +import com.baeldung.dip.entities.Customer; +import java.util.List; +import java.util.Optional; + +public class CustomerService { + + private final CustomerDao customerDao; + + public CustomerService(CustomerDao customerDao) { + this.customerDao = customerDao; + } + + public Optional findById(int id) { + return customerDao.findById(id); + } + + public List findAll() { + return customerDao.findAll(); + } +} diff --git a/patterns/dip/src/test/java/com/baeldung/dip/tests/CustomerDaoUnitTest.java b/patterns/dip/src/test/java/com/baeldung/dip/tests/CustomerDaoUnitTest.java new file mode 100644 index 0000000000..2a03822ce2 --- /dev/null +++ b/patterns/dip/src/test/java/com/baeldung/dip/tests/CustomerDaoUnitTest.java @@ -0,0 +1,46 @@ +package com.baeldung.dip.tests; + +import com.baeldung.dip.daoimplementations.SimpleCustomerDao; +import com.baeldung.dip.daointerfaces.CustomerDao; +import com.baeldung.dip.entities.Customer; +import java.util.Map; +import java.util.HashMap; +import java.util.List; +import java.util.Optional; +import static org.assertj.core.api.Assertions.assertThat; +import org.junit.Before; +import org.junit.Test; + +public class CustomerDaoUnitTest { + + private CustomerDao customerDao; + + @Before + public void setUpCustomerDaoInstance() { + Map customers = new HashMap<>(); + customers.put(1, new Customer("John")); + customers.put(2, new Customer("Susan")); + customerDao = new SimpleCustomerDao(customers); + } + + @Test + public void givenCustomerDaoInstance_whenCalledFindById_thenCorrect() { + assertThat(customerDao.findById(1)).isInstanceOf(Optional.class); + } + + @Test + public void givenCustomerDaoInstance_whenCalledFindAll_thenCorrect() { + assertThat(customerDao.findAll()).isInstanceOf(List.class); + } + + @Test + public void givenCustomerDaoInstance_whenCalledFindByIdWithNullCustomer_thenCorrect() { + Map customers = new HashMap(); + customers.put(1, null); + CustomerDao customerDaoObject = new SimpleCustomerDao(customers); + + Customer customer = customerDaoObject.findById(1).orElseGet(() -> new Customer("Non-existing customer")); + + assertThat(customer.getName()).isEqualTo("Non-existing customer"); + } +} diff --git a/patterns/dip/src/test/java/com/baeldung/dip/tests/CustomerServiceUnitTest.java b/patterns/dip/src/test/java/com/baeldung/dip/tests/CustomerServiceUnitTest.java new file mode 100644 index 0000000000..5ffd6fad51 --- /dev/null +++ b/patterns/dip/src/test/java/com/baeldung/dip/tests/CustomerServiceUnitTest.java @@ -0,0 +1,46 @@ +package com.baeldung.dip.tests; + +import com.baeldung.dip.daoimplementations.SimpleCustomerDao; +import com.baeldung.dip.entities.Customer; +import com.baeldung.dip.services.CustomerService; +import java.util.Map; +import java.util.HashMap; +import java.util.List; +import java.util.Optional; +import static org.assertj.core.api.Assertions.assertThat; +import org.junit.Before; +import org.junit.Test; + +public class CustomerServiceUnitTest { + + private CustomerService customerService; + + @Before + public void setUpCustomerServiceInstance() { + Map customers = new HashMap<>(); + customers.put(1, new Customer("John")); + customers.put(2, new Customer("Susan")); + customerService = new CustomerService(new SimpleCustomerDao(customers)); + } + + @Test + public void givenCustomerServiceInstance_whenCalledFindById_thenCorrect() { + assertThat(customerService.findById(1)).isInstanceOf(Optional.class); + } + + @Test + public void givenCustomerServiceInstance_whenCalledFindAll_thenCorrect() { + assertThat(customerService.findAll()).isInstanceOf(List.class); + } + + @Test + public void givenCustomerServiceInstance_whenCalledFindByIdWithNullCustomer_thenCorrect() { + Map customers = new HashMap<>(); + customers.put(1, null); + customerService = new CustomerService(new SimpleCustomerDao(customers)); + + Customer customer = customerService.findById(1).orElseGet(() -> new Customer("Non-existing customer")); + + assertThat(customer.getName()).isEqualTo("Non-existing customer"); + } +} diff --git a/patterns/dipmodular/com.baeldung.dip.daoimplementations/com/baeldung/dip/daoimplementations/SimpleCustomerDao.java b/patterns/dipmodular/com.baeldung.dip.daoimplementations/com/baeldung/dip/daoimplementations/SimpleCustomerDao.java new file mode 100644 index 0000000000..ef6482ecc7 --- /dev/null +++ b/patterns/dipmodular/com.baeldung.dip.daoimplementations/com/baeldung/dip/daoimplementations/SimpleCustomerDao.java @@ -0,0 +1,30 @@ +package com.baeldung.dip.daoimplementations; + +import com.baeldung.dip.daos.CustomerDao; +import com.baeldung.dip.entities.Customer; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +public class SimpleCustomerDao implements CustomerDao { + + private Map customers = new HashMap<>(); + + public SimpleCustomerDao() { + + } + + public SimpleCustomerDao(Map customers) { + this.customers = customers; + } + + @Override + public Optional findById(int id) { + return Optional.ofNullable(customers.get(id)); + } + + @Override + public List findAll() { + return new ArrayList<>(customers.values()); + } +} diff --git a/patterns/dipmodular/com.baeldung.dip.daoimplementations/module-info.java b/patterns/dipmodular/com.baeldung.dip.daoimplementations/module-info.java new file mode 100644 index 0000000000..1df40ce3b8 --- /dev/null +++ b/patterns/dipmodular/com.baeldung.dip.daoimplementations/module-info.java @@ -0,0 +1,6 @@ +module com.baeldung.dip.daoimplementations { + requires com.baeldung.dip.entities; + requires com.baeldung.dip.daos; + provides com.baeldung.dip.daos.CustomerDao with com.baeldung.dip.daoimplementations.SimpleCustomerDao; + exports com.baeldung.dip.daoimplementations; +} diff --git a/patterns/dipmodular/com.baeldung.dip.daos/com/baeldung/dip/daos/CustomerDao.java b/patterns/dipmodular/com.baeldung.dip.daos/com/baeldung/dip/daos/CustomerDao.java new file mode 100644 index 0000000000..b0080dd15e --- /dev/null +++ b/patterns/dipmodular/com.baeldung.dip.daos/com/baeldung/dip/daos/CustomerDao.java @@ -0,0 +1,13 @@ +package com.baeldung.dip.daos; + +import com.baeldung.dip.entities.Customer; +import java.util.Map; +import java.util.Optional; + +public interface CustomerDao { + + Optional findById(int id); + + List findAll(); + +} diff --git a/patterns/dipmodular/com.baeldung.dip.daos/module-info.java b/patterns/dipmodular/com.baeldung.dip.daos/module-info.java new file mode 100644 index 0000000000..897c6168a1 --- /dev/null +++ b/patterns/dipmodular/com.baeldung.dip.daos/module-info.java @@ -0,0 +1,4 @@ +module com.baeldung.dip.daos { + requires com.baeldung.dip.entities; + exports com.baeldung.dip.daos; +} diff --git a/patterns/dipmodular/com.baeldung.dip.entities/com/baeldung/dip/entities/Customer.java b/patterns/dipmodular/com.baeldung.dip.entities/com/baeldung/dip/entities/Customer.java new file mode 100644 index 0000000000..f8d5d82102 --- /dev/null +++ b/patterns/dipmodular/com.baeldung.dip.entities/com/baeldung/dip/entities/Customer.java @@ -0,0 +1,19 @@ +package com.baeldung.dip.entities; + +public class Customer { + + private final String name; + + public Customer(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + @Override + public String toString() { + return "Customer{" + "name=" + name + '}'; + } +} diff --git a/patterns/dipmodular/com.baeldung.dip.entities/module-info.java b/patterns/dipmodular/com.baeldung.dip.entities/module-info.java new file mode 100644 index 0000000000..da8c1ccaee --- /dev/null +++ b/patterns/dipmodular/com.baeldung.dip.entities/module-info.java @@ -0,0 +1,3 @@ +module com.baeldung.dip.entities { + exports com.baeldung.dip.entities; +} diff --git a/patterns/dipmodular/com.baeldung.dip.mainapp/com/baeldung/dip/mainapp/MainApplication.java b/patterns/dipmodular/com.baeldung.dip.mainapp/com/baeldung/dip/mainapp/MainApplication.java new file mode 100644 index 0000000000..8972dc3994 --- /dev/null +++ b/patterns/dipmodular/com.baeldung.dip.mainapp/com/baeldung/dip/mainapp/MainApplication.java @@ -0,0 +1,17 @@ +package com.baeldung.dip.mainapp; + +import com.baeldung.dip.daoimplementations.MapCustomerDao; +import com.baeldung.dip.entities.Customer; +import com.baeldung.dip.services.CustomerService; +import java.util.HashMap; + +public class MainApplication { + + public static void main(String args[]) { + var customers = new HashMap(); + customers.put(1, new Customer("John")); + customers.put(2, new Customer("Susan")); + CustomerService customerService = new CustomerService(new SimpleCustomerDao(customers)); + customerService.findAll().forEach(System.out::println); + } +} diff --git a/patterns/dipmodular/com.baeldung.dip.mainapp/module-info.java b/patterns/dipmodular/com.baeldung.dip.mainapp/module-info.java new file mode 100644 index 0000000000..466306334a --- /dev/null +++ b/patterns/dipmodular/com.baeldung.dip.mainapp/module-info.java @@ -0,0 +1,7 @@ +module com.baeldung.dip.mainapp { + requires com.baeldung.dip.entities; + requires com.baeldung.dip.daos; + requires com.baeldung.dip.daoimplementations; + requires com.baeldung.dip.services; + exports com.baeldung.dip.mainapp; +} diff --git a/patterns/dipmodular/com.baeldung.dip.services/com/baeldung/dip/services/CustomerService.java b/patterns/dipmodular/com.baeldung.dip.services/com/baeldung/dip/services/CustomerService.java new file mode 100644 index 0000000000..39955abdaf --- /dev/null +++ b/patterns/dipmodular/com.baeldung.dip.services/com/baeldung/dip/services/CustomerService.java @@ -0,0 +1,23 @@ +package com.baeldung.dip.services; + +import com.baeldung.dip.daos.CustomerDao; +import com.baeldung.dip.entities.Customer; +import java.util.Map; +import java.util.Optional; + +public class CustomerService { + + private final CustomerDao customerDao; + + public CustomerService(CustomerDao customerDao) { + this.customerDao = customerDao; + } + + public Optional findById(int id) { + return customerDao.findById(id); + } + + public List findAll() { + return customerDao.findAll(); + } +} diff --git a/patterns/dipmodular/com.baeldung.dip.services/module-info.java b/patterns/dipmodular/com.baeldung.dip.services/module-info.java new file mode 100644 index 0000000000..8e59cd7abe --- /dev/null +++ b/patterns/dipmodular/com.baeldung.dip.services/module-info.java @@ -0,0 +1,6 @@ +module com.baeldung.dip.services { + requires com.baeldung.dip.entities; + requires com.baeldung.dip.daos; + uses com.baeldung.dip.daos.CustomerDao; + exports com.baeldung.dip.services; +} diff --git a/patterns/pom.xml b/patterns/pom.xml index 111e72b9ca..bf302a7a74 100644 --- a/patterns/pom.xml +++ b/patterns/pom.xml @@ -1,10 +1,10 @@ + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 patterns pom - patterns + patterns com.baeldung @@ -19,6 +19,7 @@ design-patterns design-patterns-2 solid + dip @@ -55,4 +56,4 @@ 9.4.0.v20161208 - \ No newline at end of file + diff --git a/patterns/principles/solid/README.md b/patterns/principles/solid/README.md index e2d72ecd28..ddd2f78b7e 100644 --- a/patterns/principles/solid/README.md +++ b/patterns/principles/solid/README.md @@ -1,5 +1,5 @@ ### Relevant Articles: -- [A Guide to Solid Principles](https://www.baeldung.com/solid-principles) +- [A Solid Guide to Solid Principles](https://www.baeldung.com/solid-principles) diff --git a/patterns/solid/pom.xml b/patterns/solid/pom.xml index 146a9903cf..faf8bdc8d9 100644 --- a/patterns/solid/pom.xml +++ b/patterns/solid/pom.xml @@ -8,7 +8,7 @@ solid 1.0-SNAPSHOT - + com.baeldung patterns 1.0.0-SNAPSHOT diff --git a/persistence-modules/README.md b/persistence-modules/README.md index 87dc9522fd..2fbaf25f2f 100644 --- a/persistence-modules/README.md +++ b/persistence-modules/README.md @@ -11,3 +11,5 @@ - [Pessimistic Locking in JPA](http://www.baeldung.com/jpa-pessimistic-locking) - [Get All Data from a Table with Hibernate](https://www.baeldung.com/hibernate-select-all) - [Spring Data with Reactive Cassandra](https://www.baeldung.com/spring-data-cassandra-reactive) +- [Spring Data JPA – Derived Delete Methods](https://www.baeldung.com/spring-data-jpa-deleteby) +- [Difference Between save() and saveAndFlush() in Spring Data JPA](https://www.baeldung.com/spring-data-jpa-save-saveandflush) diff --git a/persistence-modules/core-java-persistence/README.md b/persistence-modules/core-java-persistence/README.md index ca0ce81eef..26bd4bf00f 100644 --- a/persistence-modules/core-java-persistence/README.md +++ b/persistence-modules/core-java-persistence/README.md @@ -7,3 +7,4 @@ - [Batch Processing in JDBC](http://www.baeldung.com/jdbc-batch-processing) - [Introduction to the JDBC RowSet Interface in Java](http://www.baeldung.com/java-jdbc-rowset) - [A Simple Guide to Connection Pooling in Java](https://www.baeldung.com/java-connection-pooling) +- [Guide to the JDBC ResultSet Interface](https://www.baeldung.com/jdbc-resultset) diff --git a/persistence-modules/core-java-persistence/pom.xml b/persistence-modules/core-java-persistence/pom.xml index a777eeb73f..2ad2083fec 100644 --- a/persistence-modules/core-java-persistence/pom.xml +++ b/persistence-modules/core-java-persistence/pom.xml @@ -6,15 +6,21 @@ 0.1.0-SNAPSHOT core-java-persistence jar - + com.baeldung parent-java 0.0.1-SNAPSHOT ../../parent-java - + + + org.postgresql + postgresql + ${postgresql.version} + test + org.assertj assertj-core @@ -52,7 +58,7 @@ ${springframework.boot.spring-boot-starter.version} - + core-java-persistence @@ -62,8 +68,10 @@ - + + 42.2.5.jre7 + 8.0.15 3.10.0 1.4.197 2.4.0 @@ -72,5 +80,5 @@ 1.5.8.RELEASE 4.3.4.RELEASE - + \ No newline at end of file diff --git a/persistence-modules/core-java-persistence/src/main/java/com/baeldung/jdbc/Employee.java b/persistence-modules/core-java-persistence/src/main/java/com/baeldung/jdbc/Employee.java index 749855ca3b..27aef8b82f 100644 --- a/persistence-modules/core-java-persistence/src/main/java/com/baeldung/jdbc/Employee.java +++ b/persistence-modules/core-java-persistence/src/main/java/com/baeldung/jdbc/Employee.java @@ -1,5 +1,7 @@ package com.baeldung.jdbc; +import java.util.Objects; + public class Employee { private int id; private String name; @@ -48,4 +50,21 @@ public class Employee { this.position = position; } + @Override + public int hashCode() { + return Objects.hash(id, name, position, salary); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Employee other = (Employee) obj; + return id == other.id && Objects.equals(name, other.name) && Objects.equals(position, other.position) && Double.doubleToLongBits(salary) == Double.doubleToLongBits(other.salary); + } + } diff --git a/persistence-modules/core-java-persistence/src/main/java/com/baeldung/jdbc/joins/ArticleWithAuthor.java b/persistence-modules/core-java-persistence/src/main/java/com/baeldung/jdbc/joins/ArticleWithAuthor.java new file mode 100644 index 0000000000..5ce196ee47 --- /dev/null +++ b/persistence-modules/core-java-persistence/src/main/java/com/baeldung/jdbc/joins/ArticleWithAuthor.java @@ -0,0 +1,41 @@ +package com.baeldung.jdbc.joins; + +class ArticleWithAuthor { + + private String title; + + private String authorFirstName; + + private String authorLastName; + + public ArticleWithAuthor(String title, String authorFirstName, String authorLastName) { + this.title = title; + this.authorFirstName = authorFirstName; + this.authorLastName = authorLastName; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getAuthorFirstName() { + return authorFirstName; + } + + public void setAuthorFirstName(String authorFirstName) { + this.authorFirstName = authorFirstName; + } + + public String getAuthorLastName() { + return authorLastName; + } + + public void setAuthorLastName(String authorLastName) { + this.authorLastName = authorLastName; + } + +} diff --git a/persistence-modules/core-java-persistence/src/main/java/com/baeldung/jdbc/joins/ArticleWithAuthorDAO.java b/persistence-modules/core-java-persistence/src/main/java/com/baeldung/jdbc/joins/ArticleWithAuthorDAO.java new file mode 100644 index 0000000000..55f03d99ec --- /dev/null +++ b/persistence-modules/core-java-persistence/src/main/java/com/baeldung/jdbc/joins/ArticleWithAuthorDAO.java @@ -0,0 +1,61 @@ +package com.baeldung.jdbc.joins; + +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.List; + +class ArticleWithAuthorDAO { + + private static final String QUERY_TEMPLATE = "SELECT ARTICLE.TITLE, AUTHOR.LAST_NAME, AUTHOR.FIRST_NAME FROM ARTICLE %s AUTHOR ON AUTHOR.id=ARTICLE.AUTHOR_ID"; + private final Connection connection; + + ArticleWithAuthorDAO(Connection connection) { + this.connection = connection; + } + + List articleInnerJoinAuthor() { + String query = String.format(QUERY_TEMPLATE, "INNER JOIN"); + return executeQuery(query); + } + + List articleLeftJoinAuthor() { + String query = String.format(QUERY_TEMPLATE, "LEFT JOIN"); + return executeQuery(query); + } + + List articleRightJoinAuthor() { + String query = String.format(QUERY_TEMPLATE, "RIGHT JOIN"); + return executeQuery(query); + } + + List articleFullJoinAuthor() { + String query = String.format(QUERY_TEMPLATE, "FULL JOIN"); + return executeQuery(query); + } + + private List executeQuery(String query) { + try (Statement statement = connection.createStatement()) { + ResultSet resultSet = statement.executeQuery(query); + return mapToList(resultSet); + } catch (SQLException e) { + e.printStackTrace(); + } + return null; + } + + private List mapToList(ResultSet resultSet) throws SQLException { + List list = new ArrayList<>(); + while (resultSet.next()) { + ArticleWithAuthor articleWithAuthor = new ArticleWithAuthor( + resultSet.getString("TITLE"), + resultSet.getString("FIRST_NAME"), + resultSet.getString("LAST_NAME") + ); + list.add(articleWithAuthor); + } + return list; + } +} diff --git a/persistence-modules/core-java-persistence/src/test/java/com/baeldung/jdbc/ResultSetLiveTest.java b/persistence-modules/core-java-persistence/src/test/java/com/baeldung/jdbc/ResultSetLiveTest.java new file mode 100644 index 0000000000..4e10f8bd43 --- /dev/null +++ b/persistence-modules/core-java-persistence/src/test/java/com/baeldung/jdbc/ResultSetLiveTest.java @@ -0,0 +1,359 @@ +package com.baeldung.jdbc; + +import static org.junit.Assert.assertEquals; + +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +import junit.framework.Assert; + +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class ResultSetLiveTest { + + private static final Logger logger = Logger.getLogger(ResultSetLiveTest.class); + + private final Employee expectedEmployee1 = new Employee(1, "John", 1000.0, "Developer"); + + private final Employee updatedEmployee1 = new Employee(1, "John", 1100.0, "Developer"); + + private final Employee expectedEmployee2 = new Employee(2, "Chris", 925.0, "DBA"); + + private final int rowCount = 2; + + private static Connection dbConnection; + + @BeforeClass + public static void setup() throws ClassNotFoundException, SQLException { + Class.forName("com.mysql.cj.jdbc.Driver"); + dbConnection = DriverManager.getConnection("jdbc:mysql://localhost:3306/myDB?noAccessToProcedureBodies=true", "user1", "pass"); + String tableSql = "CREATE TABLE IF NOT EXISTS employees (emp_id int PRIMARY KEY AUTO_INCREMENT, name varchar(30), position varchar(30), salary double)"; + try (Statement stmt = dbConnection.createStatement()) { + stmt.execute(tableSql); + try (PreparedStatement pstmt = dbConnection.prepareStatement("INSERT INTO employees(name, position, salary) values ('John', 'Developer', 1000.0)")) { + pstmt.executeUpdate(); + } + } + } + + @Test + public void givenDbConnectionA_whenRetreiveByColumnNames_thenCorrect() throws SQLException { + Employee employee = null; + try (PreparedStatement pstmt = dbConnection.prepareStatement("select * from employees"); ResultSet rs = pstmt.executeQuery()) { + while (rs.next()) { + String name = rs.getString("name"); + Integer empId = rs.getInt("emp_id"); + Double salary = rs.getDouble("salary"); + String position = rs.getString("position"); + employee = new Employee(empId, name, salary, position); + } + } + + assertEquals("Employee information retreived by column names.", expectedEmployee1, employee); + } + + @Test + public void givenDbConnectionB_whenRetreiveByColumnIds_thenCorrect() throws SQLException { + Employee employee = null; + try (PreparedStatement pstmt = dbConnection.prepareStatement("select * from employees"); ResultSet rs = pstmt.executeQuery()) { + while (rs.next()) { + Integer empId = rs.getInt(1); + String name = rs.getString(2); + String position = rs.getString(3); + Double salary = rs.getDouble(4); + employee = new Employee(empId, name, salary, position); + } + } + + assertEquals("Employee information retreived by column ids.", expectedEmployee1, employee); + } + + @Test + public void givenDbConnectionD_whenInsertRow_thenCorrect() throws SQLException { + int rowCount = 0; + try (PreparedStatement pstmt = dbConnection.prepareStatement("select * from employees", ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); ResultSet rs = pstmt.executeQuery()) { + rs.moveToInsertRow(); + rs.updateString("name", "Chris"); + rs.updateString("position", "DBA"); + rs.updateDouble("salary", 925.0); + rs.insertRow(); + rs.moveToCurrentRow(); + rs.last(); + rowCount = rs.getRow(); + } + + assertEquals("Row Count after inserting a row", 2, rowCount); + } + + private Employee populateResultSet(ResultSet rs) throws SQLException { + Employee employee; + String name = rs.getString("name"); + Integer empId = rs.getInt("emp_id"); + Double salary = rs.getDouble("salary"); + String position = rs.getString("position"); + employee = new Employee(empId, name, salary, position); + return employee; + } + + @Test + public void givenDbConnectionE_whenRowCount_thenCorrect() throws SQLException { + int numOfRows = 0; + try (PreparedStatement pstmt = dbConnection.prepareStatement("select * from employees", ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); ResultSet rs = pstmt.executeQuery()) { + rs.last(); + numOfRows = rs.getRow(); + } + + assertEquals("Num of rows", rowCount, numOfRows); + } + + @Test + public void givenDbConnectionG_whenAbsoluteNavigation_thenCorrect() throws SQLException { + Employee secondEmployee = null; + try (PreparedStatement pstmt = dbConnection.prepareStatement("select * from employees", ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); ResultSet rs = pstmt.executeQuery()) { + rs.absolute(2); + secondEmployee = populateResultSet(rs); + } + + assertEquals("Absolute navigation", expectedEmployee2, secondEmployee); + } + + @Test + public void givenDbConnectionH_whenLastNavigation_thenCorrect() throws SQLException { + Employee secondEmployee = null; + try (PreparedStatement pstmt = dbConnection.prepareStatement("select * from employees", ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); ResultSet rs = pstmt.executeQuery()) { + rs.last(); + secondEmployee = populateResultSet(rs); + } + + assertEquals("Using Last", expectedEmployee2, secondEmployee); + } + + @Test + public void givenDbConnectionI_whenNavigation_thenCorrect() throws SQLException { + Employee firstEmployee = null; + try (PreparedStatement pstmt = dbConnection.prepareStatement("select * from employees", ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); ResultSet rs = pstmt.executeQuery()) { + while (rs.next()) { + Employee employee = populateResultSet(rs); + } + rs.beforeFirst(); + while (rs.next()) { + Employee employee = populateResultSet(rs); + } + rs.first(); + while (rs.next()) { + Employee employee = populateResultSet(rs); + } + while (rs.previous()) { + Employee employee = populateResultSet(rs); + } + rs.afterLast(); + while (rs.previous()) { + Employee employee = populateResultSet(rs); + } + rs.last(); + while (rs.previous()) { + firstEmployee = populateResultSet(rs); + } + } + + assertEquals("Several Navigation Options", updatedEmployee1, firstEmployee); + } + + @Test + public void givenDbConnectionJ_whenClosedCursor_thenCorrect() throws SQLException { + Employee employee = null; + dbConnection.setHoldability(ResultSet.CLOSE_CURSORS_AT_COMMIT); + try (Statement pstmt = dbConnection.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE, ResultSet.CLOSE_CURSORS_AT_COMMIT)) { + dbConnection.setAutoCommit(false); + ResultSet rs = pstmt.executeQuery("select * from employees"); + while (rs.next()) { + if (rs.getString("name") + .equalsIgnoreCase("john")) { + rs.updateString("position", "Senior Engineer"); + rs.updateRow(); + dbConnection.commit(); + employee = populateResultSet(rs); + } + } + rs.last(); + } + + assertEquals("Update using closed cursor", "Senior Engineer", employee.getPosition()); + } + + @Test + public void givenDbConnectionK_whenUpdate_thenCorrect() throws SQLException { + Employee employee = null; + dbConnection.setHoldability(ResultSet.HOLD_CURSORS_OVER_COMMIT); + try (Statement pstmt = dbConnection.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE, ResultSet.HOLD_CURSORS_OVER_COMMIT)) { + dbConnection.setAutoCommit(false); + ResultSet rs = pstmt.executeQuery("select * from employees"); + while (rs.next()) { + if (rs.getString("name") + .equalsIgnoreCase("john")) { + rs.updateString("name", "John Doe"); + rs.updateRow(); + dbConnection.commit(); + employee = populateResultSet(rs); + } + } + rs.last(); + } + + assertEquals("Update using open cursor", "John Doe", employee.getName()); + } + + @Test + public void givenDbConnectionM_whenDelete_thenCorrect() throws SQLException { + int numOfRows = 0; + try (PreparedStatement pstmt = dbConnection.prepareStatement("select * from employees", ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); ResultSet rs = pstmt.executeQuery()) { + rs.absolute(2); + rs.deleteRow(); + } + try (PreparedStatement pstmt = dbConnection.prepareStatement("select * from employees", ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); ResultSet rs = pstmt.executeQuery()) { + rs.last(); + numOfRows = rs.getRow(); + } + assertEquals("Deleted row", 1, numOfRows); + } + + @Test + public void givenDbConnectionC_whenUpdate_thenCorrect() throws SQLException { + Employee employee = null; + try (PreparedStatement pstmt = dbConnection.prepareStatement("select * from employees", ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); ResultSet rs = pstmt.executeQuery()) { + while (rs.next()) { + + Assert.assertEquals(1100.0, rs.getDouble("salary")); + + rs.updateDouble("salary", 1200.0); + rs.updateRow(); + + Assert.assertEquals(1200.0, rs.getDouble("salary")); + + String name = rs.getString("name"); + Integer empId = rs.getInt("emp_id"); + Double salary = rs.getDouble("salary"); + String position = rs.getString("position"); + employee = new Employee(empId, name, salary, position); + } + } + } + + @Test + public void givenDbConnectionC_whenUpdateByIndex_thenCorrect() throws SQLException { + Employee employee = null; + try (PreparedStatement pstmt = dbConnection.prepareStatement("select * from employees", ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); ResultSet rs = pstmt.executeQuery()) { + while (rs.next()) { + + Assert.assertEquals(1000.0, rs.getDouble(4)); + + rs.updateDouble(4, 1100.0); + rs.updateRow(); + Assert.assertEquals(1100.0, rs.getDouble(4)); + + String name = rs.getString("name"); + Integer empId = rs.getInt("emp_id"); + Double salary = rs.getDouble("salary"); + String position = rs.getString("position"); + employee = new Employee(empId, name, salary, position); + } + } + } + + @Test + public void givenDbConnectionE_whenDBMetaInfo_thenCorrect() throws SQLException { + DatabaseMetaData dbmd = dbConnection.getMetaData(); + boolean supportsTypeForward = dbmd.supportsResultSetType(ResultSet.TYPE_FORWARD_ONLY); + boolean supportsTypeScrollSensitive = dbmd.supportsResultSetType(ResultSet.TYPE_SCROLL_SENSITIVE); + boolean supportsTypeScrollInSensitive = dbmd.supportsResultSetType(ResultSet.TYPE_SCROLL_INSENSITIVE); + boolean supportsCloseCursorsAtCommit = dbmd.supportsResultSetHoldability(ResultSet.CLOSE_CURSORS_AT_COMMIT); + boolean supportsHoldCursorsAtCommit = dbmd.supportsResultSetHoldability(ResultSet.HOLD_CURSORS_OVER_COMMIT); + boolean concurrency4TypeFwdNConcurReadOnly = dbmd.supportsResultSetConcurrency(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); + boolean concurrency4TypeFwdNConcurUpdatable = dbmd.supportsResultSetConcurrency(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE); + boolean concurrency4TypeScrollInSensitiveNConcurUpdatable = dbmd.supportsResultSetConcurrency(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE); + boolean concurrency4TypeScrollInSensitiveNConcurReadOnly = dbmd.supportsResultSetConcurrency(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); + boolean concurrency4TypeScrollSensitiveNConcurUpdatable = dbmd.supportsResultSetConcurrency(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); + boolean concurrency4TypeScrollSensitiveNConcurReadOnly = dbmd.supportsResultSetConcurrency(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY); + int rsHoldability = dbmd.getResultSetHoldability(); + + assertEquals("checking scroll sensitivity and concur updates : ", true, concurrency4TypeScrollInSensitiveNConcurUpdatable); + } + + @Test + public void givenDbConnectionF_whenRSMetaInfo_thenCorrect() throws SQLException { + int columnCount = 0; + try (PreparedStatement pstmt = dbConnection.prepareStatement("select * from employees", ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); ResultSet rs = pstmt.executeQuery()) { + ResultSetMetaData metaData = rs.getMetaData(); + columnCount = metaData.getColumnCount(); + for (int i = 1; i <= columnCount; i++) { + String catalogName = metaData.getCatalogName(i); + String className = metaData.getColumnClassName(i); + String label = metaData.getColumnLabel(i); + String name = metaData.getColumnName(i); + String typeName = metaData.getColumnTypeName(i); + Integer type = metaData.getColumnType(i); + String tableName = metaData.getTableName(i); + String schemaName = metaData.getSchemaName(i); + boolean isAutoIncrement = metaData.isAutoIncrement(i); + boolean isCaseSensitive = metaData.isCaseSensitive(i); + boolean isCurrency = metaData.isCurrency(i); + boolean isDefiniteWritable = metaData.isDefinitelyWritable(i); + boolean isReadOnly = metaData.isReadOnly(i); + boolean isSearchable = metaData.isSearchable(i); + boolean isReadable = metaData.isReadOnly(i); + boolean isSigned = metaData.isSigned(i); + boolean isWritable = metaData.isWritable(i); + int nullable = metaData.isNullable(i); + } + } + + assertEquals("column count", 4, columnCount); + } + + @Test + public void givenDbConnectionL_whenFetch_thenCorrect() throws SQLException { + PreparedStatement pstmt = null; + ResultSet rs = null; + List listOfEmployees = new ArrayList(); + try { + pstmt = dbConnection.prepareStatement("select * from employees", ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); + pstmt.setFetchSize(1); + rs = pstmt.executeQuery(); + rs.setFetchSize(1); + while (rs.next()) { + Employee employee = populateResultSet(rs); + listOfEmployees.add(employee); + } + } catch (Exception e) { + throw e; + } finally { + if (rs != null) + rs.close(); + if (pstmt != null) + pstmt.close(); + } + + assertEquals(2, listOfEmployees.size()); + } + + @AfterClass + public static void closeConnection() throws SQLException { + PreparedStatement deleteStmt = dbConnection.prepareStatement("drop table employees", ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE); + deleteStmt.execute(); + dbConnection.close(); + } +} \ No newline at end of file diff --git a/persistence-modules/core-java-persistence/src/test/java/com/baeldung/jdbc/joins/ArticleWithAuthorDAOIntegrationTest.java b/persistence-modules/core-java-persistence/src/test/java/com/baeldung/jdbc/joins/ArticleWithAuthorDAOIntegrationTest.java new file mode 100644 index 0000000000..5c20b6bf1e --- /dev/null +++ b/persistence-modules/core-java-persistence/src/test/java/com/baeldung/jdbc/joins/ArticleWithAuthorDAOIntegrationTest.java @@ -0,0 +1,89 @@ +package com.baeldung.jdbc.joins; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ArticleWithAuthorDAOIntegrationTest { + private Connection connection; + + private ArticleWithAuthorDAO articleWithAuthorDAO; + + @Before + public void setup() throws ClassNotFoundException, SQLException { + Class.forName("org.postgresql.Driver"); + connection = DriverManager.getConnection("jdbc:postgresql://localhost:5432/myDb", "user", "pass"); + articleWithAuthorDAO = new ArticleWithAuthorDAO(connection); + Statement statement = connection.createStatement(); + String createAuthorSql = "CREATE TABLE IF NOT EXISTS AUTHOR (ID int NOT NULL PRIMARY KEY, FIRST_NAME varchar(255), LAST_NAME varchar(255));"; + String createArticleSql = "CREATE TABLE IF NOT EXISTS ARTICLE (ID int NOT NULL PRIMARY KEY, TITLE varchar(255) NOT NULL, AUTHOR_ID int, FOREIGN KEY(AUTHOR_ID) REFERENCES AUTHOR(ID));"; + statement.execute(createAuthorSql); + statement.execute(createArticleSql); + + insertTestData(statement); + } + + @Test + public void whenQueryWithInnerJoin_thenShouldReturnProperRows() { + List articleWithAuthorList = articleWithAuthorDAO.articleInnerJoinAuthor(); + + assertThat(articleWithAuthorList).hasSize(4); + assertThat(articleWithAuthorList).noneMatch(row -> row.getAuthorFirstName() == null || row.getTitle() == null); + } + + @Test + public void whenQueryWithLeftJoin_thenShouldReturnProperRows() { + List articleWithAuthorList = articleWithAuthorDAO.articleLeftJoinAuthor(); + + assertThat(articleWithAuthorList).hasSize(5); + assertThat(articleWithAuthorList).anyMatch(row -> row.getAuthorFirstName() == null); + } + + @Test + public void whenQueryWithRightJoin_thenShouldReturnProperRows() { + List articleWithAuthorList = articleWithAuthorDAO.articleRightJoinAuthor(); + + assertThat(articleWithAuthorList).hasSize(5); + assertThat(articleWithAuthorList).anyMatch(row -> row.getTitle() == null); + } + + @Test + public void whenQueryWithFullJoin_thenShouldReturnProperRows() { + List articleWithAuthorList = articleWithAuthorDAO.articleFullJoinAuthor(); + + assertThat(articleWithAuthorList).hasSize(6); + assertThat(articleWithAuthorList).anyMatch(row -> row.getTitle() == null); + assertThat(articleWithAuthorList).anyMatch(row -> row.getAuthorFirstName() == null); + } + + @After + public void cleanup() throws SQLException { + connection.createStatement().execute("DROP TABLE ARTICLE"); + connection.createStatement().execute("DROP TABLE AUTHOR"); + connection.close(); + } + + public void insertTestData(Statement statement) throws SQLException { + String insertAuthors = "INSERT INTO AUTHOR VALUES " + + "(1, 'Siena', 'Kerr')," + + "(2, 'Daniele', 'Ferguson')," + + "(3, 'Luciano', 'Wise')," + + "(4, 'Jonas', 'Lugo');"; + String insertArticles = "INSERT INTO ARTICLE VALUES " + + "(1, 'First steps in Java', 1)," + + "(2, 'SpringBoot tutorial', 1)," + + "(3, 'Java 12 insights', null)," + + "(4, 'SQL JOINS', 2)," + + "(5, 'Introduction to Spring Security', 3);"; + statement.execute(insertAuthors); + statement.execute(insertArticles); + } +} diff --git a/persistence-modules/hibernate-mapping/pom.xml b/persistence-modules/hibernate-mapping/pom.xml new file mode 100644 index 0000000000..fdc82a5275 --- /dev/null +++ b/persistence-modules/hibernate-mapping/pom.xml @@ -0,0 +1,71 @@ + + + + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + ../../ + + + hibernate-mapping + 1.0.0-SNAPSHOT + 4.0.0 + + + + org.hibernate + hibernate-core + ${hibernate.version} + + + org.assertj + assertj-core + ${assertj-core.version} + test + + + com.h2database + h2 + ${h2database.version} + + + + org.hibernate + hibernate-validator + ${hibernate-validator.version} + + + javax.el + javax.el-api + ${javax.el-api.version} + + + org.glassfish + javax.el + ${org.glassfish.javax.el.version} + + + + + hibernate-mapping + + + src/test/resources + true + + + + + + 5.3.7.Final + 1.4.196 + 3.8.0 + 5.3.3.Final + 2.2.5 + 3.0.1-b08 + + + \ No newline at end of file diff --git a/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/HibernateUtil.java b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/HibernateUtil.java new file mode 100644 index 0000000000..7411edd225 --- /dev/null +++ b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/HibernateUtil.java @@ -0,0 +1,64 @@ +package com.baeldung.hibernate; + +import org.hibernate.SessionFactory; +import org.hibernate.boot.Metadata; +import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.service.ServiceRegistry; + +import java.io.FileInputStream; +import java.io.IOException; +import java.net.URL; +import java.util.Properties; + +public class HibernateUtil { + private static SessionFactory sessionFactory; + + private HibernateUtil() { + } + + public static SessionFactory getSessionFactory(Strategy strategy) { + if (sessionFactory == null) { + sessionFactory = buildSessionFactory(strategy); + } + return sessionFactory; + } + + private static SessionFactory buildSessionFactory(Strategy strategy) { + try { + ServiceRegistry serviceRegistry = configureServiceRegistry(); + + MetadataSources metadataSources = new MetadataSources(serviceRegistry); + + for (Class entityClass : strategy.getEntityClasses()) { + metadataSources.addAnnotatedClass(entityClass); + } + + Metadata metadata = metadataSources.getMetadataBuilder() + .build(); + + return metadata.getSessionFactoryBuilder() + .build(); + } catch (IOException ex) { + throw new ExceptionInInitializerError(ex); + } + } + + + private static ServiceRegistry configureServiceRegistry() throws IOException { + Properties properties = getProperties(); + return new StandardServiceRegistryBuilder().applySettings(properties) + .build(); + } + + private static Properties getProperties() throws IOException { + Properties properties = new Properties(); + URL propertiesURL = Thread.currentThread() + .getContextClassLoader() + .getResource("hibernate.properties"); + try (FileInputStream inputStream = new FileInputStream(propertiesURL.getFile())) { + properties.load(inputStream); + } + return properties; + } +} diff --git a/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/Strategy.java b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/Strategy.java new file mode 100644 index 0000000000..78434fd2a2 --- /dev/null +++ b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/Strategy.java @@ -0,0 +1,31 @@ +package com.baeldung.hibernate; + + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public enum Strategy { + //See that the classes belongs to different packages + MAP_KEY_COLUMN_BASED(Collections.singletonList(com.baeldung.hibernate.persistmaps.mapkeycolumn.Order.class)), + MAP_KEY_BASED(Arrays.asList(com.baeldung.hibernate.persistmaps.mapkey.Item.class, + com.baeldung.hibernate.persistmaps.mapkey.Order.class,com.baeldung.hibernate.persistmaps.mapkey.User.class)), + MAP_KEY_JOIN_COLUMN_BASED(Arrays.asList(com.baeldung.hibernate.persistmaps.mapkeyjoincolumn.Seller.class, + com.baeldung.hibernate.persistmaps.mapkeyjoincolumn.Item.class, + com.baeldung.hibernate.persistmaps.mapkeyjoincolumn.Order.class)), + MAP_KEY_ENUMERATED_BASED(Arrays.asList(com.baeldung.hibernate.persistmaps.mapkeyenumerated.Order.class, + com.baeldung.hibernate.persistmaps.mapkey.Item.class)), + MAP_KEY_TEMPORAL_BASED(Arrays.asList(com.baeldung.hibernate.persistmaps.mapkeytemporal.Order.class, + com.baeldung.hibernate.persistmaps.mapkey.Item.class)); + + + private List> entityClasses; + + Strategy(List> entityClasses) { + this.entityClasses = entityClasses; + } + + public List> getEntityClasses() { + return entityClasses; + } +} diff --git a/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/persistmaps/ItemType.java b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/persistmaps/ItemType.java new file mode 100644 index 0000000000..b7f3cef9a2 --- /dev/null +++ b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/persistmaps/ItemType.java @@ -0,0 +1,6 @@ +package com.baeldung.hibernate.persistmaps; + +public enum ItemType { + JEANS, + TSHIRTS +} diff --git a/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/persistmaps/mapkey/Item.java b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/persistmaps/mapkey/Item.java new file mode 100644 index 0000000000..385ffe93ea --- /dev/null +++ b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/persistmaps/mapkey/Item.java @@ -0,0 +1,95 @@ +package com.baeldung.hibernate.persistmaps.mapkey; + +import com.baeldung.hibernate.persistmaps.ItemType; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; +import java.util.Date; +import java.util.Objects; + +@Entity +@Table(name = "item") +public class Item { + @Id + @GeneratedValue + @Column(name = "id") + private int id; + + @Column(name = "name") + private String itemName; + + @Column(name = "price") + private double itemPrice; + + @Enumerated(EnumType.STRING) + @Column(name = "item_type") + private ItemType itemType; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "created_on") + private Date createdOn; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getItemName() { + return itemName; + } + + public void setItemName(String itemName) { + this.itemName = itemName; + } + + public double getItemPrice() { + return itemPrice; + } + + public void setItemPrice(double itemPrice) { + this.itemPrice = itemPrice; + } + + public ItemType getItemType() { + return itemType; + } + + public void setItemType(ItemType itemType) { + this.itemType = itemType; + } + + public Date getCreatedOn() { + return createdOn; + } + + public void setCreatedOn(Date createdOn) { + this.createdOn = createdOn; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Item item = (Item) o; + return id == item.id && + Double.compare(item.itemPrice, itemPrice) == 0 && + Objects.equals(itemName, item.itemName) && + itemType == item.itemType && + Objects.equals(createdOn, item.createdOn); + } + + @Override + public int hashCode() { + return Objects.hash(id, itemName, itemPrice, itemType, createdOn); + } +} diff --git a/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/persistmaps/mapkey/Order.java b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/persistmaps/mapkey/Order.java new file mode 100644 index 0000000000..8409cacd6b --- /dev/null +++ b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/persistmaps/mapkey/Order.java @@ -0,0 +1,44 @@ +package com.baeldung.hibernate.persistmaps.mapkey; + +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.JoinTable; +import javax.persistence.MapKey; +import javax.persistence.OneToMany; +import javax.persistence.Table; +import java.util.Map; + +@Entity +@Table(name = "orders") +public class Order { + @Id + @GeneratedValue + @Column(name = "id") + private int id; + + @OneToMany(cascade = CascadeType.ALL) + @JoinTable(name = "order_item_mapping", joinColumns = {@JoinColumn(name = "order_id", referencedColumnName = "id")}, + inverseJoinColumns = {@JoinColumn(name = "item_id", referencedColumnName = "id")}) + @MapKey(name = "itemName") + private Map itemMap; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public Map getItemMap() { + return itemMap; + } + + public void setItemMap(Map itemMap) { + this.itemMap = itemMap; + } +} \ No newline at end of file diff --git a/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/persistmaps/mapkey/User.java b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/persistmaps/mapkey/User.java new file mode 100644 index 0000000000..f6e8f1cdd6 --- /dev/null +++ b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/persistmaps/mapkey/User.java @@ -0,0 +1,66 @@ +package com.baeldung.hibernate.persistmaps.mapkey; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.validation.constraints.Size; + +import org.hibernate.validator.constraints.Length; + +@Entity +public class User { + @Id + @Column(length = 3) + private String firstName; + + @Size(min = 3, max = 15) + private String middleName; + + @Length(min = 3, max = 15) + private String lastName; + + @Column(length = 5) + @Size(min = 3, max = 5) + private String city; + + public User(String firstName, String middleName, String lastName, String city) { + super(); + this.firstName = firstName; + this.middleName = middleName; + this.lastName = lastName; + this.city = city; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getMiddleName() { + return middleName; + } + + public void setMiddleName(String middletName) { + this.middleName = middletName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + +} diff --git a/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/persistmaps/mapkeycolumn/Order.java b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/persistmaps/mapkeycolumn/Order.java new file mode 100644 index 0000000000..fa092060da --- /dev/null +++ b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/persistmaps/mapkeycolumn/Order.java @@ -0,0 +1,43 @@ +package com.baeldung.hibernate.persistmaps.mapkeycolumn; + +import javax.persistence.CollectionTable; +import javax.persistence.Column; +import javax.persistence.ElementCollection; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.MapKeyColumn; +import javax.persistence.Table; +import java.util.Map; + +@Entity +@Table(name = "orders") +public class Order { + @Id + @GeneratedValue + @Column(name = "id") + private int id; + + @ElementCollection + @CollectionTable(name = "order_item_mapping", joinColumns = {@JoinColumn(name = "order_id", referencedColumnName = "id")}) + @MapKeyColumn(name = "item_name") + @Column(name = "price") + private Map itemPriceMap; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public Map getItemPriceMap() { + return itemPriceMap; + } + + public void setItemPriceMap(Map itemPriceMap) { + this.itemPriceMap = itemPriceMap; + } +} \ No newline at end of file diff --git a/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/persistmaps/mapkeyenumerated/Order.java b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/persistmaps/mapkeyenumerated/Order.java new file mode 100644 index 0000000000..e1f62599b8 --- /dev/null +++ b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/persistmaps/mapkeyenumerated/Order.java @@ -0,0 +1,48 @@ +package com.baeldung.hibernate.persistmaps.mapkeyenumerated; + +import com.baeldung.hibernate.persistmaps.ItemType; +import com.baeldung.hibernate.persistmaps.mapkey.Item; + +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.JoinTable; +import javax.persistence.MapKeyEnumerated; +import javax.persistence.OneToMany; +import javax.persistence.Table; +import java.util.Map; + +@Entity +@Table(name = "orders") +public class Order { + @Id + @GeneratedValue + @Column(name = "id") + private int id; + + @OneToMany(cascade = CascadeType.ALL) + @JoinTable(name = "order_item_mapping", joinColumns = {@JoinColumn(name = "order_id", referencedColumnName = "id")}, + inverseJoinColumns = {@JoinColumn(name = "item_id", referencedColumnName = "id")}) + @MapKeyEnumerated(EnumType.STRING) + private Map itemMap; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public Map getItemMap() { + return itemMap; + } + + public void setItemMap(Map itemMap) { + this.itemMap = itemMap; + } +} diff --git a/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/persistmaps/mapkeyjoincolumn/Item.java b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/persistmaps/mapkeyjoincolumn/Item.java new file mode 100644 index 0000000000..97bbd5b539 --- /dev/null +++ b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/persistmaps/mapkeyjoincolumn/Item.java @@ -0,0 +1,112 @@ +package com.baeldung.hibernate.persistmaps.mapkeyjoincolumn; + +import com.baeldung.hibernate.persistmaps.ItemType; + +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; +import java.util.Date; +import java.util.Objects; + +@Entity +@Table(name = "item") +public class Item { + @Id + @GeneratedValue + @Column(name = "id") + private int id; + + @Column(name = "name") + private String itemName; + + @Column(name = "price") + private double itemPrice; + + @Column(name = "item_type") + @Enumerated(EnumType.STRING) + private ItemType itemType; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "created_on") + private Date createdOn; + + @ManyToOne(cascade = CascadeType.ALL) + @JoinColumn(name = "seller_id") + private Seller seller; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getItemName() { + return itemName; + } + + public void setItemName(String itemName) { + this.itemName = itemName; + } + + public double getItemPrice() { + return itemPrice; + } + + public void setItemPrice(double itemPrice) { + this.itemPrice = itemPrice; + } + + public ItemType getItemType() { + return itemType; + } + + public void setItemType(ItemType itemType) { + this.itemType = itemType; + } + + public Date getCreatedOn() { + return createdOn; + } + + public void setCreatedOn(Date createdOn) { + this.createdOn = createdOn; + } + + public Seller getSeller() { + return seller; + } + + public void setSeller(Seller seller) { + this.seller = seller; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Item item = (Item) o; + return id == item.id && + Double.compare(item.itemPrice, itemPrice) == 0 && + Objects.equals(itemName, item.itemName) && + itemType == item.itemType && + Objects.equals(createdOn, item.createdOn) && + Objects.equals(seller, item.seller); + } + + @Override + public int hashCode() { + + return Objects.hash(id, itemName, itemPrice, itemType, createdOn, seller); + } +} diff --git a/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/persistmaps/mapkeyjoincolumn/Order.java b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/persistmaps/mapkeyjoincolumn/Order.java new file mode 100644 index 0000000000..d680d84501 --- /dev/null +++ b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/persistmaps/mapkeyjoincolumn/Order.java @@ -0,0 +1,44 @@ +package com.baeldung.hibernate.persistmaps.mapkeyjoincolumn; + +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.JoinTable; +import javax.persistence.MapKeyJoinColumn; +import javax.persistence.OneToMany; +import javax.persistence.Table; +import java.util.Map; + +@Entity +@Table(name = "orders") +public class Order { + @Id + @GeneratedValue + @Column(name = "id") + private int id; + + @OneToMany(cascade = CascadeType.ALL) + @JoinTable(name = "order_item_mapping", joinColumns = {@JoinColumn(name = "order_id", referencedColumnName = "id")}, + inverseJoinColumns = {@JoinColumn(name = "item_id", referencedColumnName = "id")}) + @MapKeyJoinColumn(name = "seller_id") + private Map sellerItemMap; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public Map getSellerItemMap() { + return sellerItemMap; + } + + public void setSellerItemMap(Map sellerItemMap) { + this.sellerItemMap = sellerItemMap; + } +} \ No newline at end of file diff --git a/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/persistmaps/mapkeyjoincolumn/Seller.java b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/persistmaps/mapkeyjoincolumn/Seller.java new file mode 100644 index 0000000000..15b08e9fe6 --- /dev/null +++ b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/persistmaps/mapkeyjoincolumn/Seller.java @@ -0,0 +1,51 @@ +package com.baeldung.hibernate.persistmaps.mapkeyjoincolumn; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.Table; +import java.util.Objects; + +@Entity +@Table(name = "seller") +public class Seller { + + @Id + @GeneratedValue + @Column(name = "id") + private int id; + + @Column(name = "name") + private String sellerName; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getSellerName() { + return sellerName; + } + + public void setSellerName(String sellerName) { + this.sellerName = sellerName; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Seller seller = (Seller) o; + return Objects.equals(sellerName, seller.sellerName); + } + + @Override + public int hashCode() { + + return Objects.hash(sellerName); + } +} diff --git a/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/persistmaps/mapkeytemporal/Order.java b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/persistmaps/mapkeytemporal/Order.java new file mode 100644 index 0000000000..be602c1e9f --- /dev/null +++ b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/persistmaps/mapkeytemporal/Order.java @@ -0,0 +1,48 @@ +package com.baeldung.hibernate.persistmaps.mapkeytemporal; + +import com.baeldung.hibernate.persistmaps.mapkey.Item; + +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.JoinTable; +import javax.persistence.MapKeyTemporal; +import javax.persistence.OneToMany; +import javax.persistence.Table; +import javax.persistence.TemporalType; +import java.util.Date; +import java.util.Map; + +@Entity +@Table(name = "orders") +public class Order { + @Id + @GeneratedValue + @Column(name = "id") + private int id; + + @OneToMany(cascade = CascadeType.ALL) + @JoinTable(name = "order_item_mapping", joinColumns = {@JoinColumn(name = "order_id", referencedColumnName = "id")}, + inverseJoinColumns = {@JoinColumn(name = "item_id", referencedColumnName = "id")}) + @MapKeyTemporal(TemporalType.TIMESTAMP) + private Map itemMap; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public Map getItemMap() { + return itemMap; + } + + public void setItemMap(Map itemMap) { + this.itemMap = itemMap; + } +} diff --git a/persistence-modules/hibernate-mapping/src/main/resources/logback.xml b/persistence-modules/hibernate-mapping/src/main/resources/logback.xml new file mode 100644 index 0000000000..26beb6d5b4 --- /dev/null +++ b/persistence-modules/hibernate-mapping/src/main/resources/logback.xml @@ -0,0 +1,13 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + \ No newline at end of file diff --git a/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/persistmaps/MapKeyColumnIntegrationTest.java b/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/persistmaps/MapKeyColumnIntegrationTest.java new file mode 100644 index 0000000000..acd77ee382 --- /dev/null +++ b/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/persistmaps/MapKeyColumnIntegrationTest.java @@ -0,0 +1,79 @@ +package com.baeldung.hibernate.persistmaps; + +import com.baeldung.hibernate.HibernateUtil; +import com.baeldung.hibernate.Strategy; +import com.baeldung.hibernate.persistmaps.mapkeycolumn.Order; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +public class MapKeyColumnIntegrationTest { + private static SessionFactory sessionFactory; + + private Session session; + + @BeforeClass + public static void beforeTests() { + sessionFactory = HibernateUtil.getSessionFactory(Strategy.MAP_KEY_COLUMN_BASED); + } + + @Before + public void setUp() { + session = sessionFactory.openSession(); + session.beginTransaction(); + } + + @Test + public void givenData_whenInsertUsingMapKeyColumn_thenPersistMap() { + Map itemPriceMap = new HashMap<>(); + itemPriceMap.put("Wrangler Jeans", 150.0); + itemPriceMap.put("Lee Jeans", 180.0); + + + Order order = new Order(); + order.setItemPriceMap(itemPriceMap); + + session.persist(order); + session.getTransaction().commit(); + + assertInsertedData(); + } + + private void assertInsertedData() { + @SuppressWarnings("unchecked") + List orderList = session.createQuery("FROM Order").list(); + + assertNotNull(orderList); + assertEquals(1, orderList.size()); + + Order order = orderList.get(0); + + Map itemPriceMap = order.getItemPriceMap(); + assertNotNull(itemPriceMap); + assertEquals(itemPriceMap.size(), 2); + assertEquals((Double) 150.0, itemPriceMap.get("Wrangler Jeans")); + assertEquals((Double) 180.0, itemPriceMap.get("Lee Jeans")); + + } + + @After + public void tearDown() { + session.close(); + } + + @AfterClass + public static void afterTests() { + sessionFactory.close(); + } +} diff --git a/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/persistmaps/MapKeyEnumeratedIntegrationTest.java b/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/persistmaps/MapKeyEnumeratedIntegrationTest.java new file mode 100644 index 0000000000..221aa7b1d7 --- /dev/null +++ b/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/persistmaps/MapKeyEnumeratedIntegrationTest.java @@ -0,0 +1,95 @@ +package com.baeldung.hibernate.persistmaps; + +import com.baeldung.hibernate.HibernateUtil; +import com.baeldung.hibernate.Strategy; +import com.baeldung.hibernate.persistmaps.mapkey.Item; +import com.baeldung.hibernate.persistmaps.mapkeyenumerated.Order; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.time.Instant; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +public class MapKeyEnumeratedIntegrationTest { + private static SessionFactory sessionFactory; + + private Session session; + + @BeforeClass + public static void beforeTests() { + sessionFactory = HibernateUtil.getSessionFactory(Strategy.MAP_KEY_ENUMERATED_BASED); + } + + @Before + public void setUp() { + session = sessionFactory.openSession(); + session.beginTransaction(); + } + + @Test + public void givenData_whenInsertUsingMapKeyEnumerated_thenPersistMap() { + Item item1 = new Item(); + item1.setItemName("Wrangler Jeans"); + item1.setItemPrice(150.0); + item1.setItemType(ItemType.JEANS); + item1.setCreatedOn(Date.from(Instant.ofEpochSecond(1554926573))); + + + Item item2 = new Item(); + item2.setItemName("Armani Tshirts"); + item2.setItemPrice(180.0); + item2.setItemType(ItemType.TSHIRTS); + item2.setCreatedOn(Date.from(Instant.ofEpochSecond(1554890573))); + + Map itemMap = new HashMap<>(); + itemMap.put(item1.getItemType(), item1); + itemMap.put(item2.getItemType(), item2); + + Order order = new Order(); + order.setItemMap(itemMap); + + session.persist(order); + session.getTransaction().commit(); + + assertInsertedData(item1, item2); + } + + private void assertInsertedData(Item expectedItem1, Item expectedItem2) { + @SuppressWarnings("unchecked") + List orderList = session.createQuery("FROM Order").list(); + + assertNotNull(orderList); + assertEquals(1, orderList.size()); + + Order order = orderList.get(0); + + Map itemMap = order.getItemMap(); + assertNotNull(itemMap); + assertEquals(2, itemMap.size()); + assertEquals(expectedItem1, itemMap.get(ItemType.JEANS)); + assertEquals(expectedItem2, itemMap.get(ItemType.TSHIRTS)); + + } + + @After + public void tearDown() { + session.close(); + } + + @AfterClass + public static void afterTests() { + sessionFactory.close(); + } +} + diff --git a/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/persistmaps/MapKeyIntegrationTest.java b/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/persistmaps/MapKeyIntegrationTest.java new file mode 100644 index 0000000000..b500deb78e --- /dev/null +++ b/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/persistmaps/MapKeyIntegrationTest.java @@ -0,0 +1,95 @@ +package com.baeldung.hibernate.persistmaps; + +import com.baeldung.hibernate.HibernateUtil; +import com.baeldung.hibernate.Strategy; +import com.baeldung.hibernate.persistmaps.mapkey.Item; +import com.baeldung.hibernate.persistmaps.mapkey.Order; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.time.Instant; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +public class MapKeyIntegrationTest { + private static SessionFactory sessionFactory; + + private Session session; + + @BeforeClass + public static void beforeTests() { + sessionFactory = HibernateUtil.getSessionFactory(Strategy.MAP_KEY_BASED); + } + + @Before + public void setUp() { + session = sessionFactory.openSession(); + session.beginTransaction(); + } + + @Test + public void givenData_whenInsertUsingMapKey_thenPersistMap() { + Item item1 = new Item(); + item1.setItemName("Wrangler Jeans"); + item1.setItemPrice(150.0); + item1.setItemType(ItemType.JEANS); + item1.setCreatedOn(Date.from(Instant.ofEpochSecond(1554926573))); + + + Item item2 = new Item(); + item2.setItemName("Armani Tshirts"); + item2.setItemPrice(180.0); + item2.setItemType(ItemType.TSHIRTS); + item2.setCreatedOn(Date.from(Instant.ofEpochSecond(1554890573))); + + Map itemMap = new HashMap<>(); + itemMap.put(item1.getItemName(), item1); + itemMap.put(item2.getItemName(), item2); + + Order order = new Order(); + order.setItemMap(itemMap); + + session.persist(order); + session.getTransaction().commit(); + + assertInsertedData(item1, item2); + } + + private void assertInsertedData(Item expectedItem1, Item expectedItem2) { + @SuppressWarnings("unchecked") + List orderList = session.createQuery("FROM Order").list(); + + assertNotNull(orderList); + assertEquals(1, orderList.size()); + + Order order = orderList.get(0); + + Map itemMap = order.getItemMap(); + assertNotNull(itemMap); + assertEquals(2, itemMap.size()); + assertEquals(expectedItem1, itemMap.get("Wrangler Jeans")); + assertEquals(expectedItem2, itemMap.get("Armani Tshirts")); + + } + + @After + public void tearDown() { + session.close(); + } + + @AfterClass + public static void afterTests() { + sessionFactory.close(); + } +} + diff --git a/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/persistmaps/MapKeyJoinColumnIntegrationTest.java b/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/persistmaps/MapKeyJoinColumnIntegrationTest.java new file mode 100644 index 0000000000..88b22f5c99 --- /dev/null +++ b/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/persistmaps/MapKeyJoinColumnIntegrationTest.java @@ -0,0 +1,105 @@ +package com.baeldung.hibernate.persistmaps; + +import com.baeldung.hibernate.HibernateUtil; +import com.baeldung.hibernate.Strategy; +import com.baeldung.hibernate.persistmaps.mapkeyjoincolumn.Item; +import com.baeldung.hibernate.persistmaps.mapkeyjoincolumn.Order; +import com.baeldung.hibernate.persistmaps.mapkeyjoincolumn.Seller; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.time.Instant; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +public class MapKeyJoinColumnIntegrationTest { + private static SessionFactory sessionFactory; + + private Session session; + + @BeforeClass + public static void beforeTests() { + sessionFactory = HibernateUtil.getSessionFactory(Strategy.MAP_KEY_JOIN_COLUMN_BASED); + } + + @Before + public void setUp() { + session = sessionFactory.openSession(); + session.beginTransaction(); + } + + @Test + public void givenData_whenInsertUsingMapKeyJoinColumn_thenPersistMap() { + Seller seller1 = new Seller(); + seller1.setSellerName("Walmart"); + + Item item1 = new Item(); + item1.setItemName("Wrangler Jeans"); + item1.setItemPrice(150.0); + item1.setItemType(ItemType.JEANS); + item1.setCreatedOn(Date.from(Instant.ofEpochSecond(1554926573))); + item1.setSeller(seller1); + + + Seller seller2 = new Seller(); + seller2.setSellerName("Amazon"); + + Item item2 = new Item(); + item2.setItemName("Armani Tshirts"); + item2.setItemPrice(180.0); + item2.setItemType(ItemType.TSHIRTS); + item2.setCreatedOn(Date.from(Instant.ofEpochSecond(1554890573))); + item2.setSeller(seller2); + + Map itemSellerMap = new HashMap<>(); + itemSellerMap.put(seller1, item1); + itemSellerMap.put(seller2, item2); + + Order order = new Order(); + order.setSellerItemMap(itemSellerMap); + + + session.persist(order); + session.getTransaction().commit(); + + assertInsertedData(seller1, item1, seller2, item2); + } + + private void assertInsertedData(Seller seller1, Item expectedItem1, Seller seller2, Item expectedItem2) { + @SuppressWarnings("unchecked") + List orderList = session.createQuery("FROM Order").list(); + + assertNotNull(orderList); + assertEquals(1, orderList.size()); + + Order order = orderList.get(0); + + Map sellerItemMap = order.getSellerItemMap(); + assertNotNull(sellerItemMap); + assertEquals(2, sellerItemMap.size()); + assertEquals(expectedItem1, sellerItemMap.get(seller1)); + assertEquals(expectedItem2, sellerItemMap.get(seller2)); + + } + + @After + public void tearDown() { + session.close(); + } + + @AfterClass + public static void afterTests() { + sessionFactory.close(); + } +} + diff --git a/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/persistmaps/MapKeyTemporalIntegrationTest.java b/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/persistmaps/MapKeyTemporalIntegrationTest.java new file mode 100644 index 0000000000..7117cad22f --- /dev/null +++ b/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/persistmaps/MapKeyTemporalIntegrationTest.java @@ -0,0 +1,96 @@ +package com.baeldung.hibernate.persistmaps; + +import com.baeldung.hibernate.HibernateUtil; +import com.baeldung.hibernate.Strategy; +import com.baeldung.hibernate.persistmaps.mapkey.Item; +import com.baeldung.hibernate.persistmaps.mapkeytemporal.Order; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.time.Instant; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +public class MapKeyTemporalIntegrationTest { + private static SessionFactory sessionFactory; + + private Session session; + + @BeforeClass + public static void beforeTests() { + sessionFactory = HibernateUtil.getSessionFactory(Strategy.MAP_KEY_TEMPORAL_BASED); + } + + @Before + public void setUp() { + session = sessionFactory.openSession(); + session.beginTransaction(); + } + + @Test + public void givenData_whenInsertUsingMapKeyEnumerated_thenPersistMap() { + Date item1CreatedOn = Date.from(Instant.ofEpochSecond(1554926573)); + Item item1 = new Item(); + item1.setItemName("Wrangler Jeans"); + item1.setItemPrice(150.0); + item1.setItemType(ItemType.JEANS); + item1.setCreatedOn(item1CreatedOn); + + + Date item2CreatedOn = Date.from(Instant.ofEpochSecond(1554890573)); + Item item2 = new Item(); + item2.setItemName("Armani Tshirts"); + item2.setItemPrice(180.0); + item2.setItemType(ItemType.TSHIRTS); + item2.setCreatedOn(item2CreatedOn); + + Map itemMap = new HashMap<>(); + itemMap.put(item1CreatedOn, item1); + itemMap.put(item2CreatedOn, item2); + + Order order = new Order(); + order.setItemMap(itemMap); + + session.persist(order); + session.getTransaction().commit(); + + assertInsertedData(item1CreatedOn, item1, item2CreatedOn, item2); + } + + private void assertInsertedData(Date item1CreatedOn, Item expectedItem1, Date item2CreatedOn, Item expectedItem2) { + @SuppressWarnings("unchecked") + List orderList = session.createQuery("FROM Order").list(); + + assertNotNull(orderList); + assertEquals(1, orderList.size()); + + Order order = orderList.get(0); + + Map itemMap = order.getItemMap(); + assertNotNull(itemMap); + assertEquals(2, itemMap.size()); + assertEquals(expectedItem1, itemMap.get(item1CreatedOn)); + assertEquals(expectedItem2, itemMap.get(item2CreatedOn)); + + } + + @After + public void tearDown() { + session.close(); + } + + @AfterClass + public static void afterTests() { + sessionFactory.close(); + } +} diff --git a/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/validation/UserValidationUnitTest.java b/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/validation/UserValidationUnitTest.java new file mode 100644 index 0000000000..e39f324856 --- /dev/null +++ b/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/validation/UserValidationUnitTest.java @@ -0,0 +1,81 @@ +package com.baeldung.hibernate.validation; + +import static org.junit.Assert.assertEquals; +import java.util.Set; +import javax.persistence.PersistenceException; +import javax.validation.ConstraintViolation; +import javax.validation.Validation; +import javax.validation.Validator; +import javax.validation.ValidatorFactory; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import com.baeldung.hibernate.HibernateUtil; +import com.baeldung.hibernate.Strategy; +import com.baeldung.hibernate.persistmaps.mapkey.User; + +public class UserValidationUnitTest { + + private static Validator validator; + private static SessionFactory sessionFactory; + private Session session; + private Set> constraintViolations; + + @BeforeClass + public static void before() { + ValidatorFactory config = Validation.buildDefaultValidatorFactory(); + validator = config.getValidator(); + sessionFactory = HibernateUtil.getSessionFactory(Strategy.MAP_KEY_BASED); + } + + @Before + public void setUp() { + session = sessionFactory.openSession(); + session.beginTransaction(); + } + + @Test + public void whenValidationWithSizeAndInvalidMiddleName_thenConstraintViolation() { + User user = new User("john", "m", "butler", "japan"); + constraintViolations = validator.validateProperty(user, "middleName"); + assertEquals(constraintViolations.size(), 1); + } + + @Test + public void whenValidationWithSizeAndValidMiddleName_thenNoConstraintViolation() { + User user = new User("john", "mathis", "butler", "japan"); + constraintViolations = validator.validateProperty(user, "middleName"); + assertEquals(constraintViolations.size(), 0); + } + + @Test + public void whenValidationWithLengthAndInvalidLastName_thenConstraintViolation() { + User user = new User("john", "m", "b", "japan"); + constraintViolations = validator.validateProperty(user, "lastName"); + assertEquals(constraintViolations.size(), 1); + } + + @Test + public void whenValidationWithLengthAndValidLastName_thenNoConstraintViolation() { + User user = new User("john", "mathis", "butler", "japan"); + constraintViolations = validator.validateProperty(user, "lastName"); + assertEquals(constraintViolations.size(), 0); + } + + @Test(expected = PersistenceException.class) + public void whenSavingFirstNameWithInvalidFirstName_thenPersistenceException() { + User user = new User("john", "mathis", "butler", "japan"); + session.save(user); + session.getTransaction() + .commit(); + } + + @Test + public void whenValidationWithSizeAndColumnWithValidCity_thenNoConstraintViolation() { + User user = new User("john", "mathis", "butler", "japan"); + constraintViolations = validator.validateProperty(user, "city"); + assertEquals(constraintViolations.size(), 0); + } +} diff --git a/persistence-modules/hibernate-mapping/src/test/resources/hibernate.properties b/persistence-modules/hibernate-mapping/src/test/resources/hibernate.properties new file mode 100644 index 0000000000..c22da2496b --- /dev/null +++ b/persistence-modules/hibernate-mapping/src/test/resources/hibernate.properties @@ -0,0 +1,10 @@ +hibernate.connection.driver_class=org.h2.Driver +hibernate.connection.url=jdbc:h2:mem:mydb1;DB_CLOSE_DELAY=-1 +hibernate.connection.username=sa +hibernate.connection.autocommit=true +jdbc.password= + +hibernate.dialect=org.hibernate.dialect.H2Dialect +hibernate.show_sql=true +hibernate.hbm2ddl.auto=create-drop + diff --git a/persistence-modules/hibernate-ogm/README.md b/persistence-modules/hibernate-ogm/README.md index f4a5bb6c3b..df99cce129 100644 --- a/persistence-modules/hibernate-ogm/README.md +++ b/persistence-modules/hibernate-ogm/README.md @@ -1,4 +1,4 @@ ## Relevant articles: -- [Guide to Hibernate OGM](http://www.baeldung.com/xxxx) +- [A Guide to Hibernate OGM](https://www.baeldung.com/hibernate-ogm) diff --git a/persistence-modules/hibernate5/README.md b/persistence-modules/hibernate5/README.md index a37720a428..68008bc8fe 100644 --- a/persistence-modules/hibernate5/README.md +++ b/persistence-modules/hibernate5/README.md @@ -32,3 +32,4 @@ - [Common Hibernate Exceptions](https://www.baeldung.com/hibernate-exceptions) - [Hibernate Aggregate Functions](https://www.baeldung.com/hibernate-aggregate-functions) - [Hibernate Query Plan Cache](https://www.baeldung.com/hibernate-query-plan-cache) +- [TransactionRequiredException Error](https://www.baeldung.com/jpa-transaction-required-exception) diff --git a/persistence-modules/hibernate5/pom.xml b/persistence-modules/hibernate5/pom.xml index a09669c8b5..c7f08e50d5 100644 --- a/persistence-modules/hibernate5/pom.xml +++ b/persistence-modules/hibernate5/pom.xml @@ -83,13 +83,18 @@ jmh-generator-annprocess ${openjdk-jmh.version} + + javax.xml.bind + jaxb-api + 2.3.0 + hibernate5 - src/main/resources + src/test/resources true diff --git a/persistence-modules/hibernate5/src/main/java/com/baeldung/hibernate/HibernateUtil.java b/persistence-modules/hibernate5/src/main/java/com/baeldung/hibernate/HibernateUtil.java index ea0af97d5a..48c9b9d5c2 100644 --- a/persistence-modules/hibernate5/src/main/java/com/baeldung/hibernate/HibernateUtil.java +++ b/persistence-modules/hibernate5/src/main/java/com/baeldung/hibernate/HibernateUtil.java @@ -113,6 +113,7 @@ public class HibernateUtil { metadataSources.addAnnotatedClass(OptimisticLockingCourse.class); metadataSources.addAnnotatedClass(OptimisticLockingStudent.class); metadataSources.addAnnotatedClass(OfficeEmployee.class); + metadataSources.addAnnotatedClass(Post.class); Metadata metadata = metadataSources.getMetadataBuilder() .applyBasicType(LocalDateStringType.INSTANCE) diff --git a/persistence-modules/hibernate5/src/main/java/com/baeldung/hibernate/pojo/Post.java b/persistence-modules/hibernate5/src/main/java/com/baeldung/hibernate/pojo/Post.java new file mode 100644 index 0000000000..25e51e35d0 --- /dev/null +++ b/persistence-modules/hibernate5/src/main/java/com/baeldung/hibernate/pojo/Post.java @@ -0,0 +1,59 @@ +package com.baeldung.hibernate.pojo; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.Table; + +@Entity +@Table(name = "posts") +public class Post { + + @Id + @GeneratedValue + private int id; + + private String title; + + private String body; + + public Post() { } + + public Post(String title, String body) { + this.title = title; + this.body = body; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getBody() { + return body; + } + + public void setBody(String body) { + this.body = body; + } + + @Override + public String toString() { + return "Post{" + + "id=" + id + + ", title='" + title + '\'' + + ", body='" + body + '\'' + + '}'; + } +} diff --git a/persistence-modules/hibernate5/src/main/java/com/baeldung/hibernate/transaction/PostService.java b/persistence-modules/hibernate5/src/main/java/com/baeldung/hibernate/transaction/PostService.java new file mode 100644 index 0000000000..5a4eb20079 --- /dev/null +++ b/persistence-modules/hibernate5/src/main/java/com/baeldung/hibernate/transaction/PostService.java @@ -0,0 +1,29 @@ +package com.baeldung.hibernate.transaction; + +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.query.Query; + +public class PostService { + + + private Session session; + + public PostService(Session session) { + this.session = session; + } + + + public void updatePost(String title, String body, int id) { + Transaction txn = session.beginTransaction(); + Query updateQuery = session.createQuery("UPDATE Post p SET p.title = ?1, p.body = ?2 WHERE p.id = ?3"); + updateQuery.setParameter(1, title); + updateQuery.setParameter(2, body); + updateQuery.setParameter(3, id); + updateQuery.executeUpdate(); + txn.commit(); + } + + + +} diff --git a/persistence-modules/hibernate5/src/test/java/com/baeldung/hibernate/CustomClassIntegrationTest.java b/persistence-modules/hibernate5/src/test/java/com/baeldung/hibernate/CustomClassIntegrationTest.java index 29ae55b773..e64e836924 100644 --- a/persistence-modules/hibernate5/src/test/java/com/baeldung/hibernate/CustomClassIntegrationTest.java +++ b/persistence-modules/hibernate5/src/test/java/com/baeldung/hibernate/CustomClassIntegrationTest.java @@ -74,4 +74,6 @@ public class CustomClassIntegrationTest { assertEquals("John Smith", result.getEmployeeName()); assertEquals("Sales", result.getDepartmentName()); } + + } diff --git a/persistence-modules/hibernate5/src/test/java/com/baeldung/hibernate/transaction/TransactionIntegrationTest.java b/persistence-modules/hibernate5/src/test/java/com/baeldung/hibernate/transaction/TransactionIntegrationTest.java new file mode 100644 index 0000000000..246a7d59f9 --- /dev/null +++ b/persistence-modules/hibernate5/src/test/java/com/baeldung/hibernate/transaction/TransactionIntegrationTest.java @@ -0,0 +1,57 @@ +package com.baeldung.hibernate.transaction; + +import com.baeldung.hibernate.HibernateUtil; +import com.baeldung.hibernate.pojo.Post; +import com.baeldung.hibernate.transaction.PostService; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.junit.BeforeClass; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.FileInputStream; +import java.io.IOException; +import java.util.Properties; + +import static org.junit.Assert.assertEquals; + +public class TransactionIntegrationTest { + + private static PostService postService; + private static Session session; + private static Logger logger = LoggerFactory.getLogger(TransactionIntegrationTest.class); + + @BeforeClass + public static void init() throws IOException { + Properties properties = new Properties(); + properties.setProperty("hibernate.connection.driver_class", "org.h2.Driver"); + properties.setProperty("hibernate.connection.url", "jdbc:h2:mem:mydb1;DB_CLOSE_DELAY=-1"); + properties.setProperty("hibernate.connection.username", "sa"); + properties.setProperty("hibernate.show_sql", "true"); + properties.setProperty("jdbc.password", ""); + properties.setProperty("hibernate.dialect", "org.hibernate.dialect.H2Dialect"); + properties.setProperty("hibernate.hbm2ddl.auto", "create-drop"); + SessionFactory sessionFactory = HibernateUtil.getSessionFactoryByProperties(properties); + session = sessionFactory.openSession(); + postService = new PostService(session); + } + + @Test + public void givenTitleAndBody_whenRepositoryUpdatePost_thenUpdatePost() { + + Post post = new Post("This is a title", "This is a sample post"); + session.persist(post); + + String title = "[UPDATE] Java HowTos"; + String body = "This is an updated posts on Java how-tos"; + postService.updatePost(title, body, post.getId()); + + session.refresh(post); + + assertEquals(post.getTitle(), title); + assertEquals(post.getBody(), body); + } + + +} diff --git a/persistence-modules/java-jpa/README.md b/persistence-modules/java-jpa/README.md index 2c26581bab..5be1015942 100644 --- a/persistence-modules/java-jpa/README.md +++ b/persistence-modules/java-jpa/README.md @@ -2,7 +2,8 @@ - [A Guide to SqlResultSetMapping](http://www.baeldung.com/jpa-sql-resultset-mapping) - [A Guide to Stored Procedures with JPA](http://www.baeldung.com/jpa-stored-procedures) -- [Fixing the JPA error “java.lang.String cannot be cast to Ljava.lang.String;”](https://www.baeldung.com/jpa-error-java-lang-string-cannot-be-cast) +- [Fixing the JPA error “java.lang.String cannot be cast to [Ljava.lang.String;”]](https://www.baeldung.com/jpa-error-java-lang-string-cannot-be-cast) - [JPA Entity Graph](https://www.baeldung.com/jpa-entity-graph) - [JPA 2.2 Support for Java 8 Date/Time Types](https://www.baeldung.com/jpa-java-time) - [Converting Between LocalDate and SQL Date](https://www.baeldung.com/java-convert-localdate-sql-date) +- [Combining JPA And/Or Criteria Predicates](https://www.baeldung.com/jpa-and-or-criteria-predicates) diff --git a/persistence-modules/java-jpa/src/main/java/com/baeldung/jpa/criteria/entity/Item.java b/persistence-modules/java-jpa/src/main/java/com/baeldung/jpa/criteria/entity/Item.java new file mode 100644 index 0000000000..64ef46f265 --- /dev/null +++ b/persistence-modules/java-jpa/src/main/java/com/baeldung/jpa/criteria/entity/Item.java @@ -0,0 +1,49 @@ +package com.baeldung.jpa.criteria.entity; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; + +@Table(name = "item") +@Entity +public class Item { + + @Id + private Long id; + private String color; + private String grade; + private String name; + + public String getColor() { + return color; + } + + public String getGrade() { + return grade; + } + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + public void setColor(String color) { + this.color = color; + } + + public void setGrade(String grade) { + this.grade = grade; + } + + public void setId(Long id) { + this.id = id; + } + + public void setName(String name) { + this.name = name; + } + +} diff --git a/persistence-modules/java-jpa/src/main/java/com/baeldung/jpa/criteria/repository/CustomItemRepository.java b/persistence-modules/java-jpa/src/main/java/com/baeldung/jpa/criteria/repository/CustomItemRepository.java new file mode 100644 index 0000000000..c55dc4a592 --- /dev/null +++ b/persistence-modules/java-jpa/src/main/java/com/baeldung/jpa/criteria/repository/CustomItemRepository.java @@ -0,0 +1,12 @@ +package com.baeldung.jpa.criteria.repository; + +import java.util.List; + +import com.baeldung.jpa.criteria.entity.Item; + +public interface CustomItemRepository { + + List findItemsByColorAndGrade(); + + List findItemByColorOrGrade(); +} diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/impl/CustomItemRepositoryImpl.java b/persistence-modules/java-jpa/src/main/java/com/baeldung/jpa/criteria/repository/impl/CustomItemRepositoryImpl.java similarity index 81% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/impl/CustomItemRepositoryImpl.java rename to persistence-modules/java-jpa/src/main/java/com/baeldung/jpa/criteria/repository/impl/CustomItemRepositoryImpl.java index 9791cb0aa7..bf1d3eed0b 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/impl/CustomItemRepositoryImpl.java +++ b/persistence-modules/java-jpa/src/main/java/com/baeldung/jpa/criteria/repository/impl/CustomItemRepositoryImpl.java @@ -1,88 +1,77 @@ -package com.baeldung.dao.repositories.impl; - -import java.util.List; - -import javax.persistence.EntityManager; -import javax.persistence.criteria.CriteriaBuilder; -import javax.persistence.criteria.CriteriaQuery; -import javax.persistence.criteria.Predicate; -import javax.persistence.criteria.Root; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Repository; - -import com.baeldung.dao.repositories.CustomItemRepository; -import com.baeldung.domain.Item; - -@Repository -public class CustomItemRepositoryImpl implements CustomItemRepository { - - @Autowired - private EntityManager entityManager; - - @Override - public void deleteCustom(Item item) { - entityManager.remove(item); - } - - @Override - public Item findItemById(Long id) { - return entityManager.find(Item.class, id); - } - - @Override - public void findThenDelete(Long id) { - final Item item = entityManager.find(Item.class, id); - entityManager.remove(item); - } - - @Override - public List findItemsByColorAndGrade() { - - CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); - CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(Item.class); - Root itemRoot = criteriaQuery.from(Item.class); - - Predicate predicateForBlueColor = criteriaBuilder.equal(itemRoot.get("color"), "blue"); - Predicate predicateForRedColor = criteriaBuilder.equal(itemRoot.get("color"), "red"); - Predicate predicateForColor = criteriaBuilder.or(predicateForBlueColor, predicateForRedColor); - - Predicate predicateForGradeA = criteriaBuilder.equal(itemRoot.get("grade"), "A"); - Predicate predicateForGradeB = criteriaBuilder.equal(itemRoot.get("grade"), "B"); - Predicate predicateForGrade = criteriaBuilder.or(predicateForGradeA, predicateForGradeB); - - // final search filter - Predicate finalPredicate = criteriaBuilder.and(predicateForColor, predicateForGrade); - - criteriaQuery.where(finalPredicate); - - List items = entityManager.createQuery(criteriaQuery) - .getResultList(); - return items; - } - - @Override - public List findItemByColorOrGrade() { - - CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); - CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(Item.class); - Root itemRoot = criteriaQuery.from(Item.class); - - Predicate predicateForBlueColor = criteriaBuilder.equal(itemRoot.get("color"), "red"); - Predicate predicateForGradeA = criteriaBuilder.equal(itemRoot.get("grade"), "D"); - Predicate predicateForBlueColorAndGradeA = criteriaBuilder.and(predicateForBlueColor, predicateForGradeA); - - Predicate predicateForRedColor = criteriaBuilder.equal(itemRoot.get("color"), "blue"); - Predicate predicateForGradeB = criteriaBuilder.equal(itemRoot.get("grade"), "B"); - Predicate predicateForRedColorAndGradeB = criteriaBuilder.and(predicateForRedColor, predicateForGradeB); - - // final search filter - Predicate finalPredicate = criteriaBuilder.or(predicateForBlueColorAndGradeA, predicateForRedColorAndGradeB); - - criteriaQuery.where(finalPredicate); - - List items = entityManager.createQuery(criteriaQuery) - .getResultList(); - return items; - } -} +package com.baeldung.jpa.criteria.repository.impl; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.Persistence; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Predicate; +import javax.persistence.criteria.Root; + +import com.baeldung.jpa.criteria.entity.Item; +import com.baeldung.jpa.criteria.repository.CustomItemRepository; + +public class CustomItemRepositoryImpl implements CustomItemRepository { + + private EntityManager entityManager; + + public CustomItemRepositoryImpl() { + super(); + EntityManagerFactory factory = Persistence.createEntityManagerFactory("jpa-h2-criteria"); + entityManager = factory.createEntityManager(); + } + + @Override + public List findItemsByColorAndGrade() { + + CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); + CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(Item.class); + Root itemRoot = criteriaQuery.from(Item.class); + + Predicate predicateForBlueColor = criteriaBuilder.equal(itemRoot.get("color"), "blue"); + Predicate predicateForRedColor = criteriaBuilder.equal(itemRoot.get("color"), "red"); + Predicate predicateForColor = criteriaBuilder.or(predicateForBlueColor, predicateForRedColor); + + Predicate predicateForGradeA = criteriaBuilder.equal(itemRoot.get("grade"), "A"); + Predicate predicateForGradeB = criteriaBuilder.equal(itemRoot.get("grade"), "B"); + Predicate predicateForGrade = criteriaBuilder.or(predicateForGradeA, predicateForGradeB); + + // final search filter + Predicate finalPredicate = criteriaBuilder.and(predicateForColor, predicateForGrade); + + criteriaQuery.where(finalPredicate); + + List items = entityManager.createQuery(criteriaQuery) + .getResultList(); + return items; + } + + @Override + public List findItemByColorOrGrade() { + + CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); + CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(Item.class); + Root itemRoot = criteriaQuery.from(Item.class); + + Predicate predicateForBlueColor = criteriaBuilder.equal(itemRoot.get("color"), "red"); + Predicate predicateForGradeA = criteriaBuilder.equal(itemRoot.get("grade"), "D"); + Predicate predicateForBlueColorAndGradeA = criteriaBuilder.and(predicateForBlueColor, predicateForGradeA); + + Predicate predicateForRedColor = criteriaBuilder.equal(itemRoot.get("color"), "blue"); + Predicate predicateForGradeB = criteriaBuilder.equal(itemRoot.get("grade"), "B"); + Predicate predicateForRedColorAndGradeB = criteriaBuilder.and(predicateForRedColor, predicateForGradeB); + + // final search filter + Predicate finalPredicate = criteriaBuilder.or(predicateForBlueColorAndGradeA, predicateForRedColorAndGradeB); + + criteriaQuery.where(finalPredicate); + + List items = entityManager.createQuery(criteriaQuery) + .getResultList(); + return items; + } +} diff --git a/persistence-modules/java-jpa/src/main/java/com/baeldung/jpa/querytypes/QueryTypesExamples.java b/persistence-modules/java-jpa/src/main/java/com/baeldung/jpa/querytypes/QueryTypesExamples.java new file mode 100644 index 0000000000..523fc348f9 --- /dev/null +++ b/persistence-modules/java-jpa/src/main/java/com/baeldung/jpa/querytypes/QueryTypesExamples.java @@ -0,0 +1,69 @@ +package com.baeldung.jpa.querytypes; + +import java.util.HashMap; +import java.util.Map; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.Persistence; +import javax.persistence.Query; +import javax.persistence.TypedQuery; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; + +/** + * JPA Query Types examples. All using the UserEntity class. + * + * @author Rodolfo Felipe + */ +public class QueryTypesExamples { + + EntityManagerFactory emf; + + public QueryTypesExamples() { + Map properties = new HashMap(); + properties.put("hibernate.show_sql", "true"); + properties.put("hibernate.format_sql", "true"); + emf = Persistence.createEntityManagerFactory("jpa-query-types", properties); + } + + private EntityManager getEntityManager() { + return emf.createEntityManager(); + } + + public UserEntity getUserByIdWithPlainQuery(Long id) { + Query jpqlQuery = getEntityManager().createQuery("SELECT u FROM UserEntity u WHERE u.id=:id"); + jpqlQuery.setParameter("id", id); + return (UserEntity) jpqlQuery.getSingleResult(); + } + + public UserEntity getUserByIdWithTypedQuery(Long id) { + TypedQuery typedQuery = getEntityManager().createQuery("SELECT u FROM UserEntity u WHERE u.id=:id", UserEntity.class); + typedQuery.setParameter("id", id); + return typedQuery.getSingleResult(); + } + + public UserEntity getUserByIdWithNamedQuery(Long id) { + Query namedQuery = getEntityManager().createNamedQuery("UserEntity.findByUserId"); + namedQuery.setParameter("userId", id); + return (UserEntity) namedQuery.getSingleResult(); + } + + public UserEntity getUserByIdWithNativeQuery(Long id) { + Query nativeQuery = getEntityManager().createNativeQuery("SELECT * FROM users WHERE id=:userId", UserEntity.class); + nativeQuery.setParameter("userId", id); + return (UserEntity) nativeQuery.getSingleResult(); + } + + public UserEntity getUserByIdWithCriteriaQuery(Long id) { + CriteriaBuilder criteriaBuilder = getEntityManager().getCriteriaBuilder(); + CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(UserEntity.class); + Root userRoot = criteriaQuery.from(UserEntity.class); + UserEntity queryResult = getEntityManager().createQuery(criteriaQuery.select(userRoot) + .where(criteriaBuilder.equal(userRoot.get("id"), id))) + .getSingleResult(); + return queryResult; + } + +} diff --git a/persistence-modules/java-jpa/src/main/java/com/baeldung/jpa/querytypes/UserEntity.java b/persistence-modules/java-jpa/src/main/java/com/baeldung/jpa/querytypes/UserEntity.java new file mode 100644 index 0000000000..1d4a231b31 --- /dev/null +++ b/persistence-modules/java-jpa/src/main/java/com/baeldung/jpa/querytypes/UserEntity.java @@ -0,0 +1,38 @@ +package com.baeldung.jpa.querytypes; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.NamedQuery; +import javax.persistence.Table; + +/** + * User entity class. Used as an asset for JPA Query Types examples. + * + * @author Rodolfo Felipe + */ +@Table(name = "users") +@Entity +@NamedQuery(name = "UserEntity.findByUserId", query = "SELECT u FROM UserEntity u WHERE u.id=:userId") +public class UserEntity { + + @Id + private Long id; + private String name; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + +} diff --git a/persistence-modules/java-jpa/src/main/resources/META-INF/persistence.xml b/persistence-modules/java-jpa/src/main/resources/META-INF/persistence.xml index 8592fce533..5422afa4a3 100644 --- a/persistence-modules/java-jpa/src/main/resources/META-INF/persistence.xml +++ b/persistence-modules/java-jpa/src/main/resources/META-INF/persistence.xml @@ -1,91 +1,133 @@ - - - - - org.hibernate.jpa.HibernatePersistenceProvider - com.baeldung.sqlresultsetmapping.ScheduledDay - com.baeldung.sqlresultsetmapping.Employee - true - - - - - - - - - - - - - - org.hibernate.jpa.HibernatePersistenceProvider - com.baeldung.jpa.stringcast.Message - true - - - - - - - - - - - - - - org.hibernate.jpa.HibernatePersistenceProvider - com.baeldung.jpa.model.Car - true - - - - - - - - - - - - com.baeldung.jpa.entitygraph.model.Post - com.baeldung.jpa.entitygraph.model.User - com.baeldung.jpa.entitygraph.model.Comment - true - - - - - - - - - - - - - org.eclipse.persistence.jpa.PersistenceProvider - com.baeldung.jpa.datetime.JPA22DateTimeEntity - true - - - - - - - - - - - - - - + + + + + org.hibernate.jpa.HibernatePersistenceProvider + com.baeldung.sqlresultsetmapping.ScheduledDay + com.baeldung.sqlresultsetmapping.Employee + true + + + + + + + + + + + + + + org.hibernate.jpa.HibernatePersistenceProvider + com.baeldung.jpa.stringcast.Message + true + + + + + + + + + + + + + + org.hibernate.jpa.HibernatePersistenceProvider + com.baeldung.jpa.model.Car + true + + + + + + + + + + + + com.baeldung.jpa.entitygraph.model.Post + com.baeldung.jpa.entitygraph.model.User + com.baeldung.jpa.entitygraph.model.Comment + true + + + + + + + + + + + + + org.eclipse.persistence.jpa.PersistenceProvider + com.baeldung.jpa.datetime.JPA22DateTimeEntity + true + + + + + + + + + + + + + + + + org.hibernate.jpa.HibernatePersistenceProvider + com.baeldung.jpa.criteria.entity.Item + true + + + + + + + + + + + + + + + org.hibernate.jpa.HibernatePersistenceProvider + com.baeldung.jpa.querytypes.UserEntity + true + + + + + + + + + + + + + \ No newline at end of file diff --git a/persistence-modules/java-jpa/src/test/java/com/baeldung/jpa/criteria/repository/impl/CustomItemRepositoryIntegrationTest.java b/persistence-modules/java-jpa/src/test/java/com/baeldung/jpa/criteria/repository/impl/CustomItemRepositoryIntegrationTest.java new file mode 100644 index 0000000000..169fb44618 --- /dev/null +++ b/persistence-modules/java-jpa/src/test/java/com/baeldung/jpa/criteria/repository/impl/CustomItemRepositoryIntegrationTest.java @@ -0,0 +1,44 @@ +package com.baeldung.jpa.criteria.repository.impl; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; + +import java.util.List; + +import org.junit.Test; + +import com.baeldung.jpa.criteria.entity.Item; +import com.baeldung.jpa.criteria.repository.CustomItemRepository; + +public class CustomItemRepositoryIntegrationTest { + + CustomItemRepository customItemRepository = new CustomItemRepositoryImpl(); + + @Test + public void givenItems_whenFindItemsByColorAndGrade_thenReturnItems() { + + List items = customItemRepository.findItemsByColorAndGrade(); + + assertFalse("No items found", items.isEmpty()); + assertEquals("There should be only one item", 1, items.size()); + + Item item = items.get(0); + + assertEquals("this item do not have blue color", "blue", item.getColor()); + assertEquals("this item does not belong to A grade", "A", item.getGrade()); + } + + @Test + public void givenItems_whenFindItemByColorOrGrade_thenReturnItems() { + + List items = customItemRepository.findItemByColorOrGrade(); + + assertFalse("No items found", items.isEmpty()); + assertEquals("There should be only one item", 1, items.size()); + + Item item = items.get(0); + + assertEquals("this item do not have red color", "red", item.getColor()); + assertEquals("this item does not belong to D grade", "D", item.getGrade()); + } +} diff --git a/persistence-modules/java-jpa/src/test/java/com/baeldung/jpa/querytypes/QueryTypesExamplesIntegrationTest.java b/persistence-modules/java-jpa/src/test/java/com/baeldung/jpa/querytypes/QueryTypesExamplesIntegrationTest.java new file mode 100644 index 0000000000..4e854a464a --- /dev/null +++ b/persistence-modules/java-jpa/src/test/java/com/baeldung/jpa/querytypes/QueryTypesExamplesIntegrationTest.java @@ -0,0 +1,65 @@ +package com.baeldung.jpa.querytypes; + +import org.junit.Assert; +import org.junit.Test; + +/** + * QueryTypesExamples class integration tests. + * + * @author Rodolfo Felipe + */ +public class QueryTypesExamplesIntegrationTest { + + QueryTypesExamples userDao = new QueryTypesExamples(); + + @Test + public void givenUserId_whenCallingPlaingQueryMethod_thenReturnExpectedUser() { + UserEntity firstUser = userDao.getUserByIdWithPlainQuery(1L); + Assert.assertNotNull("User not found", firstUser); + Assert.assertEquals("User should be baeldung", "baeldung", firstUser.getName()); + UserEntity lastUser = userDao.getUserByIdWithPlainQuery(4L); + Assert.assertNotNull("User not found", lastUser); + Assert.assertEquals("User should be baeldung", "batman", lastUser.getName()); + } + + @Test + public void givenUserId_whenCallingTypedQueryMethod_thenReturnExpectedUser() { + UserEntity firstUser = userDao.getUserByIdWithTypedQuery(1L); + Assert.assertNotNull("User not found", firstUser); + Assert.assertEquals("User should be baeldung", "baeldung", firstUser.getName()); + UserEntity lastUser = userDao.getUserByIdWithTypedQuery(4L); + Assert.assertNotNull("User not found", lastUser); + Assert.assertEquals("User should be baeldung", "batman", lastUser.getName()); + } + + @Test + public void givenUserId_whenCallingNamedQueryMethod_thenReturnExpectedUser() { + UserEntity firstUser = userDao.getUserByIdWithNamedQuery(1L); + Assert.assertNotNull("User not found", firstUser); + Assert.assertEquals("User should be baeldung", "baeldung", firstUser.getName()); + UserEntity lastUser = userDao.getUserByIdWithNamedQuery(4L); + Assert.assertNotNull("User not found", lastUser); + Assert.assertEquals("User should be baeldung", "batman", lastUser.getName()); + } + + @Test + public void givenUserId_whenCallingNativeQueryMethod_thenReturnExpectedUser() { + UserEntity firstUser = userDao.getUserByIdWithNativeQuery(1L); + Assert.assertNotNull("User not found", firstUser); + Assert.assertEquals("User should be baeldung", "baeldung", firstUser.getName()); + UserEntity lastUser = userDao.getUserByIdWithNativeQuery(4L); + Assert.assertNotNull("User not found", lastUser); + Assert.assertEquals("User should be baeldung", "batman", lastUser.getName()); + } + + @Test + public void givenUserId_whenCallingCriteriaApiMethod_thenReturnExpectedUser() { + UserEntity firstUser = userDao.getUserByIdWithCriteriaQuery(1L); + Assert.assertNotNull("User not found", firstUser); + Assert.assertEquals("User should be baeldung", "baeldung", firstUser.getName()); + UserEntity lastUser = userDao.getUserByIdWithCriteriaQuery(4L); + Assert.assertNotNull("User not found", lastUser); + Assert.assertEquals("User should be baeldung", "batman", lastUser.getName()); + } + +} diff --git a/persistence-modules/java-jpa/src/test/resources/item.sql b/persistence-modules/java-jpa/src/test/resources/item.sql new file mode 100644 index 0000000000..faf50f6829 --- /dev/null +++ b/persistence-modules/java-jpa/src/test/resources/item.sql @@ -0,0 +1,4 @@ +insert into item(id,grade,color) values (10,'C','blue'); +insert into item(id,grade,color) values (11,'C','red'); +insert into item(id,grade,color) values (12,'A','blue'); +insert into item(id,grade,color) values (13,'D','red'); \ No newline at end of file diff --git a/persistence-modules/java-jpa/src/test/resources/users.sql b/persistence-modules/java-jpa/src/test/resources/users.sql new file mode 100644 index 0000000000..227022e5df --- /dev/null +++ b/persistence-modules/java-jpa/src/test/resources/users.sql @@ -0,0 +1,4 @@ +INSERT INTO users(id,name) VALUES(1,'baeldung'); +INSERT INTO users(id,name) VALUES(2,'john doe'); +INSERT INTO users(id,name) VALUES(3,'jane doe'); +INSERT INTO users(id,name) VALUES(4,'batman'); diff --git a/persistence-modules/java-mongodb/pom.xml b/persistence-modules/java-mongodb/pom.xml index 9658ef567f..0f5efedb96 100644 --- a/persistence-modules/java-mongodb/pom.xml +++ b/persistence-modules/java-mongodb/pom.xml @@ -35,8 +35,8 @@ 1.8 1.8 - 3.4.1 + 3.10.1 1.11 - \ No newline at end of file + diff --git a/persistence-modules/java-mongodb/src/main/java/com/baeldung/MongoBsonExample.java b/persistence-modules/java-mongodb/src/main/java/com/baeldung/MongoBsonExample.java new file mode 100644 index 0000000000..0ad3dfae30 --- /dev/null +++ b/persistence-modules/java-mongodb/src/main/java/com/baeldung/MongoBsonExample.java @@ -0,0 +1,79 @@ +package com.baeldung; + +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoDatabase; +import org.bson.Document; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class MongoBsonExample +{ + public static void main(String[] args) + { + // + // 4.1 Connect to cluster (default is localhost:27017) + // + + MongoClient mongoClient = MongoClients.create(); + MongoDatabase database = mongoClient.getDatabase("myDB"); + MongoCollection collection = database.getCollection("employees"); + + // + // 4.2 Insert new document + // + + Document employee = new Document() + .append("first_name", "Joe") + .append("last_name", "Smith") + .append("title", "Java Developer") + .append("years_of_service", 3) + .append("skills", Arrays.asList("java", "spring", "mongodb")) + .append("manager", new Document() + .append("first_name", "Sally") + .append("last_name", "Johanson")); + collection.insertOne(employee); + + // + // 4.3 Find documents + // + + + Document query = new Document("last_name", "Smith"); + List results = new ArrayList<>(); + collection.find(query).into(results); + + query = + new Document("$or", Arrays.asList( + new Document("last_name", "Smith"), + new Document("first_name", "Joe"))); + results = new ArrayList<>(); + collection.find(query).into(results); + + // + // 4.4 Update document + // + + query = new Document( + "skills", + new Document( + "$elemMatch", + new Document("$eq", "spring"))); + Document update = new Document( + "$push", + new Document("skills", "security")); + collection.updateMany(query, update); + + // + // 4.5 Delete documents + // + + query = new Document( + "years_of_service", + new Document("$lt", 0)); + collection.deleteMany(query); + } +} diff --git a/persistence-modules/jnosql/jnosql-artemis/pom.xml b/persistence-modules/jnosql/jnosql-artemis/pom.xml index a07f26c6ee..09d6af13df 100644 --- a/persistence-modules/jnosql/jnosql-artemis/pom.xml +++ b/persistence-modules/jnosql/jnosql-artemis/pom.xml @@ -17,7 +17,7 @@ javax javaee-web-api - 8.0 + ${javaee-web-api.version} provided @@ -80,6 +80,7 @@ 2.4.2 false + 8.0 diff --git a/persistence-modules/jnosql/jnosql-diana/pom.xml b/persistence-modules/jnosql/jnosql-diana/pom.xml index b52c808cf5..a4951761d8 100644 --- a/persistence-modules/jnosql/jnosql-diana/pom.xml +++ b/persistence-modules/jnosql/jnosql-diana/pom.xml @@ -18,36 +18,36 @@ org.jnosql.diana diana-document - 0.0.5 + ${jnosql.version} org.jnosql.diana mongodb-driver - 0.0.5 + ${jnosql.version} org.jnosql.diana diana-column - 0.0.5 + ${jnosql.version} org.jnosql.diana cassandra-driver - 0.0.5 + ${jnosql.version} org.jnosql.diana diana-key-value - 0.0.5 + ${jnosql.version} org.jnosql.diana hazelcast-driver - 0.0.5 + ${jnosql.version} diff --git a/persistence-modules/pom.xml b/persistence-modules/pom.xml index 47c733d8a7..67a5c36fed 100644 --- a/persistence-modules/pom.xml +++ b/persistence-modules/pom.xml @@ -22,6 +22,7 @@ hbase hibernate5 hibernate-ogm + hibernate-mapping influxdb java-cassandra java-cockroachdb @@ -34,7 +35,7 @@ querydsl redis solr - spring-boot-h2/spring-boot-h2-database + spring-boot-persistence-h2 spring-boot-persistence spring-boot-persistence-mongodb spring-data-cassandra diff --git a/persistence-modules/spring-boot-h2/spring-boot-h2-database/.gitignore b/persistence-modules/spring-boot-persistence-h2/.gitignore similarity index 100% rename from persistence-modules/spring-boot-h2/spring-boot-h2-database/.gitignore rename to persistence-modules/spring-boot-persistence-h2/.gitignore diff --git a/persistence-modules/spring-boot-h2/README.md b/persistence-modules/spring-boot-persistence-h2/README.md similarity index 67% rename from persistence-modules/spring-boot-h2/README.md rename to persistence-modules/spring-boot-persistence-h2/README.md index af5f395440..377b7c8939 100644 --- a/persistence-modules/spring-boot-h2/README.md +++ b/persistence-modules/spring-boot-persistence-h2/README.md @@ -1,2 +1,3 @@ ### Relevant Articles: - [Access the Same In-Memory H2 Database in Multiple Spring Boot Applications](https://www.baeldung.com/spring-boot-access-h2-database-multiple-apps) +- [Spring Boot With H2 Database](https://www.baeldung.com/spring-boot-h2-database) \ No newline at end of file diff --git a/persistence-modules/spring-boot-h2/spring-boot-h2-database/pom.xml b/persistence-modules/spring-boot-persistence-h2/pom.xml similarity index 97% rename from persistence-modules/spring-boot-h2/spring-boot-h2-database/pom.xml rename to persistence-modules/spring-boot-persistence-h2/pom.xml index 882b88b535..4c8073ddb4 100644 --- a/persistence-modules/spring-boot-h2/spring-boot-h2-database/pom.xml +++ b/persistence-modules/spring-boot-persistence-h2/pom.xml @@ -14,7 +14,7 @@ parent-boot-2 com.baeldung 0.0.1-SNAPSHOT - ../../../parent-boot-2 + ../../parent-boot-2 diff --git a/persistence-modules/spring-boot-h2/spring-boot-h2-database/src/main/java/com/baeldung/h2db/auto/configuration/AutoConfigurationDemo.java b/persistence-modules/spring-boot-persistence-h2/src/main/java/com/baeldung/h2db/auto/configuration/AutoConfigurationDemo.java similarity index 100% rename from persistence-modules/spring-boot-h2/spring-boot-h2-database/src/main/java/com/baeldung/h2db/auto/configuration/AutoConfigurationDemo.java rename to persistence-modules/spring-boot-persistence-h2/src/main/java/com/baeldung/h2db/auto/configuration/AutoConfigurationDemo.java diff --git a/persistence-modules/spring-boot-h2/spring-boot-h2-database/src/main/java/com/baeldung/h2db/demo/client/ClientSpringBootApp.java b/persistence-modules/spring-boot-persistence-h2/src/main/java/com/baeldung/h2db/demo/client/ClientSpringBootApp.java similarity index 100% rename from persistence-modules/spring-boot-h2/spring-boot-h2-database/src/main/java/com/baeldung/h2db/demo/client/ClientSpringBootApp.java rename to persistence-modules/spring-boot-persistence-h2/src/main/java/com/baeldung/h2db/demo/client/ClientSpringBootApp.java diff --git a/persistence-modules/spring-boot-h2/spring-boot-h2-database/src/main/java/com/baeldung/h2db/demo/server/SpringBootApp.java b/persistence-modules/spring-boot-persistence-h2/src/main/java/com/baeldung/h2db/demo/server/SpringBootApp.java similarity index 100% rename from persistence-modules/spring-boot-h2/spring-boot-h2-database/src/main/java/com/baeldung/h2db/demo/server/SpringBootApp.java rename to persistence-modules/spring-boot-persistence-h2/src/main/java/com/baeldung/h2db/demo/server/SpringBootApp.java diff --git a/persistence-modules/spring-boot-persistence-h2/src/main/java/com/baeldung/h2db/springboot/SpringBootH2Application.java b/persistence-modules/spring-boot-persistence-h2/src/main/java/com/baeldung/h2db/springboot/SpringBootH2Application.java new file mode 100644 index 0000000000..378093cfa9 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-h2/src/main/java/com/baeldung/h2db/springboot/SpringBootH2Application.java @@ -0,0 +1,12 @@ +package com.baeldung.h2db.springboot; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SpringBootH2Application { + + public static void main(String... args) { + SpringApplication.run(SpringBootH2Application.class, args); + } +} diff --git a/persistence-modules/spring-boot-persistence-h2/src/main/java/com/baeldung/h2db/springboot/daos/UserRepository.java b/persistence-modules/spring-boot-persistence-h2/src/main/java/com/baeldung/h2db/springboot/daos/UserRepository.java new file mode 100644 index 0000000000..35e496e910 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-h2/src/main/java/com/baeldung/h2db/springboot/daos/UserRepository.java @@ -0,0 +1,10 @@ +package com.baeldung.h2db.springboot.daos; + + + + +import com.baeldung.h2db.springboot.models.User; +import org.springframework.data.repository.CrudRepository; + +public interface UserRepository extends CrudRepository { +} diff --git a/persistence-modules/spring-boot-persistence-h2/src/main/java/com/baeldung/h2db/springboot/models/User.java b/persistence-modules/spring-boot-persistence-h2/src/main/java/com/baeldung/h2db/springboot/models/User.java new file mode 100644 index 0000000000..fa3c01c035 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-h2/src/main/java/com/baeldung/h2db/springboot/models/User.java @@ -0,0 +1,54 @@ +package com.baeldung.h2db.springboot.models; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.Table; + +@Table(name = "users") +@Entity +public class User { + + @Id + @GeneratedValue + private int id; + + private String firstName; + + private String lastName; + + public User() { } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + @Override + public String toString() { + return "User{" + + "id=" + id + + ", firstName='" + firstName + '\'' + + ", lastName='" + lastName + '\'' + + '}'; + } +} diff --git a/persistence-modules/spring-boot-h2/spring-boot-h2-database/src/main/resources/application.properties b/persistence-modules/spring-boot-persistence-h2/src/main/resources/application.properties similarity index 84% rename from persistence-modules/spring-boot-h2/spring-boot-h2-database/src/main/resources/application.properties rename to persistence-modules/spring-boot-persistence-h2/src/main/resources/application.properties index 5e425a3550..109b389b58 100644 --- a/persistence-modules/spring-boot-h2/spring-boot-h2-database/src/main/resources/application.properties +++ b/persistence-modules/spring-boot-persistence-h2/src/main/resources/application.properties @@ -2,7 +2,7 @@ spring.datasource.url=jdbc:h2:mem:mydb spring.datasource.driverClassName=org.h2.Driver spring.datasource.username=sa spring.datasource.password= -spring.jpa.hibernate.ddl-auto=create +spring.jpa.hibernate.ddl-auto=create-drop spring.h2.console.enabled=true spring.h2.console.path=/h2-console debug=true \ No newline at end of file diff --git a/persistence-modules/spring-boot-persistence-h2/src/main/resources/data.sql b/persistence-modules/spring-boot-persistence-h2/src/main/resources/data.sql new file mode 100644 index 0000000000..2d7b446005 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-h2/src/main/resources/data.sql @@ -0,0 +1,13 @@ +DROP TABLE IF EXISTS billionaires; + +CREATE TABLE billionaires ( + id INT AUTO_INCREMENT PRIMARY KEY, + first_name VARCHAR(250) NOT NULL, + last_name VARCHAR(250) NOT NULL, + career VARCHAR(250) DEFAULT NULL +); + +INSERT INTO billionaires (first_name, last_name, career) VALUES +('Aliko', 'Dangote', 'Billionaire Industrialist'), +('Bill', 'Gates', 'Billionaire Tech Entrepreneur'), +('Folrunsho', 'Alakija', 'Billionaire Oil Magnate'); \ No newline at end of file diff --git a/persistence-modules/spring-boot-persistence-h2/src/test/java/com/baeldung/SpringBootH2IntegrationTest.java b/persistence-modules/spring-boot-persistence-h2/src/test/java/com/baeldung/SpringBootH2IntegrationTest.java new file mode 100644 index 0000000000..aecc63c599 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-h2/src/test/java/com/baeldung/SpringBootH2IntegrationTest.java @@ -0,0 +1,50 @@ +package com.baeldung; + +import com.baeldung.h2db.springboot.SpringBootH2Application; +import com.baeldung.h2db.springboot.daos.UserRepository; +import com.baeldung.h2db.springboot.models.User; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import java.util.List; + +import static org.junit.Assert.*; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = SpringBootH2Application.class) +public class SpringBootH2IntegrationTest { + + @Autowired + private UserRepository userRepository; + + @Test + public void contextLoads() { } + + @Test + public void givenUserProfile_whenAddUser_thenCreateNewUser() { + User user = new User(); + user.setFirstName("John"); + user.setLastName("Doe"); + userRepository.save(user); + List users = (List) userRepository.findAll(); + assertFalse(users.isEmpty()); + + String firstName = "Aliko"; + String lastName = "Dangote"; + User user1 = userRepository.findById(users.get(0).getId()).get(); + user1.setLastName(lastName); + user1.setFirstName(firstName); + userRepository.save(user1); + + user = userRepository.findById(user.getId()).get(); + assertEquals(user.getFirstName(), firstName); + assertEquals(user.getLastName(), lastName); + + userRepository.deleteById(user.getId()); + assertTrue( ((List) userRepository.findAll()).isEmpty()); + } + +} diff --git a/persistence-modules/spring-boot-h2/spring-boot-h2-database/src/test/java/com/baeldung/SpringContextIntegrationTest.java b/persistence-modules/spring-boot-persistence-h2/src/test/java/com/baeldung/SpringContextIntegrationTest.java similarity index 100% rename from persistence-modules/spring-boot-h2/spring-boot-h2-database/src/test/java/com/baeldung/SpringContextIntegrationTest.java rename to persistence-modules/spring-boot-persistence-h2/src/test/java/com/baeldung/SpringContextIntegrationTest.java diff --git a/persistence-modules/spring-boot-persistence-mongodb/README.md b/persistence-modules/spring-boot-persistence-mongodb/README.md index f093d4baf0..40f9f40749 100644 --- a/persistence-modules/spring-boot-persistence-mongodb/README.md +++ b/persistence-modules/spring-boot-persistence-mongodb/README.md @@ -1,3 +1,4 @@ # Relevant Articles - [Auto-Generated Field for MongoDB using Spring Boot](https://www.baeldung.com/spring-boot-mongodb-auto-generated-field) +- [Spring Boot Integration Testing with Embedded MongoDB](http://www.baeldung.com/spring-boot-embedded-mongodb) diff --git a/persistence-modules/spring-boot-persistence-mongodb/pom.xml b/persistence-modules/spring-boot-persistence-mongodb/pom.xml index 86b93c7826..585e54bf57 100644 --- a/persistence-modules/spring-boot-persistence-mongodb/pom.xml +++ b/persistence-modules/spring-boot-persistence-mongodb/pom.xml @@ -25,6 +25,11 @@ org.springframework.boot spring-boot-starter-data-mongodb + + de.flapdoodle.embed + de.flapdoodle.embed.mongo + test + org.junit.jupiter @@ -102,4 +107,4 @@ - \ No newline at end of file + diff --git a/persistence-modules/spring-boot-persistence-mongodb/src/main/java/com/baeldung/mongodb/events/UserModelListener.java b/persistence-modules/spring-boot-persistence-mongodb/src/main/java/com/baeldung/mongodb/events/UserModelListener.java index 24b53f3d2d..2fe81f7ef4 100644 --- a/persistence-modules/spring-boot-persistence-mongodb/src/main/java/com/baeldung/mongodb/events/UserModelListener.java +++ b/persistence-modules/spring-boot-persistence-mongodb/src/main/java/com/baeldung/mongodb/events/UserModelListener.java @@ -21,7 +21,9 @@ public class UserModelListener extends AbstractMongoEventListener { @Override public void onBeforeConvert(BeforeConvertEvent event) { - event.getSource().setId(sequenceGenerator.generateSequence(User.SEQUENCE_NAME)); + if (event.getSource().getId() < 1) { + event.getSource().setId(sequenceGenerator.generateSequence(User.SEQUENCE_NAME)); + } } diff --git a/spring-boot/src/test/java/com/baeldung/mongodb/ManualEmbeddedMongoDbIntegrationTest.java b/persistence-modules/spring-boot-persistence-mongodb/src/test/java/com/baeldung/mongodb/ManualEmbeddedMongoDbIntegrationTest.java similarity index 100% rename from spring-boot/src/test/java/com/baeldung/mongodb/ManualEmbeddedMongoDbIntegrationTest.java rename to persistence-modules/spring-boot-persistence-mongodb/src/test/java/com/baeldung/mongodb/ManualEmbeddedMongoDbIntegrationTest.java diff --git a/spring-boot/src/test/java/com/baeldung/mongodb/MongoDbSpringIntegrationTest.java b/persistence-modules/spring-boot-persistence-mongodb/src/test/java/com/baeldung/mongodb/MongoDbSpringIntegrationTest.java similarity index 90% rename from spring-boot/src/test/java/com/baeldung/mongodb/MongoDbSpringIntegrationTest.java rename to persistence-modules/spring-boot-persistence-mongodb/src/test/java/com/baeldung/mongodb/MongoDbSpringIntegrationTest.java index 39127f62e9..954bae3684 100644 --- a/spring-boot/src/test/java/com/baeldung/mongodb/MongoDbSpringIntegrationTest.java +++ b/persistence-modules/spring-boot-persistence-mongodb/src/test/java/com/baeldung/mongodb/MongoDbSpringIntegrationTest.java @@ -2,7 +2,6 @@ package com.baeldung.mongodb; import static org.assertj.core.api.Assertions.assertThat; -import org.baeldung.boot.Application; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -12,10 +11,11 @@ import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; +import com.baeldung.SpringBootPersistenceApplication; import com.mongodb.BasicDBObjectBuilder; import com.mongodb.DBObject; -@ContextConfiguration(classes = Application.class) +@ContextConfiguration(classes = SpringBootPersistenceApplication.class) @DataMongoTest @ExtendWith(SpringExtension.class) public class MongoDbSpringIntegrationTest { diff --git a/persistence-modules/spring-boot-persistence/README.MD b/persistence-modules/spring-boot-persistence/README.MD index f62ca57a19..709f505ea9 100644 --- a/persistence-modules/spring-boot-persistence/README.MD +++ b/persistence-modules/spring-boot-persistence/README.MD @@ -7,3 +7,5 @@ - [Hibernate Field Naming with Spring Boot](https://www.baeldung.com/hibernate-field-naming-spring-boot) - [Integrating Spring Boot with HSQLDB](https://www.baeldung.com/spring-boot-hsqldb) - [Configuring a DataSource Programmatically in Spring Boot](https://www.baeldung.com/spring-boot-configure-data-source-programmatic) +- [Resolving “Failed to Configure a DataSource” Error](https://www.baeldung.com/spring-boot-failed-to-configure-data-source) +- [Spring Boot with Hibernate](https://www.baeldung.com/spring-boot-hibernate) diff --git a/persistence-modules/spring-boot-persistence/pom.xml b/persistence-modules/spring-boot-persistence/pom.xml index d9d3a9f9b7..ca7c7306e7 100644 --- a/persistence-modules/spring-boot-persistence/pom.xml +++ b/persistence-modules/spring-boot-persistence/pom.xml @@ -25,6 +25,12 @@ org.springframework.boot spring-boot-starter-data-jpa + + + com.zaxxer + HikariCP + + org.springframework.boot @@ -48,6 +54,11 @@ mysql mysql-connector-java + + javax.validation + validation-api + ${validation-api.version} + @@ -73,6 +84,7 @@ 9.0.10 1.4.197 2.23.0 + 2.0.1.Final diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/Application.java b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/Application.java similarity index 93% rename from persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/Application.java rename to persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/Application.java index 43888c2d67..cb0d0c1532 100644 --- a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/Application.java +++ b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/Application.java @@ -1,4 +1,4 @@ -package com.baeldung; +package com.baeldung.boot; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/config/H2JpaConfig.java b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/config/H2JpaConfig.java index 547a905d91..c5c77be56f 100644 --- a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/config/H2JpaConfig.java +++ b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/config/H2JpaConfig.java @@ -1,13 +1,9 @@ package com.baeldung.boot.config; -import java.util.Properties; - -import javax.persistence.EntityManagerFactory; -import javax.sql.DataSource; - import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; import org.springframework.context.annotation.PropertySource; import org.springframework.core.env.Environment; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; @@ -17,10 +13,17 @@ import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; import org.springframework.transaction.annotation.EnableTransactionManagement; +import javax.persistence.EntityManagerFactory; +import javax.sql.DataSource; +import java.util.Properties; + @Configuration @EnableJpaRepositories(basePackages = { "com.baeldung.boot.repository", "com.baeldung.repository" }) @PropertySource("classpath:persistence-generic-entity.properties") @EnableTransactionManagement +@Profile("default") //only required to allow H2JpaConfig and H2TestProfileJPAConfig to coexist in same project + //this demo project is showcasing several ways to achieve the same end, and class-level + //Profile annotations are only necessary because the different techniques are sharing a project public class H2JpaConfig { @Autowired diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/domain/Car.java b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/domain/Car.java new file mode 100644 index 0000000000..736c12fb07 --- /dev/null +++ b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/domain/Car.java @@ -0,0 +1,48 @@ +package com.baeldung.boot.domain; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +/** + * @author paullatzelsperger + * @since 2019-03-20 + */ +@Entity +public class Car { + + @Id + @GeneratedValue + private int id; + private Integer power; + private String model; + + public Car() { + + } + + public Car(int power, String model) { + this.power = power; + this.model = model; + } + + public Integer getPower() { + return power; + } + + public void setPower(Integer power) { + this.power = power; + } + + public String getModel() { + return model; + } + + public void setModel(String model) { + this.model = model; + } + + public int getId() { + return id; + } +} diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/domain/Country.java b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/domain/Country.java similarity index 94% rename from persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/domain/Country.java rename to persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/domain/Country.java index e6a88c7121..59227f6412 100644 --- a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/domain/Country.java +++ b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/domain/Country.java @@ -1,4 +1,4 @@ -package com.baeldung.domain; +package com.baeldung.boot.domain; import static javax.persistence.GenerationType.IDENTITY; diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/domain/User.java b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/domain/User.java similarity index 96% rename from persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/domain/User.java rename to persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/domain/User.java index 9d1fc4c8ad..bdbe75cd0c 100644 --- a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/domain/User.java +++ b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/domain/User.java @@ -1,4 +1,4 @@ -package com.baeldung.domain; +package com.baeldung.boot.domain; import javax.persistence.Entity; import javax.persistence.GeneratedValue; diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/naming/HibernateConfig.java b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/naming/HibernateConfig.java similarity index 95% rename from persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/naming/HibernateConfig.java rename to persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/naming/HibernateConfig.java index 897e34d406..adde46e2b6 100644 --- a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/naming/HibernateConfig.java +++ b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/naming/HibernateConfig.java @@ -1,4 +1,4 @@ -package com.baeldung.naming; +package com.baeldung.boot.naming; import org.hibernate.jpa.boot.spi.IntegratorProvider; import org.springframework.boot.autoconfigure.orm.jpa.HibernatePropertiesCustomizer; diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/naming/MetadataExtractorIntegrator.java b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/naming/MetadataExtractorIntegrator.java similarity index 97% rename from persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/naming/MetadataExtractorIntegrator.java rename to persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/naming/MetadataExtractorIntegrator.java index 24b5cdea64..8702624d3f 100644 --- a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/naming/MetadataExtractorIntegrator.java +++ b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/naming/MetadataExtractorIntegrator.java @@ -1,4 +1,4 @@ -package com.baeldung.naming; +package com.baeldung.boot.naming; import org.hibernate.boot.Metadata; import org.hibernate.boot.model.relational.Database; diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/naming/entity/Account.java b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/naming/entity/Account.java similarity index 90% rename from persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/naming/entity/Account.java rename to persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/naming/entity/Account.java index 6145818c5b..00e90a5ec9 100644 --- a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/naming/entity/Account.java +++ b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/naming/entity/Account.java @@ -1,4 +1,4 @@ -package com.baeldung.naming.entity; +package com.baeldung.boot.naming.entity; import javax.persistence.Column; import javax.persistence.Entity; diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/naming/entity/Preference.java b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/naming/entity/Preference.java similarity index 84% rename from persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/naming/entity/Preference.java rename to persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/naming/entity/Preference.java index 928884a2c5..7711156864 100644 --- a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/naming/entity/Preference.java +++ b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/naming/entity/Preference.java @@ -1,4 +1,4 @@ -package com.baeldung.naming.entity; +package com.baeldung.boot.naming.entity; import javax.persistence.Entity; import javax.persistence.Id; diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/repository/CarRepository.java b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/repository/CarRepository.java new file mode 100644 index 0000000000..0176b14169 --- /dev/null +++ b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/repository/CarRepository.java @@ -0,0 +1,26 @@ +package com.baeldung.boot.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +import com.baeldung.boot.domain.Car; + +/** + * @author paullatzelsperger + * @since 2019-03-20 + */ +@Repository +public interface CarRepository extends JpaRepository { + + boolean existsCarByPower(int power); + + boolean existsCarByModel(String model); + + @Query("select case when count(c)> 0 then true else false end from Car c where c.model = :model") + boolean existsCarExactCustomQuery(@Param("model") String model); + + @Query("select case when count(c)> 0 then true else false end from Car c where lower(c.model) like lower(:model)") + boolean existsCarLikeCustomQuery(@Param("model") String model); +} diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/repository/UserRepository.java b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/repository/UserRepository.java similarity index 97% rename from persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/repository/UserRepository.java rename to persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/repository/UserRepository.java index bdc1e0af33..eae80b2e92 100644 --- a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/repository/UserRepository.java +++ b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/repository/UserRepository.java @@ -1,6 +1,5 @@ -package com.baeldung.repository; +package com.baeldung.boot.repository; -import com.baeldung.domain.User; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; @@ -11,6 +10,8 @@ import org.springframework.data.repository.query.Param; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Repository; +import com.baeldung.boot.domain.User; + import java.util.Collection; import java.util.List; import java.util.Optional; diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/disabledatasource/application/Application.java b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/disabledatasource/application/Application.java new file mode 100644 index 0000000000..79273ba141 --- /dev/null +++ b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/disabledatasource/application/Application.java @@ -0,0 +1,13 @@ +package com.baeldung.disabledatasource.application; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; + +@SpringBootApplication(exclude=DataSourceAutoConfiguration.class) +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } +} diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/jpadefaultvalues/application/Application.java b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/jpadefaultvalues/application/Application.java new file mode 100644 index 0000000000..3b96f68583 --- /dev/null +++ b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/jpadefaultvalues/application/Application.java @@ -0,0 +1,14 @@ +package com.baeldung.jpadefaultvalues.application; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ApplicationContext; + +@SpringBootApplication +public class Application { + private static ApplicationContext applicationContext; + + public static void main(String[] args) { + applicationContext = SpringApplication.run(Application.class, args); + } +} diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/jpadefaultvalues/application/User.java b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/jpadefaultvalues/application/User.java new file mode 100644 index 0000000000..e271c01815 --- /dev/null +++ b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/jpadefaultvalues/application/User.java @@ -0,0 +1,55 @@ +package com.baeldung.jpadefaultvalues.application; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +@Entity +public class User { + + @Id + @GeneratedValue + private Long id; + + @Column(columnDefinition = "varchar(255) default 'John Snow'") + private String name = "John Snow"; + + @Column(columnDefinition = "integer default 25") + private Integer age = 25; + + @Column(columnDefinition = "boolean default false") + private Boolean locked = false; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getAge() { + return age; + } + + public void setAge(Integer age) { + this.age = age; + } + + public Boolean getLocked() { + return locked; + } + + public void setLocked(Boolean locked) { + this.locked = locked; + } +} diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/jpadefaultvalues/application/UserRepository.java b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/jpadefaultvalues/application/UserRepository.java new file mode 100644 index 0000000000..ca0e4c4d71 --- /dev/null +++ b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/jpadefaultvalues/application/UserRepository.java @@ -0,0 +1,8 @@ +package com.baeldung.jpadefaultvalues.application; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface UserRepository extends JpaRepository { +} diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springboothibernate/application/ExampleApplication.java b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springboothibernate/application/ExampleApplication.java new file mode 100644 index 0000000000..4b6a93ab8b --- /dev/null +++ b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springboothibernate/application/ExampleApplication.java @@ -0,0 +1,14 @@ +package com.baeldung.springboothibernate.application; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class ExampleApplication { + + public static void main(String[] args) { + SpringApplication.run(ExampleApplication.class, args); + } + +} + diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springboothibernate/application/datasources/DataSourceBean.java b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springboothibernate/application/datasources/DataSourceBean.java new file mode 100644 index 0000000000..54a0c4f077 --- /dev/null +++ b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springboothibernate/application/datasources/DataSourceBean.java @@ -0,0 +1,21 @@ +package com.baeldung.springboothibernate.application.datasources; + +import org.springframework.boot.jdbc.DataSourceBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import javax.sql.DataSource; + +@Configuration +public class DataSourceBean { + + @Bean + public DataSource getDataSource() { + DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create(); + dataSourceBuilder.driverClassName("org.h2.Driver"); + dataSourceBuilder.url("jdbc:h2:mem:test"); + dataSourceBuilder.username("SA"); + dataSourceBuilder.password(""); + return dataSourceBuilder.build(); + } +} diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springboothibernate/application/models/Book.java b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springboothibernate/application/models/Book.java new file mode 100644 index 0000000000..7562c072c7 --- /dev/null +++ b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springboothibernate/application/models/Book.java @@ -0,0 +1,40 @@ +package com.baeldung.springboothibernate.application.models; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +@Entity +public class Book { + + @Id + @GeneratedValue + private Long id; + private String name; + + public Book() { + super(); + } + + public Book(Long id, String name) { + super(); + this.id = id; + this.name = name; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springboothibernate/application/repositories/BookRepository.java b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springboothibernate/application/repositories/BookRepository.java new file mode 100644 index 0000000000..3d5789fb4d --- /dev/null +++ b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springboothibernate/application/repositories/BookRepository.java @@ -0,0 +1,9 @@ +package com.baeldung.springboothibernate.application.repositories; + +import com.baeldung.springboothibernate.application.models.Book; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface BookRepository extends JpaRepository { +} diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springboothibernate/application/services/BookService.java b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springboothibernate/application/services/BookService.java new file mode 100644 index 0000000000..e495045bab --- /dev/null +++ b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springboothibernate/application/services/BookService.java @@ -0,0 +1,19 @@ +package com.baeldung.springboothibernate.application.services; + +import com.baeldung.springboothibernate.application.models.Book; +import com.baeldung.springboothibernate.application.repositories.BookRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class BookService { + + @Autowired + private BookRepository bookRepository; + + public List list() { + return bookRepository.findAll(); + } +} diff --git a/persistence-modules/spring-boot-persistence/src/main/resources/application.properties b/persistence-modules/spring-boot-persistence/src/main/resources/application.properties index b0caf4a809..7b5a467a2b 100644 --- a/persistence-modules/spring-boot-persistence/src/main/resources/application.properties +++ b/persistence-modules/spring-boot-persistence/src/main/resources/application.properties @@ -3,3 +3,9 @@ spring.datasource.url = jdbc:hsqldb:mem:test;DB_CLOSE_DELAY=-1 spring.datasource.username = sa spring.datasource.password = spring.jpa.hibernate.ddl-auto = create + +# Enabling H2 Console +spring.h2.console.enabled=true + +# Uppercase Table Names +spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl \ No newline at end of file diff --git a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/SpringBootH2IntegrationTest.java b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/SpringBootH2IntegrationTest.java index ecacf62285..01082cc6e2 100644 --- a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/SpringBootH2IntegrationTest.java +++ b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/SpringBootH2IntegrationTest.java @@ -9,6 +9,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import com.baeldung.boot.Application; import com.baeldung.boot.config.H2JpaConfig; import com.baeldung.boot.domain.GenericEntity; import com.baeldung.boot.repository.GenericEntityRepository; diff --git a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/SpringBootJPAIntegrationTest.java b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/SpringBootJPAIntegrationTest.java index 01fae2fb4d..f1ab442949 100644 --- a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/SpringBootJPAIntegrationTest.java +++ b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/SpringBootJPAIntegrationTest.java @@ -9,6 +9,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; +import com.baeldung.boot.Application; import com.baeldung.boot.domain.GenericEntity; import com.baeldung.boot.repository.GenericEntityRepository; diff --git a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/SpringBootProfileIntegrationTest.java b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/SpringBootProfileIntegrationTest.java index 65a75d7bfe..d7bb44e133 100644 --- a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/SpringBootProfileIntegrationTest.java +++ b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/SpringBootProfileIntegrationTest.java @@ -1,8 +1,9 @@ package com.baeldung; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; - +import com.baeldung.boot.Application; +import com.baeldung.boot.domain.GenericEntity; +import com.baeldung.boot.repository.GenericEntityRepository; +import com.baeldung.config.H2TestProfileJPAConfig; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; @@ -10,9 +11,8 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.junit4.SpringRunner; -import com.baeldung.boot.domain.GenericEntity; -import com.baeldung.boot.repository.GenericEntityRepository; -import com.baeldung.config.H2TestProfileJPAConfig; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; @RunWith(SpringRunner.class) @SpringBootTest(classes = { Application.class, H2TestProfileJPAConfig.class }) diff --git a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/naming/LegacyJpaImplNamingIntegrationTest.java b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/boot/naming/LegacyJpaImplNamingIntegrationTest.java similarity index 90% rename from persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/naming/LegacyJpaImplNamingIntegrationTest.java rename to persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/boot/naming/LegacyJpaImplNamingIntegrationTest.java index e68be3bed8..2feee10980 100644 --- a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/naming/LegacyJpaImplNamingIntegrationTest.java +++ b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/boot/naming/LegacyJpaImplNamingIntegrationTest.java @@ -1,6 +1,5 @@ -package com.baeldung.naming; +package com.baeldung.boot.naming; -import com.baeldung.naming.entity.Account; import org.assertj.core.api.SoftAssertions; import org.hibernate.boot.Metadata; import org.hibernate.mapping.PersistentClass; @@ -8,15 +7,20 @@ import org.hibernate.mapping.Table; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit4.SpringRunner; +import com.baeldung.boot.naming.NamingConfig.Config; +import com.baeldung.boot.naming.entity.Account; + @RunWith(SpringRunner.class) @DataJpaTest @TestPropertySource(properties = { "spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl", "spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl" }) +@Import(Config.class) public class LegacyJpaImplNamingIntegrationTest extends NamingConfig { @Test diff --git a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/naming/NamingConfig.java b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/boot/naming/NamingConfig.java similarity index 92% rename from persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/naming/NamingConfig.java rename to persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/boot/naming/NamingConfig.java index c3ef37aeb4..9b6574b1d7 100644 --- a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/naming/NamingConfig.java +++ b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/boot/naming/NamingConfig.java @@ -1,4 +1,4 @@ -package com.baeldung.naming; +package com.baeldung.boot.naming; import org.springframework.boot.autoconfigure.orm.jpa.HibernatePropertiesCustomizer; import org.springframework.boot.test.context.TestConfiguration; diff --git a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/naming/SpringBootDefaultNamingIntegrationTest.java b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/boot/naming/SpringBootDefaultNamingIntegrationTest.java similarity index 90% rename from persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/naming/SpringBootDefaultNamingIntegrationTest.java rename to persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/boot/naming/SpringBootDefaultNamingIntegrationTest.java index 089430aabb..c5c320f70c 100644 --- a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/naming/SpringBootDefaultNamingIntegrationTest.java +++ b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/boot/naming/SpringBootDefaultNamingIntegrationTest.java @@ -1,6 +1,5 @@ -package com.baeldung.naming; +package com.baeldung.boot.naming; -import com.baeldung.naming.entity.Account; import org.assertj.core.api.SoftAssertions; import org.hibernate.boot.Metadata; import org.hibernate.mapping.PersistentClass; @@ -8,10 +7,12 @@ import org.hibernate.mapping.Table; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit4.SpringRunner; -import static org.assertj.core.api.Assertions.assertThat; +import com.baeldung.boot.naming.NamingConfig.Config; +import com.baeldung.boot.naming.entity.Account; @RunWith(SpringRunner.class) @DataJpaTest @@ -19,6 +20,7 @@ import static org.assertj.core.api.Assertions.assertThat; "spring.jpa.hibernate.naming.physical-strategy=org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy", "spring.jpa.hibernate.naming.implicit-strategy=org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy" }) +@Import(Config.class) public class SpringBootDefaultNamingIntegrationTest extends NamingConfig { @Test diff --git a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/naming/StrategyLegacyHbmImplIntegrationTest.java b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/boot/naming/StrategyLegacyHbmImplIntegrationTest.java similarity index 88% rename from persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/naming/StrategyLegacyHbmImplIntegrationTest.java rename to persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/boot/naming/StrategyLegacyHbmImplIntegrationTest.java index 046755d9bc..ef978e5a98 100644 --- a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/naming/StrategyLegacyHbmImplIntegrationTest.java +++ b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/boot/naming/StrategyLegacyHbmImplIntegrationTest.java @@ -1,6 +1,9 @@ -package com.baeldung.naming; +package com.baeldung.boot.naming; + +import com.baeldung.boot.naming.MetadataExtractorIntegrator; +import com.baeldung.boot.naming.NamingConfig.Config; +import com.baeldung.boot.naming.entity.Preference; -import com.baeldung.naming.entity.Preference; import org.assertj.core.api.SoftAssertions; import org.hibernate.boot.Metadata; import org.hibernate.mapping.PersistentClass; @@ -8,6 +11,7 @@ import org.hibernate.mapping.Table; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit4.SpringRunner; @@ -19,6 +23,7 @@ import java.util.Collection; "spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl", "spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyHbmImpl", }) +@Import(Config.class) public class StrategyLegacyHbmImplIntegrationTest extends NamingConfig { @Test diff --git a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/repository/UserRepositoryIntegrationTest.java b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/boot/test/UserRepositoryMultipleSqlFilesIntTest.java similarity index 66% rename from persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/repository/UserRepositoryIntegrationTest.java rename to persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/boot/test/UserRepositoryMultipleSqlFilesIntTest.java index af5abc22d7..f1f6e85d8c 100644 --- a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/repository/UserRepositoryIntegrationTest.java +++ b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/boot/test/UserRepositoryMultipleSqlFilesIntTest.java @@ -1,12 +1,15 @@ -package com.baeldung.repository; +package com.baeldung.boot.test; -import com.baeldung.domain.User; 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.test.context.ActiveProfiles; import org.springframework.test.context.junit4.SpringRunner; +import com.baeldung.boot.domain.User; +import com.baeldung.boot.repository.UserRepository; + import java.util.Collection; import static org.assertj.core.api.Assertions.assertThat; @@ -16,7 +19,8 @@ import static org.assertj.core.api.Assertions.assertThat; */ @RunWith(SpringRunner.class) @DataJpaTest -public class UserRepositoryIntegrationTest { +@ActiveProfiles("multiplesqlfiles") +public class UserRepositoryMultipleSqlFilesIntTest { @Autowired private UserRepository userRepository; @@ -24,7 +28,7 @@ public class UserRepositoryIntegrationTest { public void givenTwoImportFilesWhenFindAllShouldReturnSixUsers() { Collection users = userRepository.findAll(); - assertThat(users.size()).isEqualTo(9); + assertThat(users.size()).isEqualTo(6); } } diff --git a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/config/H2TestProfileJPAConfig.java b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/config/H2TestProfileJPAConfig.java index bcbded95fb..f73000a10e 100644 --- a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/config/H2TestProfileJPAConfig.java +++ b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/config/H2TestProfileJPAConfig.java @@ -1,10 +1,5 @@ package com.baeldung.config; -import java.util.Properties; - -import javax.persistence.EntityManagerFactory; -import javax.sql.DataSource; - import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -17,9 +12,16 @@ import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; import org.springframework.transaction.annotation.EnableTransactionManagement; +import javax.persistence.EntityManagerFactory; +import javax.sql.DataSource; +import java.util.Properties; + @Configuration @EnableJpaRepositories(basePackages = { "com.baeldung.repository", "com.baeldung.boot.repository" }) @EnableTransactionManagement +@Profile("test") //only required to allow H2JpaConfig and H2TestProfileJPAConfig to coexist in same project + //this demo project is showcasing several ways to achieve the same end, and class-level + //Profile annotations are only necessary because the different techniques are sharing a project public class H2TestProfileJPAConfig { @Autowired @@ -41,7 +43,7 @@ public class H2TestProfileJPAConfig { public LocalContainerEntityManagerFactoryBean entityManagerFactory() { final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); em.setDataSource(dataSource()); - em.setPackagesToScan(new String[] { "com.baeldung.domain", "com.baeldung.boot.domain" }); + em.setPackagesToScan(new String[] { "com.baeldung.boot.domain" }); em.setJpaVendorAdapter(new HibernateJpaVendorAdapter()); em.setJpaProperties(additionalProperties()); return em; diff --git a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/jpadefaultvalues/application/UserDefaultValuesUnitTest.java b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/jpadefaultvalues/application/UserDefaultValuesUnitTest.java new file mode 100644 index 0000000000..52a5c4dcd6 --- /dev/null +++ b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/jpadefaultvalues/application/UserDefaultValuesUnitTest.java @@ -0,0 +1,56 @@ +package com.baeldung.jpadefaultvalues.application; + +import com.baeldung.jpadefaultvalues.application.User; +import com.baeldung.jpadefaultvalues.application.UserRepository; + +import org.junit.Test; +import org.junit.Ignore; +import org.junit.runner.RunWith; + +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.beans.factory.annotation.Autowired; + +import static org.junit.Assert.*; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class UserDefaultValuesUnitTest { + + @Autowired + private UserRepository userRepository; + + @Test + @Ignore // SQL default values are also defined + public void saveUser_shouldSaveWithDefaultFieldValues() { + User user = new User(); + user = userRepository.save(user); + + assertEquals(user.getName(), "John Snow"); + assertEquals(25, (int) user.getAge()); + assertFalse(user.getLocked()); + } + + @Test + @Ignore // SQL default values are also defined + public void saveUser_shouldSaveWithNullName() { + User user = new User(); + user.setName(null); + user = userRepository.save(user); + + assertNull(user.getName()); + assertEquals(25, (int) user.getAge()); + assertFalse(user.getLocked()); + } + + @Test + public void saveUser_shouldSaveWithDefaultSqlValues() { + User user = new User(); + user = userRepository.save(user); + + assertEquals(user.getName(), "John Snow"); + assertEquals(25, (int) user.getAge()); + assertFalse(user.getLocked()); + } + +} diff --git a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/springbootdatasourceconfig/tests/UserRepositoryIntegrationTest.java b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/springbootdatasourceconfig/application/tests/UserRepositoryIntegrationTest.java similarity index 79% rename from persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/springbootdatasourceconfig/tests/UserRepositoryIntegrationTest.java rename to persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/springbootdatasourceconfig/application/tests/UserRepositoryIntegrationTest.java index f27681021e..e9824fce44 100644 --- a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/springbootdatasourceconfig/tests/UserRepositoryIntegrationTest.java +++ b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/springbootdatasourceconfig/application/tests/UserRepositoryIntegrationTest.java @@ -1,15 +1,17 @@ -package com.baeldung.springbootdatasourceconfig.tests; +package com.baeldung.springbootdatasourceconfig.application.tests; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; + +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.test.context.junit4.SpringRunner; import com.baeldung.springbootdatasourceconfig.application.entities.User; import com.baeldung.springbootdatasourceconfig.application.repositories.UserRepository; -import java.util.List; -import java.util.Optional; -import org.junit.Test; -import org.springframework.beans.factory.annotation.Autowired; -import static org.assertj.core.api.Assertions.assertThat; -import org.junit.runner.RunWith; -import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; -import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) @DataJpaTest @@ -23,6 +25,7 @@ public class UserRepositoryIntegrationTest { userRepository.save(new User("Bob", "bob@domain.com")); List users = (List) userRepository.findAll(); - assertThat(users.size()).isEqualTo(1); + // 2 additional users are saved in the CommandLineRunner bean + assertThat(users.size()).isEqualTo(3); } } diff --git a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/springboothibernate/application/tests/BookServiceUnitTest.java b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/springboothibernate/application/tests/BookServiceUnitTest.java new file mode 100644 index 0000000000..655a852001 --- /dev/null +++ b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/springboothibernate/application/tests/BookServiceUnitTest.java @@ -0,0 +1,27 @@ +package com.baeldung.springboothibernate.application.tests; + +import com.baeldung.springboothibernate.application.models.Book; +import com.baeldung.springboothibernate.application.services.BookService; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import java.util.List; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class BookServiceUnitTest { + + @Autowired + private BookService bookService; + + @Test + public void whenApplicationStarts_thenHibernateCreatesInitialRecords() { + List books = bookService.list(); + + Assert.assertEquals(books.size(), 3); + } +} diff --git a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/tomcatconnectionpool/test/application/SpringBootTomcatConnectionPoolIntegrationTest.java b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/tomcatconnectionpool/test/application/SpringBootTomcatConnectionPoolIntegrationTest.java index eb000bbc09..5400d76fbe 100644 --- a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/tomcatconnectionpool/test/application/SpringBootTomcatConnectionPoolIntegrationTest.java +++ b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/tomcatconnectionpool/test/application/SpringBootTomcatConnectionPoolIntegrationTest.java @@ -5,11 +5,14 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.junit4.SpringRunner; + +import com.baeldung.tomcatconnectionpool.application.SpringBootConsoleApplication; + import static org.assertj.core.api.Assertions.*; import org.springframework.boot.test.context.SpringBootTest; @RunWith(SpringRunner.class) -@SpringBootTest +@SpringBootTest(classes = {SpringBootConsoleApplication.class}) public class SpringBootTomcatConnectionPoolIntegrationTest { @Autowired diff --git a/persistence-modules/spring-boot-persistence/src/test/resources/application-multiplesqlfiles.properties b/persistence-modules/spring-boot-persistence/src/test/resources/application-multiplesqlfiles.properties new file mode 100644 index 0000000000..06efc25f38 --- /dev/null +++ b/persistence-modules/spring-boot-persistence/src/test/resources/application-multiplesqlfiles.properties @@ -0,0 +1 @@ +spring.jpa.properties.hibernate.hbm2ddl.import_files=import_active_users.sql,import_inactive_users.sql \ No newline at end of file diff --git a/persistence-modules/spring-boot-persistence/src/test/resources/application.properties b/persistence-modules/spring-boot-persistence/src/test/resources/application.properties index a5c1d983cf..3a6470c8dc 100644 --- a/persistence-modules/spring-boot-persistence/src/test/resources/application.properties +++ b/persistence-modules/spring-boot-persistence/src/test/resources/application.properties @@ -12,5 +12,5 @@ hibernate.cache.use_second_level_cache=true hibernate.cache.use_query_cache=true hibernate.cache.region.factory_class=org.hibernate.cache.ehcache.EhCacheRegionFactory -spring.jpa.properties.hibernate.hbm2ddl.import_files=migrated_users.sql +spring.jpa.properties.hibernate.hbm2ddl.import_files=migrated_users.sql, import_books.sql spring.datasource.data=import_*_users.sql \ No newline at end of file diff --git a/persistence-modules/spring-boot-persistence/src/test/resources/import_books.sql b/persistence-modules/spring-boot-persistence/src/test/resources/import_books.sql new file mode 100644 index 0000000000..8eaf972a00 --- /dev/null +++ b/persistence-modules/spring-boot-persistence/src/test/resources/import_books.sql @@ -0,0 +1,3 @@ +insert into book values(1, 'The Tartar Steppe'); +insert into book values(2, 'Poem Strip'); +insert into book values(3, 'Restless Nights: Selected Stories of Dino Buzzati'); \ No newline at end of file diff --git a/persistence-modules/spring-data-cassandra-reactive/pom.xml b/persistence-modules/spring-data-cassandra-reactive/pom.xml index d2bc574ee9..bc8f49862d 100644 --- a/persistence-modules/spring-data-cassandra-reactive/pom.xml +++ b/persistence-modules/spring-data-cassandra-reactive/pom.xml @@ -21,7 +21,7 @@ org.springframework.data spring-data-cassandra - 2.1.2.RELEASE + ${spring-data-cassandra.version} io.projectreactor @@ -53,6 +53,7 @@ UTF-8 1.8 + 2.1.2.RELEASE diff --git a/persistence-modules/spring-data-couchbase-2/README.md b/persistence-modules/spring-data-couchbase-2/README.md index 2b6a1faddf..3145fc653a 100644 --- a/persistence-modules/spring-data-couchbase-2/README.md +++ b/persistence-modules/spring-data-couchbase-2/README.md @@ -2,7 +2,7 @@ ### Relevant Articles: - [Intro to Spring Data Couchbase](http://www.baeldung.com/spring-data-couchbase) -- [Entity Validation, Query Consistency, and Optimistic Locking in Spring Data Couchbase](http://www.baeldung.com/entity-validation-locking-and-query-consistency-in-spring-data-couchbase) +- [Entity Validation, Optimistic Locking, and Query Consistency in Spring Data Couchbase](http://www.baeldung.com/entity-validation-locking-and-query-consistency-in-spring-data-couchbase) - [Multiple Buckets and Spatial View Queries in Spring Data Couchbase](http://www.baeldung.com/spring-data-couchbase-buckets-and-spatial-view-queries) ### Overview diff --git a/persistence-modules/spring-data-jpa-2/README.md b/persistence-modules/spring-data-jpa-2/README.md new file mode 100644 index 0000000000..41381ab82a --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/README.md @@ -0,0 +1,6 @@ +========= + +## Spring Data JPA Example Project + +### Relevant Articles: +- [Spring Data JPA – Derived Delete Methods](https://www.baeldung.com/spring-data-jpa-deleteby) diff --git a/persistence-modules/spring-data-jpa-2/pom.xml b/persistence-modules/spring-data-jpa-2/pom.xml new file mode 100644 index 0000000000..fbc19810ef --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/pom.xml @@ -0,0 +1,45 @@ + + + 4.0.0 + + com.baeldung + spring-data-jpa-2 + spring-data-jpa + + + parent-boot-2 + com.baeldung + 0.0.1-SNAPSHOT + ../../parent-boot-2 + + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + com.h2database + h2 + + + + net.ttddyy + datasource-proxy + 1.4.1 + + + + com.fasterxml.jackson.core + jackson-databind + + + + org.springframework + spring-oxm + + + \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/Application.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/Application.java new file mode 100644 index 0000000000..3ea3d113da --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/Application.java @@ -0,0 +1,13 @@ +package com.baeldung; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/batchinserts/DatasourceProxyBeanPostProcessor.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/batchinserts/DatasourceProxyBeanPostProcessor.java new file mode 100644 index 0000000000..504357db44 --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/batchinserts/DatasourceProxyBeanPostProcessor.java @@ -0,0 +1,53 @@ +package com.baeldung.batchinserts; + +import java.lang.reflect.Method; +import javax.sql.DataSource; +import net.ttddyy.dsproxy.support.ProxyDataSourceBuilder; +import org.aopalliance.intercept.MethodInterceptor; +import org.aopalliance.intercept.MethodInvocation; +import org.springframework.aop.framework.ProxyFactory; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Component; +import org.springframework.util.ReflectionUtils; + +@Component +@Profile("batchinserts") +public class DatasourceProxyBeanPostProcessor implements BeanPostProcessor { + + @Override + public Object postProcessBeforeInitialization(final Object bean, final String beanName) throws BeansException { + return bean; + } + + @Override + public Object postProcessAfterInitialization(final Object bean, final String beanName) throws BeansException { + if (bean instanceof DataSource) { + ProxyFactory factory = new ProxyFactory(bean); + factory.setProxyTargetClass(true); + factory.addAdvice(new ProxyDataSourceInterceptor((DataSource) bean)); + return factory.getProxy(); + } + + return bean; + } + + private static class ProxyDataSourceInterceptor implements MethodInterceptor { + + private final DataSource dataSource; + + public ProxyDataSourceInterceptor(final DataSource dataSource) { + this.dataSource = ProxyDataSourceBuilder.create(dataSource).name("Batch-Insert-Logger").asJson().countQuery().logQueryToSysOut().build(); + } + + @Override + public Object invoke(final MethodInvocation invocation) throws Throwable { + Method proxyMethod = ReflectionUtils.findMethod(dataSource.getClass(), invocation.getMethod().getName()); + if (proxyMethod != null) { + return proxyMethod.invoke(dataSource, invocation.getArguments()); + } + return invocation.proceed(); + } + } +} \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/batchinserts/model/School.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/batchinserts/model/School.java new file mode 100644 index 0000000000..6d2f333ac7 --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/batchinserts/model/School.java @@ -0,0 +1,45 @@ +package com.baeldung.batchinserts.model; + +import java.util.List; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.OneToMany; + +@Entity +public class School { + + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE) + private long id; + + private String name; + + @OneToMany(mappedBy = "school") + private List students; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public List getStudents() { + return students; + } + + public void setStudents(List students) { + this.students = students; + } +} diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/batchinserts/model/Student.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/batchinserts/model/Student.java new file mode 100644 index 0000000000..d38214f122 --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/batchinserts/model/Student.java @@ -0,0 +1,44 @@ +package com.baeldung.batchinserts.model; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.ManyToOne; + +@Entity +public class Student { + + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE) + private long id; + + private String name; + + @ManyToOne + private School school; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public School getSchool() { + return school; + } + + public void setSchool(School school) { + this.school = school; + } +} diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/config/JpaPopulators.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/config/JpaPopulators.java new file mode 100644 index 0000000000..24348d31c5 --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/config/JpaPopulators.java @@ -0,0 +1,35 @@ +package com.baeldung.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; +import org.springframework.data.repository.init.Jackson2RepositoryPopulatorFactoryBean; +import org.springframework.data.repository.init.UnmarshallerRepositoryPopulatorFactoryBean; +import org.springframework.oxm.jaxb.Jaxb2Marshaller; + +import com.baeldung.entity.Fruit; + +@Configuration +public class JpaPopulators { + + @Bean + public Jackson2RepositoryPopulatorFactoryBean getRespositoryPopulator() throws Exception { + Jackson2RepositoryPopulatorFactoryBean factory = new Jackson2RepositoryPopulatorFactoryBean(); + factory.setResources(new Resource[] { new ClassPathResource("fruit-data.json") }); + return factory; + } + + @Bean + public UnmarshallerRepositoryPopulatorFactoryBean repositoryPopulator() { + + Jaxb2Marshaller unmarshaller = new Jaxb2Marshaller(); + unmarshaller.setClassesToBeBound(Fruit.class); + + UnmarshallerRepositoryPopulatorFactoryBean factory = new UnmarshallerRepositoryPopulatorFactoryBean(); + factory.setUnmarshaller(unmarshaller); + factory.setResources(new Resource[] { new ClassPathResource("apple-fruit-data.xml"), new ClassPathResource("guava-fruit-data.xml") }); + return factory; + } + +} diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/datajpadelete/entity/Book.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/datajpadelete/entity/Book.java new file mode 100644 index 0000000000..deac24548a --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/datajpadelete/entity/Book.java @@ -0,0 +1,51 @@ +package com.baeldung.datajpadelete.entity; + +import javax.persistence.*; + +@Entity +public class Book { + + @Id + @GeneratedValue + private Long id; + private String title; + + @ManyToOne + private Category category; + + public Book() { + } + + public Book(String title) { + this.title = title; + } + + public Book(String title, Category category) { + this.title = title; + this.category = category; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public Category getCategory() { + return category; + } + + public void setCategory(Category category) { + this.category = category; + } +} \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/datajpadelete/entity/Category.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/datajpadelete/entity/Category.java new file mode 100644 index 0000000000..16f1a4157f --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/datajpadelete/entity/Category.java @@ -0,0 +1,60 @@ +package com.baeldung.datajpadelete.entity; + +import javax.persistence.*; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +@Entity +public class Category { + + @Id + @GeneratedValue + private Long id; + private String name; + + @OneToMany(mappedBy = "category", cascade = CascadeType.ALL, orphanRemoval = true) + private List books; + + public Category() { + } + + public Category(String name) { + this.name = name; + } + + public Category(String name, Book... books) { + this.name = name; + this.books = Stream.of(books).collect(Collectors.toList()); + this.books.forEach(x -> x.setCategory(this)); + } + + public Category(String name, List books) { + this.name = name; + this.books = books; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public List getBooks() { + return books; + } + + public void setBooks(List books) { + this.books = books; + } +} diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/datajpadelete/repository/BookRepository.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/datajpadelete/repository/BookRepository.java new file mode 100644 index 0000000000..5d0f45f127 --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/datajpadelete/repository/BookRepository.java @@ -0,0 +1,19 @@ +package com.baeldung.datajpadelete.repository; + +import com.baeldung.datajpadelete.entity.Book; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +@Repository +public interface BookRepository extends CrudRepository { + + long deleteByTitle(String title); + + @Modifying + @Query("delete from Book b where b.title=:title") + void deleteBooks(@Param("title") String title); + +} \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/datajpadelete/repository/CategoryRepository.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/datajpadelete/repository/CategoryRepository.java new file mode 100644 index 0000000000..6fe7058a78 --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/datajpadelete/repository/CategoryRepository.java @@ -0,0 +1,9 @@ +package com.baeldung.datajpadelete.repository; + +import com.baeldung.datajpadelete.entity.Category; +import org.springframework.data.repository.CrudRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface CategoryRepository extends CrudRepository { +} diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/embeddable/model/Company.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/embeddable/model/Company.java new file mode 100644 index 0000000000..203cff1e35 --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/embeddable/model/Company.java @@ -0,0 +1,71 @@ +package com.baeldung.embeddable.model; + +import javax.persistence.AttributeOverride; +import javax.persistence.AttributeOverrides; +import javax.persistence.Column; +import javax.persistence.Embedded; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +@Entity +public class Company { + + @Id + @GeneratedValue + private Integer id; + + private String name; + + private String address; + + private String phone; + + @Embedded + @AttributeOverrides(value = { + @AttributeOverride( name = "firstName", column = @Column(name = "contact_first_name")), + @AttributeOverride( name = "lastName", column = @Column(name = "contact_last_name")), + @AttributeOverride( name = "phone", column = @Column(name = "contact_phone")) + }) + private ContactPerson contactPerson; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public ContactPerson getContactPerson() { + return contactPerson; + } + + public void setContactPerson(ContactPerson contactPerson) { + this.contactPerson = contactPerson; + } +} diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/embeddable/model/ContactPerson.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/embeddable/model/ContactPerson.java new file mode 100644 index 0000000000..561da80878 --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/embeddable/model/ContactPerson.java @@ -0,0 +1,38 @@ +package com.baeldung.embeddable.model; + +import javax.persistence.Embeddable; + +@Embeddable +public class ContactPerson { + + private String firstName; + + private String lastName; + + private String phone; + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + +} diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/embeddable/repositories/CompanyRepository.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/embeddable/repositories/CompanyRepository.java new file mode 100644 index 0000000000..f456b15652 --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/embeddable/repositories/CompanyRepository.java @@ -0,0 +1,18 @@ +package com.baeldung.embeddable.repositories; + +import com.baeldung.embeddable.model.Company; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; + +import java.util.List; + +public interface CompanyRepository extends JpaRepository { + + List findByContactPersonFirstName(String firstName); + + @Query("SELECT C FROM Company C WHERE C.contactPerson.firstName = ?1") + List findByContactPersonFirstNameWithJPQL(String firstName); + + @Query(value = "SELECT * FROM company WHERE contact_first_name = ?1", nativeQuery = true) + List findByContactPersonFirstNameWithNativeQuery(String firstName); +} diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/entity/Customer.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/entity/Customer.java new file mode 100644 index 0000000000..efcae73853 --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/entity/Customer.java @@ -0,0 +1,37 @@ +package com.baeldung.entity; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +@Entity +public class Customer { + + @Id + @GeneratedValue + private long id; + private String name; + private String email; + + public Customer(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; + } + +} diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/entity/Employee.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/entity/Employee.java new file mode 100644 index 0000000000..135439863f --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/entity/Employee.java @@ -0,0 +1,36 @@ +package com.baeldung.entity; + +import javax.persistence.Entity; +import javax.persistence.Id; + +@Entity +public class Employee { + + @Id + private Long id; + private String name; + + public Employee() { + } + + public Employee(Long id, String name) { + this.id = id; + this.name = name; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/entity/Fruit.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/entity/Fruit.java new file mode 100644 index 0000000000..d45ac33db8 --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/entity/Fruit.java @@ -0,0 +1,40 @@ +package com.baeldung.entity; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement +@Entity +public class Fruit { + + @Id + private long id; + private String name; + private String color; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getColor() { + return color; + } + + public void setColor(String color) { + this.color = color; + } + +} diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/entity/Passenger.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/entity/Passenger.java new file mode 100644 index 0000000000..3aafbe9afa --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/entity/Passenger.java @@ -0,0 +1,78 @@ +package com.baeldung.entity; + +import javax.persistence.Basic; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import java.util.Objects; + +@Entity +public class Passenger { + + @Id + @GeneratedValue + @Column(nullable = false) + private Long id; + + @Basic(optional = false) + @Column(nullable = false) + private String firstName; + + @Basic(optional = false) + @Column(nullable = false) + private String lastName; + + private Passenger(String firstName, String lastName) { + this.firstName = firstName; + this.lastName = lastName; + } + + public static Passenger from(String firstName, String lastName) { + return new Passenger(firstName, lastName); + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + @Override + public String toString() { + return "Passenger{" + "id=" + id + ", firstName='" + firstName + '\'' + ", lastName='" + lastName + '\'' + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + Passenger passenger = (Passenger) o; + return Objects.equals(firstName, passenger.firstName) && Objects.equals(lastName, passenger.lastName); + } + + @Override + public int hashCode() { + return Objects.hash(firstName, lastName); + } +} diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/entity/Song.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/entity/Song.java new file mode 100644 index 0000000000..395527c1eb --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/entity/Song.java @@ -0,0 +1,75 @@ +package com.baeldung.entity; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import java.time.LocalDateTime; + +@Entity +public class Song { + + @Id private long id; + private String name; + @Column(name = "length_in_seconds") + private int lengthInSeconds; + private String compositor; + private String singer; + private LocalDateTime released; + private String genre; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getLengthInSeconds() { + return lengthInSeconds; + } + + public void setLengthInSeconds(int lengthInSeconds) { + this.lengthInSeconds = lengthInSeconds; + } + + public String getCompositor() { + return compositor; + } + + public void setCompositor(String compositor) { + this.compositor = compositor; + } + + public String getSinger() { + return singer; + } + + public void setSinger(String singer) { + this.singer = singer; + } + + public LocalDateTime getReleased() { + return released; + } + + public void setReleased(LocalDateTime released) { + this.released = released; + } + + public String getGenre() { + return genre; + } + + public void setGenre(String genre) { + this.genre = genre; + } +} diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/entitygraph/model/Characteristic.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/entitygraph/model/Characteristic.java new file mode 100644 index 0000000000..ae20375572 --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/entitygraph/model/Characteristic.java @@ -0,0 +1,43 @@ +package com.baeldung.entitygraph.model; + +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; + +@Entity +public class Characteristic { + + @Id + private Long id; + private String type; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn + private Item item; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public Item getItem() { + return item; + } + + public void setItem(Item item) { + this.item = item; + } +} diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/entitygraph/model/Item.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/entitygraph/model/Item.java new file mode 100644 index 0000000000..e90a22ef62 --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/entitygraph/model/Item.java @@ -0,0 +1,48 @@ +package com.baeldung.entitygraph.model; + +import java.util.ArrayList; +import java.util.List; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.NamedAttributeNode; +import javax.persistence.NamedEntityGraph; +import javax.persistence.OneToMany; + +@Entity +@NamedEntityGraph(name = "Item.characteristics", + attributeNodes = @NamedAttributeNode("characteristics") +) +public class Item { + + @Id + private Long id; + private String name; + + @OneToMany(mappedBy = "item") + private List characteristics = new ArrayList<>(); + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public List getCharacteristics() { + return characteristics; + } + + public void setCharacteristics(List characteristics) { + this.characteristics = characteristics; + } +} diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/entitygraph/repository/CharacteristicsRepository.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/entitygraph/repository/CharacteristicsRepository.java new file mode 100644 index 0000000000..9f923ab241 --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/entitygraph/repository/CharacteristicsRepository.java @@ -0,0 +1,13 @@ +package com.baeldung.entitygraph.repository; + +import org.springframework.data.jpa.repository.EntityGraph; +import org.springframework.data.jpa.repository.JpaRepository; + +import com.baeldung.entitygraph.model.Characteristic; + +public interface CharacteristicsRepository extends JpaRepository { + + @EntityGraph(attributePaths = {"item"}) + Characteristic findByType(String type); + +} diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/entitygraph/repository/ItemRepository.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/entitygraph/repository/ItemRepository.java new file mode 100644 index 0000000000..b2a5f223b3 --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/entitygraph/repository/ItemRepository.java @@ -0,0 +1,13 @@ +package com.baeldung.entitygraph.repository; + +import org.springframework.data.jpa.repository.EntityGraph; +import org.springframework.data.jpa.repository.EntityGraph.EntityGraphType; +import org.springframework.data.jpa.repository.JpaRepository; + +import com.baeldung.entitygraph.model.Item; + +public interface ItemRepository extends JpaRepository { + + @EntityGraph(value = "Item.characteristics", type = EntityGraphType.FETCH) + Item findByName(String name); +} diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/exists/Car.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/exists/Car.java new file mode 100644 index 0000000000..bf09caf6ff --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/exists/Car.java @@ -0,0 +1,48 @@ +package com.baeldung.exists; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +/** + * @author paullatzelsperger + * @since 2019-03-20 + */ +@Entity +public class Car { + + @Id + @GeneratedValue + private int id; + private Integer power; + private String model; + + Car() { + + } + + public Car(int power, String model) { + this.power = power; + this.model = model; + } + + public Integer getPower() { + return power; + } + + public void setPower(Integer power) { + this.power = power; + } + + public String getModel() { + return model; + } + + public void setModel(String model) { + this.model = model; + } + + public int getId() { + return id; + } +} diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/exists/CarRepository.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/exists/CarRepository.java new file mode 100644 index 0000000000..a54f19f4cd --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/exists/CarRepository.java @@ -0,0 +1,24 @@ +package com.baeldung.exists; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +/** + * @author paullatzelsperger + * @since 2019-03-20 + */ +@Repository +public interface CarRepository extends JpaRepository { + + boolean existsCarByPower(int power); + + boolean existsCarByModel(String model); + + @Query("select case when count(c)> 0 then true else false end from Car c where c.model = :model") + boolean existsCarExactCustomQuery(@Param("model") String model); + + @Query("select case when count(c)> 0 then true else false end from Car c where lower(c.model) like lower(:model)") + boolean existsCarLikeCustomQuery(@Param("model") String model); +} diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/joins/model/Department.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/joins/model/Department.java new file mode 100644 index 0000000000..439f7532f5 --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/joins/model/Department.java @@ -0,0 +1,45 @@ +package com.baeldung.joins.model; + +import java.util.List; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.OneToMany; + +@Entity +public class Department { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private long id; + + private String name; + + @OneToMany(mappedBy = "department") + private List employees; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public List getEmployees() { + return employees; + } + + public void setEmployees(List employees) { + this.employees = employees; + } +} diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/joins/model/Employee.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/joins/model/Employee.java new file mode 100644 index 0000000000..277274e61c --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/joins/model/Employee.java @@ -0,0 +1,69 @@ +package com.baeldung.joins.model; + +import java.util.List; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; +import javax.persistence.Table; + +@Entity +@Table(name = "joins_employee") +public class Employee { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + + private String name; + + private int age; + + @ManyToOne + private Department department; + + @OneToMany(mappedBy = "employee") + private List phones; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public Department getDepartment() { + return department; + } + + public void setDepartment(Department department) { + this.department = department; + } + + public List getPhones() { + return phones; + } + + public void setPhones(List phones) { + this.phones = phones; + } +} diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/joins/model/Phone.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/joins/model/Phone.java new file mode 100644 index 0000000000..41382915b1 --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/joins/model/Phone.java @@ -0,0 +1,44 @@ +package com.baeldung.joins.model; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.ManyToOne; + +@Entity +public class Phone { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + + private String number; + + @ManyToOne + private Employee employee; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getNumber() { + return number; + } + + public void setNumber(String number) { + this.number = number; + } + + public Employee getEmployee() { + return employee; + } + + public void setEmployee(Employee employee) { + this.employee = employee; + } +} diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/projection/model/Address.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/projection/model/Address.java new file mode 100644 index 0000000000..0c5a3eac60 --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/projection/model/Address.java @@ -0,0 +1,57 @@ +package com.baeldung.projection.model; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.OneToOne; + +@Entity +public class Address { + @Id + private Long id; + @OneToOne + private Person person; + private String state; + private String city; + private String street; + private String zipCode; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getState() { + return state; + } + + public void setState(String state) { + this.state = state; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public String getStreet() { + return street; + } + + public void setStreet(String street) { + this.street = street; + } + + public String getZipCode() { + return zipCode; + } + + public void setZipCode(String zipCode) { + this.zipCode = zipCode; + } +} diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/projection/model/Person.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/projection/model/Person.java new file mode 100644 index 0000000000..d18bd1c72d --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/projection/model/Person.java @@ -0,0 +1,47 @@ +package com.baeldung.projection.model; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.OneToOne; + +@Entity +public class Person { + @Id + private Long id; + private String firstName; + private String lastName; + @OneToOne(mappedBy = "person") + private Address address; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public Address getAddress() { + return address; + } + + public void setAddress(Address address) { + this.address = address; + } +} diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/projection/repository/AddressRepository.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/projection/repository/AddressRepository.java new file mode 100644 index 0000000000..c1053f4867 --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/projection/repository/AddressRepository.java @@ -0,0 +1,11 @@ +package com.baeldung.projection.repository; + +import com.baeldung.projection.view.AddressView; +import com.baeldung.projection.model.Address; +import org.springframework.data.repository.Repository; + +import java.util.List; + +public interface AddressRepository extends Repository { + List getAddressByState(String state); +} diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/projection/repository/PersonRepository.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/projection/repository/PersonRepository.java new file mode 100644 index 0000000000..64bc7471e6 --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/projection/repository/PersonRepository.java @@ -0,0 +1,14 @@ +package com.baeldung.projection.repository; + +import com.baeldung.projection.model.Person; +import com.baeldung.projection.view.PersonDto; +import com.baeldung.projection.view.PersonView; +import org.springframework.data.repository.Repository; + +public interface PersonRepository extends Repository { + PersonView findByLastName(String lastName); + + PersonDto findByFirstName(String firstName); + + T findByLastName(String lastName, Class type); +} diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/projection/view/AddressView.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/projection/view/AddressView.java new file mode 100644 index 0000000000..7a24a1e9b9 --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/projection/view/AddressView.java @@ -0,0 +1,7 @@ +package com.baeldung.projection.view; + +public interface AddressView { + String getZipCode(); + + PersonView getPerson(); +} diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/projection/view/PersonDto.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/projection/view/PersonDto.java new file mode 100644 index 0000000000..1fd924450b --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/projection/view/PersonDto.java @@ -0,0 +1,34 @@ +package com.baeldung.projection.view; + +import java.util.Objects; + +public class PersonDto { + private final String firstName; + private final String lastName; + + public PersonDto(String firstName, String lastName) { + this.firstName = firstName; + this.lastName = lastName; + } + + public String getFirstName() { + return firstName; + } + + public String getLastName() { + return lastName; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + PersonDto personDto = (PersonDto) o; + return Objects.equals(firstName, personDto.firstName) && Objects.equals(lastName, personDto.lastName); + } + + @Override + public int hashCode() { + return Objects.hash(firstName, lastName); + } +} diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/projection/view/PersonView.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/projection/view/PersonView.java new file mode 100644 index 0000000000..36777ec26f --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/projection/view/PersonView.java @@ -0,0 +1,12 @@ +package com.baeldung.projection.view; + +import org.springframework.beans.factory.annotation.Value; + +public interface PersonView { + String getFirstName(); + + String getLastName(); + + @Value("#{target.firstName + ' ' + target.lastName}") + String getFullName(); +} diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/repository/CustomerRepository.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/repository/CustomerRepository.java new file mode 100644 index 0000000000..65b22bbd84 --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/repository/CustomerRepository.java @@ -0,0 +1,19 @@ +package com.baeldung.repository; + +import com.baeldung.entity.Customer; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +import java.util.List; + +public interface CustomerRepository extends JpaRepository { + + List findByName(String name); + + List findByNameAndEmail(String name, String email); + + @Query("SELECT c FROM Customer c WHERE (:name is null or c.name = :name) and (:email is null or c.email = :email)") + List findCustomerByNameAndEmail(@Param("name") String name, @Param("email") String email); + +} diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/repository/EmployeeRepository.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/repository/EmployeeRepository.java new file mode 100644 index 0000000000..2c4fee80e0 --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/repository/EmployeeRepository.java @@ -0,0 +1,9 @@ +package com.baeldung.repository; + +import org.springframework.data.jpa.repository.JpaRepository; + +import com.baeldung.entity.Employee; + +public interface EmployeeRepository extends JpaRepository { + +} diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/repository/FruitRepository.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/repository/FruitRepository.java new file mode 100644 index 0000000000..9f92909b66 --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/repository/FruitRepository.java @@ -0,0 +1,27 @@ +package com.baeldung.repository; + +import java.util.List; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +import com.baeldung.entity.Fruit; + +@Repository +public interface FruitRepository extends JpaRepository { + + Long deleteByName(String name); + + List deleteByColor(String color); + + Long removeByName(String name); + + List removeByColor(String color); + + @Modifying + @Query("delete from Fruit f where f.name=:name or f.color=:color") + List deleteFruits(@Param("name") String name, @Param("color") String color); +} diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/repository/PassengerRepository.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/repository/PassengerRepository.java new file mode 100644 index 0000000000..a295a74f1b --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/repository/PassengerRepository.java @@ -0,0 +1,14 @@ +package com.baeldung.repository; + +import com.baeldung.entity.Passenger; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +interface PassengerRepository extends JpaRepository { + + List findByFirstNameIgnoreCase(String firstName); + +} diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/repository/SongRepository.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/repository/SongRepository.java new file mode 100644 index 0000000000..ad887fe680 --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/repository/SongRepository.java @@ -0,0 +1,21 @@ +package com.baeldung.repository; + +import com.baeldung.entity.Song; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface SongRepository extends JpaRepository { + + List findByNameLike(String name); + + List findByNameNotLike(String name); + + List findByNameStartingWith(String startingWith); + + List findByNameEndingWith(String endingWith); + + List findBySingerContaining(String singer); +} diff --git a/persistence-modules/spring-data-jpa-2/src/main/resources/apple-fruit-data.xml b/persistence-modules/spring-data-jpa-2/src/main/resources/apple-fruit-data.xml new file mode 100644 index 0000000000..d87ae28f1e --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/main/resources/apple-fruit-data.xml @@ -0,0 +1,7 @@ + + + + 1 + apple + red + diff --git a/persistence-modules/spring-data-jpa-2/src/main/resources/application-batchinserts.properties b/persistence-modules/spring-data-jpa-2/src/main/resources/application-batchinserts.properties new file mode 100644 index 0000000000..4141f5668e --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/main/resources/application-batchinserts.properties @@ -0,0 +1,6 @@ +spring.jpa.show-sql=false + +spring.jpa.properties.hibernate.jdbc.batch_size=5 +spring.jpa.properties.hibernate.order_inserts=true +spring.jpa.properties.hibernate.order_updates=true +spring.jpa.properties.hibernate.batch_versioned_data=true \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa-2/src/main/resources/application-joins.properties b/persistence-modules/spring-data-jpa-2/src/main/resources/application-joins.properties new file mode 100644 index 0000000000..fe2270293b --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/main/resources/application-joins.properties @@ -0,0 +1 @@ +spring.datasource.data=classpath:db/import_joins.sql diff --git a/persistence-modules/spring-data-jpa-2/src/main/resources/application.properties b/persistence-modules/spring-data-jpa-2/src/main/resources/application.properties new file mode 100644 index 0000000000..72fc330767 --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/main/resources/application.properties @@ -0,0 +1 @@ +spring.jpa.show-sql=true \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa-2/src/main/resources/db/import_joins.sql b/persistence-modules/spring-data-jpa-2/src/main/resources/db/import_joins.sql new file mode 100644 index 0000000000..e4772d6ff2 --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/main/resources/db/import_joins.sql @@ -0,0 +1,13 @@ +INSERT INTO department (id, name) VALUES (1, 'Infra'); +INSERT INTO department (id, name) VALUES (2, 'Accounting'); +INSERT INTO department (id, name) VALUES (3, 'Management'); + +INSERT INTO joins_employee (id, name, age, department_id) VALUES (1, 'Baeldung', '35', 1); +INSERT INTO joins_employee (id, name, age, department_id) VALUES (2, 'John', '35', 2); +INSERT INTO joins_employee (id, name, age, department_id) VALUES (3, 'Jane', '35', 2); + +INSERT INTO phone (id, number, employee_id) VALUES (1, '111', 1); +INSERT INTO phone (id, number, employee_id) VALUES (2, '222', 1); +INSERT INTO phone (id, number, employee_id) VALUES (3, '333', 1); + +COMMIT; diff --git a/persistence-modules/spring-data-jpa-2/src/main/resources/fruit-data.json b/persistence-modules/spring-data-jpa-2/src/main/resources/fruit-data.json new file mode 100644 index 0000000000..6dc44e2586 --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/main/resources/fruit-data.json @@ -0,0 +1,14 @@ +[ + { + "_class": "com.baeldung.entity.Fruit", + "name": "apple", + "color": "red", + "id": 1 + }, + { + "_class": "com.baeldung.entity.Fruit", + "name": "guava", + "color": "green", + "id": 2 + } +] \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa-2/src/main/resources/guava-fruit-data.xml b/persistence-modules/spring-data-jpa-2/src/main/resources/guava-fruit-data.xml new file mode 100644 index 0000000000..ffd75bb4bb --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/main/resources/guava-fruit-data.xml @@ -0,0 +1,7 @@ + + + + 2 + guava + green + diff --git a/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/batchinserts/JpaBatchInsertsIntegrationTest.java b/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/batchinserts/JpaBatchInsertsIntegrationTest.java new file mode 100644 index 0000000000..9e81dbc04d --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/batchinserts/JpaBatchInsertsIntegrationTest.java @@ -0,0 +1,94 @@ +package com.baeldung.batchinserts; + +import static com.baeldung.batchinserts.TestObjectHelper.createSchool; +import static com.baeldung.batchinserts.TestObjectHelper.createStudent; + +import com.baeldung.batchinserts.model.School; +import com.baeldung.batchinserts.model.Student; +import java.util.List; +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import javax.persistence.TypedQuery; +import org.junit.After; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.transaction.annotation.Transactional; + +@RunWith(SpringRunner.class) +@SpringBootTest +@Transactional +@ActiveProfiles("batchinserts") +public class JpaBatchInsertsIntegrationTest { + + @PersistenceContext + private EntityManager entityManager; + + private static final int BATCH_SIZE = 5; + + @Transactional + @Test + public void whenInsertingSingleTypeOfEntity_thenCreatesSingleBatch() { + for (int i = 0; i < 10; i++) { + School school = createSchool(i); + entityManager.persist(school); + } + } + + @Transactional + @Test + public void whenFlushingAfterBatch_ThenClearsMemory() { + for (int i = 0; i < 10; i++) { + if (i > 0 && i % BATCH_SIZE == 0) { + entityManager.flush(); + entityManager.clear(); + } + + School school = createSchool(i); + entityManager.persist(school); + } + } + + @Transactional + @Test + public void whenThereAreMultipleEntities_ThenCreatesNewBatch() { + for (int i = 0; i < 10; i++) { + if (i > 0 && i % BATCH_SIZE == 0) { + entityManager.flush(); + entityManager.clear(); + } + + School school = createSchool(i); + entityManager.persist(school); + Student firstStudent = createStudent(school); + Student secondStudent = createStudent(school); + entityManager.persist(firstStudent); + entityManager.persist(secondStudent); + } + } + + @Transactional + @Test + public void whenUpdatingEntities_thenCreatesBatch() { + for (int i = 0; i < 10; i++) { + School school = createSchool(i); + entityManager.persist(school); + } + + entityManager.flush(); + + TypedQuery schoolQuery = entityManager.createQuery("SELECT s from School s", School.class); + List allSchools = schoolQuery.getResultList(); + + for (School school : allSchools) { + school.setName("Updated_" + school.getName()); + } + } + + @After + public void tearDown() { + entityManager.flush(); + } +} diff --git a/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/batchinserts/JpaNoBatchInsertsIntegrationTest.java b/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/batchinserts/JpaNoBatchInsertsIntegrationTest.java new file mode 100644 index 0000000000..20502c793d --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/batchinserts/JpaNoBatchInsertsIntegrationTest.java @@ -0,0 +1,39 @@ +package com.baeldung.batchinserts; + +import static com.baeldung.batchinserts.TestObjectHelper.createSchool; + +import com.baeldung.batchinserts.model.School; +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import org.junit.After; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.transaction.annotation.Transactional; + +@RunWith(SpringRunner.class) +@SpringBootTest +@Transactional +@ActiveProfiles("batchinserts") +@TestPropertySource(properties = "spring.jpa.properties.hibernate.jdbc.batch_size=-1") +public class JpaNoBatchInsertsIntegrationTest { + + @PersistenceContext + private EntityManager entityManager; + + @Test + public void whenNotConfigured_ThenSendsInsertsSeparately() { + for (int i = 0; i < 10; i++) { + School school = createSchool(i); + entityManager.persist(school); + } + } + + @After + public void tearDown() { + entityManager.flush(); + } +} diff --git a/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/batchinserts/TestObjectHelper.java b/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/batchinserts/TestObjectHelper.java new file mode 100644 index 0000000000..fcd26cb721 --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/batchinserts/TestObjectHelper.java @@ -0,0 +1,20 @@ +package com.baeldung.batchinserts; + +import com.baeldung.batchinserts.model.School; +import com.baeldung.batchinserts.model.Student; + +public class TestObjectHelper { + + public static School createSchool(int nameIdentifier) { + School school = new School(); + school.setName("School" + (nameIdentifier + 1)); + return school; + } + + public static Student createStudent(School school) { + Student student = new Student(); + student.setName("Student-" + school.getName()); + student.setSchool(school); + return student; + } +} diff --git a/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/datajpadelete/DeleteFromRepositoryUnitTest.java b/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/datajpadelete/DeleteFromRepositoryUnitTest.java new file mode 100644 index 0000000000..9e7e516735 --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/datajpadelete/DeleteFromRepositoryUnitTest.java @@ -0,0 +1,72 @@ +package com.baeldung.datajpadelete; + +import com.baeldung.Application; +import com.baeldung.datajpadelete.entity.Book; +import com.baeldung.datajpadelete.repository.BookRepository; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Arrays; + +import static org.assertj.core.api.Assertions.assertThat; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = {Application.class}) +public class DeleteFromRepositoryUnitTest { + + @Autowired + private BookRepository repository; + + Book book1; + Book book2; + + @Before + public void setup() { + book1 = new Book("The Hobbit"); + book2 = new Book("All Quiet on the Western Front"); + + repository.saveAll(Arrays.asList(book1, book2)); + } + + @After + public void teardown() { + repository.deleteAll(); + } + + @Test + public void whenDeleteByIdFromRepository_thenDeletingShouldBeSuccessful() { + repository.deleteById(book1.getId()); + + assertThat(repository.count() == 1).isTrue(); + } + + @Test + public void whenDeleteAllFromRepository_thenRepositoryShouldBeEmpty() { + repository.deleteAll(); + + assertThat(repository.count() == 0).isTrue(); + } + + @Test + @Transactional + public void whenDeleteFromDerivedQuery_thenDeletingShouldBeSuccessful() { + repository.deleteByTitle("The Hobbit"); + + assertThat(repository.count() == 1).isTrue(); + } + + @Test + @Transactional + public void whenDeleteFromCustomQuery_thenDeletingShouldBeSuccessful() { + repository.deleteBooks("The Hobbit"); + + assertThat(repository.count() == 1).isTrue(); + } + +} \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/datajpadelete/DeleteInRelationshipsUnitTest.java b/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/datajpadelete/DeleteInRelationshipsUnitTest.java new file mode 100644 index 0000000000..56de8749b2 --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/datajpadelete/DeleteInRelationshipsUnitTest.java @@ -0,0 +1,60 @@ +package com.baeldung.datajpadelete; + +import com.baeldung.Application; +import com.baeldung.datajpadelete.entity.Book; +import com.baeldung.datajpadelete.entity.Category; +import com.baeldung.datajpadelete.repository.BookRepository; +import com.baeldung.datajpadelete.repository.CategoryRepository; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = {Application.class}) +public class DeleteInRelationshipsUnitTest { + + @Autowired + private BookRepository bookRepository; + + @Autowired + private CategoryRepository categoryRepository; + + @Before + public void setup() { + Book book1 = new Book("The Hobbit"); + Category category1 = new Category("Cat1", book1); + categoryRepository.save(category1); + + Book book2 = new Book("All Quiet on the Western Front"); + Category category2 = new Category("Cat2", book2); + categoryRepository.save(category2); + } + + @After + public void teardown() { + bookRepository.deleteAll(); + categoryRepository.deleteAll(); + } + + @Test + public void whenDeletingCategories_thenBooksShouldAlsoBeDeleted() { + categoryRepository.deleteAll(); + + assertThat(bookRepository.count() == 0).isTrue(); + assertThat(categoryRepository.count() == 0).isTrue(); + } + + @Test + public void whenDeletingBooks_thenCategoriesShouldAlsoBeDeleted() { + bookRepository.deleteAll(); + + assertThat(bookRepository.count() == 0).isTrue(); + assertThat(categoryRepository.count() == 2).isTrue(); + } +} \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/embeddable/EmbeddableIntegrationTest.java b/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/embeddable/EmbeddableIntegrationTest.java new file mode 100644 index 0000000000..b4c365a2d9 --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/embeddable/EmbeddableIntegrationTest.java @@ -0,0 +1,125 @@ +package com.baeldung.embeddable; + +import com.baeldung.Application; +import com.baeldung.embeddable.model.Company; +import com.baeldung.embeddable.model.ContactPerson; +import com.baeldung.embeddable.repositories.CompanyRepository; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +import static org.junit.Assert.assertEquals; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = {Application.class}) +public class EmbeddableIntegrationTest { + + @Autowired + private CompanyRepository companyRepository; + + @Test + @Transactional + public void whenInsertingCompany_thenEmbeddedContactPersonDetailsAreMapped() { + ContactPerson contactPerson = new ContactPerson(); + contactPerson.setFirstName("First"); + contactPerson.setLastName("Last"); + contactPerson.setPhone("123-456-789"); + + Company company = new Company(); + company.setName("Company"); + company.setAddress("1st street"); + company.setPhone("987-654-321"); + company.setContactPerson(contactPerson); + + companyRepository.save(company); + + Company result = companyRepository.getOne(company.getId()); + + assertEquals("Company", result.getName()); + assertEquals("1st street", result.getAddress()); + assertEquals("987-654-321", result.getPhone()); + assertEquals("First", result.getContactPerson().getFirstName()); + assertEquals("Last", result.getContactPerson().getLastName()); + assertEquals("123-456-789", result.getContactPerson().getPhone()); + } + + @Test + @Transactional + public void whenFindingCompanyByContactPersonAttribute_thenCompanyIsReturnedProperly() { + ContactPerson contactPerson = new ContactPerson(); + contactPerson.setFirstName("Name"); + contactPerson.setLastName("Last"); + contactPerson.setPhone("123-456-789"); + + Company company = new Company(); + company.setName("Company"); + company.setAddress("1st street"); + company.setPhone("987-654-321"); + company.setContactPerson(contactPerson); + + companyRepository.save(company); + + List result = companyRepository.findByContactPersonFirstName("Name"); + + assertEquals(1, result.size()); + + result = companyRepository.findByContactPersonFirstName("FirstName"); + + assertEquals(0, result.size()); + } + + @Test + @Transactional + public void whenFindingCompanyByContactPersonAttributeWithJPQL_thenCompanyIsReturnedProperly() { + ContactPerson contactPerson = new ContactPerson(); + contactPerson.setFirstName("@QueryName"); + contactPerson.setLastName("Last"); + contactPerson.setPhone("123-456-789"); + + Company company = new Company(); + company.setName("Company"); + company.setAddress("1st street"); + company.setPhone("987-654-321"); + company.setContactPerson(contactPerson); + + companyRepository.save(company); + + List result = companyRepository.findByContactPersonFirstNameWithJPQL("@QueryName"); + + assertEquals(1, result.size()); + + result = companyRepository.findByContactPersonFirstNameWithJPQL("FirstName"); + + assertEquals(0, result.size()); + } + + @Test + @Transactional + public void whenFindingCompanyByContactPersonAttributeWithNativeQuery_thenCompanyIsReturnedProperly() { + ContactPerson contactPerson = new ContactPerson(); + contactPerson.setFirstName("NativeQueryName"); + contactPerson.setLastName("Last"); + contactPerson.setPhone("123-456-789"); + + Company company = new Company(); + company.setName("Company"); + company.setAddress("1st street"); + company.setPhone("987-654-321"); + company.setContactPerson(contactPerson); + + companyRepository.save(company); + + List result = companyRepository.findByContactPersonFirstNameWithNativeQuery("NativeQueryName"); + + assertEquals(1, result.size()); + + result = companyRepository.findByContactPersonFirstNameWithNativeQuery("FirstName"); + + assertEquals(0, result.size()); + } +} diff --git a/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/entitygraph/EntityGraphIntegrationTest.java b/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/entitygraph/EntityGraphIntegrationTest.java new file mode 100644 index 0000000000..24880a5dff --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/entitygraph/EntityGraphIntegrationTest.java @@ -0,0 +1,39 @@ +package com.baeldung.entitygraph; + +import static org.assertj.core.api.Assertions.assertThat; + +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.test.context.jdbc.Sql; +import org.springframework.test.context.junit4.SpringRunner; + +import com.baeldung.entitygraph.model.Characteristic; +import com.baeldung.entitygraph.model.Item; +import com.baeldung.entitygraph.repository.CharacteristicsRepository; +import com.baeldung.entitygraph.repository.ItemRepository; + +@DataJpaTest +@RunWith(SpringRunner.class) +@Sql(scripts = "/entitygraph-data.sql") +public class EntityGraphIntegrationTest { + + @Autowired + private ItemRepository itemRepo; + + @Autowired + private CharacteristicsRepository characteristicsRepo; + + @Test + public void givenEntityGraph_whenCalled_shouldRetrunDefinedFields() { + Item item = itemRepo.findByName("Table"); + assertThat(item.getId()).isEqualTo(1L); + } + + @Test + public void givenAdhocEntityGraph_whenCalled_shouldRetrunDefinedFields() { + Characteristic characteristic = characteristicsRepo.findByType("Rigid"); + assertThat(characteristic.getId()).isEqualTo(1L); + } +} diff --git a/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/exists/CarRepositoryIntegrationTest.java b/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/exists/CarRepositoryIntegrationTest.java new file mode 100644 index 0000000000..d99f6671a3 --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/exists/CarRepositoryIntegrationTest.java @@ -0,0 +1,87 @@ +package com.baeldung.exists; + +import com.baeldung.Application; +import org.junit.After; +import org.junit.Before; +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.data.domain.Example; +import org.springframework.data.domain.ExampleMatcher; +import org.springframework.test.context.junit4.SpringRunner; + +import java.util.Arrays; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.data.domain.ExampleMatcher.GenericPropertyMatchers.ignoreCase; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = {Application.class}) +public class CarRepositoryIntegrationTest { + + @Autowired + private CarRepository repository; + private int searchId; + + @Before + public void setup() { + List cars = repository.saveAll(Arrays.asList(new Car(200, "BMW"), new Car(300, "Audi"))); + searchId = cars.get(0).getId(); + } + + @After + public void teardown() { + repository.deleteAll(); + } + + @Test + public void whenIdIsCorrect_thenExistsShouldReturnTrue() { + assertThat(repository.existsById(searchId)).isTrue(); + } + + @Test + public void givenExample_whenExists_thenIsTrue() { + ExampleMatcher modelMatcher = ExampleMatcher.matching() + .withIgnorePaths("id") // must explicitly ignore -> PK + .withMatcher("model", ignoreCase()); + Car probe = new Car(); + probe.setModel("bmw"); + + Example example = Example.of(probe, modelMatcher); + + assertThat(repository.exists(example)).isTrue(); + } + + @Test + public void givenPower_whenExists_thenIsFalse() { + assertThat(repository.existsCarByPower(200)).isTrue(); + assertThat(repository.existsCarByPower(800)).isFalse(); + } + + @Test + public void existsByDerivedQuery_byModel() { + assertThat(repository.existsCarByModel("Audi")).isTrue(); + assertThat(repository.existsCarByModel("audi")).isFalse(); + assertThat(repository.existsCarByModel("AUDI")).isFalse(); + assertThat(repository.existsCarByModel("")).isFalse(); + } + + @Test + public void givenModelName_whenExistsExact_thenIsTrue() { + assertThat(repository.existsCarExactCustomQuery("BMW")).isTrue(); + assertThat(repository.existsCarExactCustomQuery("Bmw")).isFalse(); + assertThat(repository.existsCarExactCustomQuery("bmw")).isFalse(); + assertThat(repository.existsCarExactCustomQuery("")).isFalse(); + } + + @Test + public void givenModelName_whenExistsLike_thenIsTrue() { + assertThat(repository.existsCarLikeCustomQuery("BMW")).isTrue(); + assertThat(repository.existsCarLikeCustomQuery("Bmw")).isTrue(); + assertThat(repository.existsCarLikeCustomQuery("bmw")).isTrue(); + assertThat(repository.existsCarLikeCustomQuery("")).isFalse(); + } + +} diff --git a/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/joins/JpaJoinsIntegrationTest.java b/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/joins/JpaJoinsIntegrationTest.java new file mode 100644 index 0000000000..9b0d23f3e4 --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/joins/JpaJoinsIntegrationTest.java @@ -0,0 +1,142 @@ +package com.baeldung.joins; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.baeldung.joins.model.Department; +import com.baeldung.joins.model.Phone; +import java.util.Collection; +import java.util.List; +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import javax.persistence.TypedQuery; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@DataJpaTest +@ActiveProfiles("joins") +public class JpaJoinsIntegrationTest { + + @PersistenceContext + private EntityManager entityManager; + + @Test + public void whenPathExpressionIsUsedForSingleValuedAssociation_thenCreatesImplicitInnerJoin() { + TypedQuery query = entityManager.createQuery("SELECT e.department FROM Employee e", Department.class); + + List resultList = query.getResultList(); + + assertThat(resultList).hasSize(3); + assertThat(resultList).extracting("name") + .containsOnly("Infra", "Accounting", "Accounting"); + } + + @Test + public void whenJoinKeywordIsUsed_thenCreatesExplicitInnerJoin() { + TypedQuery query = entityManager.createQuery("SELECT d FROM Employee e JOIN e.department d", Department.class); + + List resultList = query.getResultList(); + + assertThat(resultList).hasSize(3); + assertThat(resultList).extracting("name") + .containsOnly("Infra", "Accounting", "Accounting"); + } + + @Test + public void whenInnerJoinKeywordIsUsed_thenCreatesExplicitInnerJoin() { + TypedQuery query = entityManager.createQuery("SELECT d FROM Employee e INNER JOIN e.department d", Department.class); + + List resultList = query.getResultList(); + + assertThat(resultList).hasSize(3); + assertThat(resultList).extracting("name") + .containsOnly("Infra", "Accounting", "Accounting"); + } + + @Test + public void whenEntitiesAreListedInFromAndMatchedInWhere_ThenCreatesJoin() { + TypedQuery query = entityManager.createQuery("SELECT d FROM Employee e, Department d WHERE e.department = d", Department.class); + + List resultList = query.getResultList(); + + assertThat(resultList).hasSize(3); + assertThat(resultList).extracting("name") + .containsOnly("Infra", "Accounting", "Accounting"); + } + + @Test + public void whenEntitiesAreListedInFrom_ThenCreatesCartesianProduct() { + TypedQuery query = entityManager.createQuery("SELECT d FROM Employee e, Department d", Department.class); + + List resultList = query.getResultList(); + + assertThat(resultList).hasSize(9); + assertThat(resultList).extracting("name") + .containsOnly("Infra", "Accounting", "Management", "Infra", "Accounting", "Management", "Infra", "Accounting", "Management"); + } + + @Test + public void whenCollectionValuedAssociationIsJoined_ThenCanSelect() { + TypedQuery query = entityManager.createQuery("SELECT ph FROM Employee e JOIN e.phones ph WHERE ph LIKE '1%'", Phone.class); + + List resultList = query.getResultList(); + + assertThat(resultList).hasSize(1); + } + + @Test + public void whenMultipleEntitiesAreListedWithJoin_ThenCreatesMultipleJoins() { + TypedQuery query = entityManager.createQuery("SELECT ph FROM Employee e JOIN e.department d JOIN e.phones ph WHERE d.name IS NOT NULL", Phone.class); + + List resultList = query.getResultList(); + + assertThat(resultList).hasSize(3); + assertThat(resultList).extracting("number") + .containsOnly("111", "222", "333"); + } + + @Test + public void whenLeftKeywordIsSpecified_thenCreatesOuterJoinAndIncludesNonMatched() { + TypedQuery query = entityManager.createQuery("SELECT DISTINCT d FROM Department d LEFT JOIN d.employees e", Department.class); + + List resultList = query.getResultList(); + + assertThat(resultList).hasSize(3); + assertThat(resultList).extracting("name") + .containsOnly("Infra", "Accounting", "Management"); + } + + @Test + public void whenFetchKeywordIsSpecified_ThenCreatesFetchJoin() { + TypedQuery query = entityManager.createQuery("SELECT d FROM Department d JOIN FETCH d.employees", Department.class); + + List resultList = query.getResultList(); + + assertThat(resultList).hasSize(3); + assertThat(resultList).extracting("name") + .containsOnly("Infra", "Accounting", "Accounting"); + } + + @Test + public void whenLeftAndFetchKeywordsAreSpecified_ThenCreatesOuterFetchJoin() { + TypedQuery query = entityManager.createQuery("SELECT d FROM Department d LEFT JOIN FETCH d.employees", Department.class); + + List resultList = query.getResultList(); + + assertThat(resultList).hasSize(4); + assertThat(resultList).extracting("name") + .containsOnly("Infra", "Accounting", "Accounting", "Management"); + } + + @Test + public void whenCollectionValuedAssociationIsSpecifiedInSelect_ThenReturnsCollections() { + TypedQuery query = entityManager.createQuery("SELECT e.phones FROM Employee e", Collection.class); + + List resultList = query.getResultList(); + + assertThat(resultList).extracting("number").containsOnly("111", "222", "333"); + } +} diff --git a/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/projection/JpaProjectionIntegrationTest.java b/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/projection/JpaProjectionIntegrationTest.java new file mode 100644 index 0000000000..96eaf4ed07 --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/projection/JpaProjectionIntegrationTest.java @@ -0,0 +1,63 @@ +package com.baeldung.projection; + +import com.baeldung.projection.model.Person; +import com.baeldung.projection.repository.AddressRepository; +import com.baeldung.projection.repository.PersonRepository; +import com.baeldung.projection.view.AddressView; +import com.baeldung.projection.view.PersonDto; +import com.baeldung.projection.view.PersonView; +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.test.context.jdbc.Sql; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.test.context.jdbc.Sql.ExecutionPhase.AFTER_TEST_METHOD; + +@DataJpaTest +@RunWith(SpringRunner.class) +@Sql(scripts = "/projection-insert-data.sql") +@Sql(scripts = "/projection-clean-up-data.sql", executionPhase = AFTER_TEST_METHOD) +public class JpaProjectionIntegrationTest { + @Autowired + private AddressRepository addressRepository; + + @Autowired + private PersonRepository personRepository; + + @Test + public void whenUsingClosedProjections_thenViewWithRequiredPropertiesIsReturned() { + AddressView addressView = addressRepository.getAddressByState("CA").get(0); + assertThat(addressView.getZipCode()).isEqualTo("90001"); + + PersonView personView = addressView.getPerson(); + assertThat(personView.getFirstName()).isEqualTo("John"); + assertThat(personView.getLastName()).isEqualTo("Doe"); + } + + @Test + public void whenUsingOpenProjections_thenViewWithRequiredPropertiesIsReturned() { + PersonView personView = personRepository.findByLastName("Doe"); + assertThat(personView.getFullName()).isEqualTo("John Doe"); + } + + @Test + public void whenUsingClassBasedProjections_thenDtoWithRequiredPropertiesIsReturned() { + PersonDto personDto = personRepository.findByFirstName("John"); + assertThat(personDto.getFirstName()).isEqualTo("John"); + assertThat(personDto.getLastName()).isEqualTo("Doe"); + } + + @Test + public void whenUsingDynamicProjections_thenObjectWithRequiredPropertiesIsReturned() { + Person person = personRepository.findByLastName("Doe", Person.class); + PersonView personView = personRepository.findByLastName("Doe", PersonView.class); + PersonDto personDto = personRepository.findByLastName("Doe", PersonDto.class); + + assertThat(person.getFirstName()).isEqualTo("John"); + assertThat(personView.getFirstName()).isEqualTo("John"); + assertThat(personDto.getFirstName()).isEqualTo("John"); + } +} diff --git a/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/repository/CustomerRepositoryIntegrationTest.java b/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/repository/CustomerRepositoryIntegrationTest.java new file mode 100644 index 0000000000..5d6457ce30 --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/repository/CustomerRepositoryIntegrationTest.java @@ -0,0 +1,64 @@ +package com.baeldung.repository; + +import com.baeldung.entity.Customer; +import org.junit.After; +import org.junit.Before; +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.test.context.junit4.SpringRunner; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import java.util.List; + +import static org.junit.Assert.assertEquals; + +@DataJpaTest +@RunWith(SpringRunner.class) +public class CustomerRepositoryIntegrationTest { + + @PersistenceContext + private EntityManager entityManager; + + @Autowired + private CustomerRepository repository; + + @Before + public void before() { + entityManager.persist(new Customer("A", "A@example.com")); + entityManager.persist(new Customer("D", null)); + entityManager.persist(new Customer("D", "D@example.com")); + } + + @Test + public void givenQueryMethod_whenEmailIsNull_thenFoundByNullEmail() { + List customers = repository.findByNameAndEmail("D", null); + + assertEquals(1, customers.size()); + Customer actual = customers.get(0); + + assertEquals(null, actual.getEmail()); + assertEquals("D", actual.getName()); + } + + @Test + public void givenQueryMethod_whenEmailIsAbsent_thenIgnoreEmail() { + List customers = repository.findByName("D"); + + assertEquals(2, customers.size()); + } + + @Test + public void givenQueryAnnotation_whenEmailIsNull_thenIgnoreEmail() { + List customers = repository.findCustomerByNameAndEmail("D", null); + + assertEquals(2, customers.size()); + } + + @After + public void cleanUp() { + repository.deleteAll(); + } +} \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/repository/EmployeeRepositoryIntegrationTest.java b/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/repository/EmployeeRepositoryIntegrationTest.java new file mode 100644 index 0000000000..ebeed276c9 --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/repository/EmployeeRepositoryIntegrationTest.java @@ -0,0 +1,39 @@ +package com.baeldung.repository; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +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.test.context.junit4.SpringRunner; + +import com.baeldung.entity.Employee; + +@RunWith(SpringRunner.class) +@DataJpaTest +public class EmployeeRepositoryIntegrationTest { + + private static final Employee EMPLOYEE1 = new Employee(1L, "John"); + private static final Employee EMPLOYEE2 = new Employee(2L, "Alice"); + + @Autowired + private EmployeeRepository employeeRepository; + + @Test + public void givenEmployeeEntity_whenInsertWithSave_ThenEmployeeIsPersisted() { + employeeRepository.save(EMPLOYEE1); + assertEmployeePersisted(EMPLOYEE1); + } + + @Test + public void givenEmployeeEntity_whenInsertWithSaveAndFlush_ThenEmployeeIsPersisted() { + employeeRepository.saveAndFlush(EMPLOYEE2); + assertEmployeePersisted(EMPLOYEE2); + } + + private void assertEmployeePersisted(Employee input) { + Employee employee = employeeRepository.getOne(input.getId()); + assertThat(employee).isNotNull(); + } +} diff --git a/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/repository/FruitPopulatorTest.java b/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/repository/FruitPopulatorTest.java new file mode 100644 index 0000000000..29ef52dcef --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/repository/FruitPopulatorTest.java @@ -0,0 +1,38 @@ +package com.baeldung.repository; + +import static org.junit.Assert.assertEquals; + +import java.util.List; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import com.baeldung.entity.Fruit; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class FruitPopulatorTest { + + @Autowired + private FruitRepository fruitRepository; + + @Test + public void givenFruitJsonPopulatorThenShouldInsertRecordOnStart() { + + List fruits = fruitRepository.findAll(); + assertEquals("record count is not matching", 2, fruits.size()); + + fruits.forEach(fruit -> { + if (1 == fruit.getId()) { + assertEquals("apple", fruit.getName()); + assertEquals("red", fruit.getColor()); + } else if (2 == fruit.getId()) { + assertEquals("guava", fruit.getName()); + assertEquals("green", fruit.getColor()); + } + }); + } +} diff --git a/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/repository/FruitRepositoryIntegrationTest.java b/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/repository/FruitRepositoryIntegrationTest.java new file mode 100644 index 0000000000..866cf1157b --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/repository/FruitRepositoryIntegrationTest.java @@ -0,0 +1,77 @@ +package com.baeldung.repository; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.List; + +import org.junit.jupiter.api.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.jdbc.Sql; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.transaction.annotation.Transactional; + +import com.baeldung.entity.Fruit; + +@RunWith(SpringRunner.class) +@SpringBootTest +class FruitRepositoryIntegrationTest { + + @Autowired + private FruitRepository fruitRepository; + + @Transactional + @Test + @Sql(scripts = { "/test-fruit-data.sql" }) + public void givenFruits_WhenDeletedByColor_ThenDeletedFruitsShouldReturn() { + + List fruits = fruitRepository.deleteByColor("green"); + + assertEquals("number of fruits are not matching", 2, fruits.size()); + fruits.forEach(fruit -> assertEquals("Its not a green fruit", "green", fruit.getColor())); + } + + @Transactional + @Test + @Sql(scripts = { "/test-fruit-data.sql" }) + public void givenFruits_WhenDeletedByName_ThenDeletedFruitCountShouldReturn() { + + Long deletedFruitCount = fruitRepository.deleteByName("apple"); + + assertEquals("deleted fruit count is not matching", 1, deletedFruitCount.intValue()); + } + + @Transactional + @Test + @Sql(scripts = { "/test-fruit-data.sql" }) + public void givenFruits_WhenRemovedByColor_ThenDeletedFruitsShouldReturn() { + + List fruits = fruitRepository.removeByColor("green"); + + assertEquals("number of fruits are not matching", 2, fruits.size()); + fruits.forEach(fruit -> assertEquals("Its not a green fruit", "green", fruit.getColor())); + } + + @Transactional + @Test + @Sql(scripts = { "/test-fruit-data.sql" }) + public void givenFruits_WhenRemovedByName_ThenDeletedFruitCountShouldReturn() { + + Long deletedFruitCount = fruitRepository.removeByName("apple"); + + assertEquals("deleted fruit count is not matching", 1, deletedFruitCount.intValue()); + } + + @Transactional + @Test + @Sql(scripts = { "/test-fruit-data.sql" }) + public void givenFruits_WhenDeletedByColorOrName_ThenDeletedFruitsShouldReturn() { + + List fruits = fruitRepository.deleteFruits("apple", "green"); + + assertEquals("number of fruits are not matching", 3, fruits.size()); + fruits.forEach(fruit -> assertTrue("Its not a green fruit or apple", ("green".equals(fruit.getColor())) || "apple".equals(fruit.getColor()))); + } +} \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/repository/PassengerRepositoryIntegrationTest.java b/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/repository/PassengerRepositoryIntegrationTest.java new file mode 100644 index 0000000000..f96f0249d7 --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/repository/PassengerRepositoryIntegrationTest.java @@ -0,0 +1,54 @@ +package com.baeldung.repository; + +import com.baeldung.entity.Passenger; +import org.junit.Before; +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.test.context.junit4.SpringRunner; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import java.util.List; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.core.IsNot.not; + +@DataJpaTest +@RunWith(SpringRunner.class) +public class PassengerRepositoryIntegrationTest { + + @PersistenceContext + private EntityManager entityManager; + @Autowired + private PassengerRepository repository; + + @Before + public void before() { + entityManager.persist(Passenger.from("Jill", "Smith")); + entityManager.persist(Passenger.from("Eve", "Jackson")); + entityManager.persist(Passenger.from("Fred", "Bloggs")); + entityManager.persist(Passenger.from("Ricki", "Bobbie")); + entityManager.persist(Passenger.from("Siya", "Kolisi")); + } + + @Test + public void givenPassengers_whenMatchingIgnoreCase_thenExpectedReturned() { + Passenger jill = Passenger.from("Jill", "Smith"); + Passenger eve = Passenger.from("Eve", "Jackson"); + Passenger fred = Passenger.from("Fred", "Bloggs"); + Passenger siya = Passenger.from("Siya", "Kolisi"); + Passenger ricki = Passenger.from("Ricki", "Bobbie"); + + List passengers = repository.findByFirstNameIgnoreCase("FRED"); + + assertThat(passengers, contains(fred)); + assertThat(passengers, not(contains(eve))); + assertThat(passengers, not(contains(siya))); + assertThat(passengers, not(contains(jill))); + assertThat(passengers, not(contains(ricki))); + + } +} diff --git a/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/repository/SongRepositoryIntegrationTest.java b/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/repository/SongRepositoryIntegrationTest.java new file mode 100644 index 0000000000..c3d0636881 --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/repository/SongRepositoryIntegrationTest.java @@ -0,0 +1,57 @@ +package com.baeldung.repository; + +import com.baeldung.entity.Song; +import org.junit.jupiter.api.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.jdbc.Sql; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +import static org.junit.Assert.assertEquals; + +@RunWith(SpringRunner.class) +@SpringBootTest +@Sql(scripts = { "/test-song-data.sql" }) +public class SongRepositoryIntegrationTest { + + @Autowired private SongRepository songRepository; + + @Transactional + @Test + public void givenSong_WhenFindLikeByName_ThenShouldReturnOne() { + List songs = songRepository.findByNameLike("Despacito"); + assertEquals(1, songs.size()); + } + + @Transactional + @Test + public void givenSong_WhenFindByNameNotLike_thenShouldReturn3Songs() { + List songs = songRepository.findByNameNotLike("Despacito"); + assertEquals(5, songs.size()); + } + + @Transactional + @Test + public void givenSong_WhenFindByNameStartingWith_thenShouldReturn2Songs() { + List songs = songRepository.findByNameStartingWith("Co"); + assertEquals(2, songs.size()); + } + + @Transactional + @Test + public void givenSong_WhenFindByNameEndingWith_thenShouldReturn2Songs() { + List songs = songRepository.findByNameEndingWith("Life"); + assertEquals(2, songs.size()); + } + + @Transactional + @Test + public void givenSong_WhenFindBySingerContaining_thenShouldReturn2Songs() { + List songs = songRepository.findBySingerContaining("Luis"); + assertEquals(2, songs.size()); + } +} diff --git a/persistence-modules/spring-data-jpa-2/src/test/resources/entitygraph-data.sql b/persistence-modules/spring-data-jpa-2/src/test/resources/entitygraph-data.sql new file mode 100644 index 0000000000..685ec2c605 --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/test/resources/entitygraph-data.sql @@ -0,0 +1,7 @@ +INSERT INTO Item(id,name) VALUES (1,'Table'); +INSERT INTO Item(id,name) VALUES (2,'Bottle'); + +INSERT INTO Characteristic(id,item_id, type) VALUES (1,1,'Rigid'); +INSERT INTO Characteristic(id,item_id,type) VALUES (2,1,'Big'); +INSERT INTO Characteristic(id,item_id,type) VALUES (3,2,'Fragile'); +INSERT INTO Characteristic(id,item_id,type) VALUES (4,2,'Small'); \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa-2/src/test/resources/projection-clean-up-data.sql b/persistence-modules/spring-data-jpa-2/src/test/resources/projection-clean-up-data.sql new file mode 100644 index 0000000000..d34f6f0636 --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/test/resources/projection-clean-up-data.sql @@ -0,0 +1,2 @@ +DELETE FROM address; +DELETE FROM person; \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa-2/src/test/resources/projection-insert-data.sql b/persistence-modules/spring-data-jpa-2/src/test/resources/projection-insert-data.sql new file mode 100644 index 0000000000..544dcc4b88 --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/test/resources/projection-insert-data.sql @@ -0,0 +1,2 @@ +INSERT INTO person(id,first_name,last_name) VALUES (1,'John','Doe'); +INSERT INTO address(id,person_id,state,city,street,zip_code) VALUES (1,1,'CA', 'Los Angeles', 'Standford Ave', '90001'); \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa-2/src/test/resources/test-fruit-data.sql b/persistence-modules/spring-data-jpa-2/src/test/resources/test-fruit-data.sql new file mode 100644 index 0000000000..ce2189121f --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/test/resources/test-fruit-data.sql @@ -0,0 +1,4 @@ +insert into fruit(id,name,color) values (1,'apple','red'); +insert into fruit(id,name,color) values (2,'custard apple','green'); +insert into fruit(id,name,color) values (3,'mango','yellow'); +insert into fruit(id,name,color) values (4,'guava','green'); \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa-2/src/test/resources/test-song-data.sql b/persistence-modules/spring-data-jpa-2/src/test/resources/test-song-data.sql new file mode 100644 index 0000000000..5a2b1a5555 --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/test/resources/test-song-data.sql @@ -0,0 +1,8 @@ +INSERT INTO song(id,name,length_in_seconds,compositor,singer,released,genre) +VALUES +(1,'Despacito',209,'Luis Fonsi','Luis Fonsi, Daddy Yankee','2017-01-12','Reggaeton'), +(2,'Con calma',188,'Daddy Yankee','Daddy Yankee','2019-01-24','Reggaeton'), +(3,'It''s My Life',205,'Bon Jovi','Jon Bon Jovi','2000-05-23','Pop'), +(4,'Live is Life',242,'Opus','Opus','1985-01-01','Reggae'), +(5,'Countdown to Extinction',249,'Megadeth','Megadeth','1992-07-14','Heavy Metal'), +(6, 'Si nos dejan',139,'Luis Miguel','Luis Miguel','1995-10-17','Bolero'); \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa/README.md b/persistence-modules/spring-data-jpa/README.md index 9512ad336d..4e390c2faf 100644 --- a/persistence-modules/spring-data-jpa/README.md +++ b/persistence-modules/spring-data-jpa/README.md @@ -5,7 +5,7 @@ ### Relevant Articles: - [Spring JPA – Multiple Databases](http://www.baeldung.com/spring-data-jpa-multiple-databases) - [Spring Data JPA – Adding a Method in All Repositories](http://www.baeldung.com/spring-data-jpa-method-in-all-repositories) -- [Advanced Tagging Implementation with JPA](http://www.baeldung.com/jpa-tagging-advanced) +- [An Advanced Tagging Implementation with JPA](http://www.baeldung.com/jpa-tagging-advanced) - [Spring Data JPA @Query](http://www.baeldung.com/spring-data-jpa-query) - [Spring Data Annotations](http://www.baeldung.com/spring-data-annotations) - [Spring Data Java 8 Support](http://www.baeldung.com/spring-data-java-8) @@ -22,6 +22,7 @@ - [Spring Data JPA Query by Example](https://www.baeldung.com/spring-data-query-by-example) - [DB Integration Tests with Spring Boot and Testcontainers](https://www.baeldung.com/spring-boot-testcontainers-integration-test) - [Spring Data JPA @Modifying Annotation](https://www.baeldung.com/spring-data-jpa-modifying-annotation) +- [Spring Data JPA Batch Inserts](https://www.baeldung.com/spring-data-jpa-batch-inserts) ### Eclipse Config After importing the project into Eclipse, you may see the following error: diff --git a/persistence-modules/spring-data-jpa/pom.xml b/persistence-modules/spring-data-jpa/pom.xml index 401f4877ac..a7788065c9 100644 --- a/persistence-modules/spring-data-jpa/pom.xml +++ b/persistence-modules/spring-data-jpa/pom.xml @@ -53,6 +53,15 @@ spring-security-test test + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-test + test + com.google.guava @@ -80,5 +89,9 @@ test + + + com.baeldung.boot.Application + \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/Application.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/Application.java similarity index 75% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/Application.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/Application.java index 72d29d9fa5..1f078801e2 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/Application.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/Application.java @@ -1,10 +1,11 @@ -package com.baeldung; +package com.baeldung.boot; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; -import com.baeldung.dao.repositories.impl.ExtendedRepositoryImpl; +import com.baeldung.boot.daos.impl.ExtendedRepositoryImpl; +import com.baeldung.multipledb.MultipleDbApplication; @SpringBootApplication @EnableJpaRepositories(repositoryBaseClass = ExtendedRepositoryImpl.class) diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/config/PersistenceConfiguration.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/config/PersistenceConfiguration.java new file mode 100644 index 0000000000..35a603d9f4 --- /dev/null +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/config/PersistenceConfiguration.java @@ -0,0 +1,21 @@ +package com.baeldung.boot.config; + +import com.baeldung.boot.services.IBarService; +import com.baeldung.boot.services.impl.BarSpringDataJpaService; +import org.springframework.context.annotation.*; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +@Configuration +@Profile("!tc") +@EnableTransactionManagement +@EnableJpaAuditing +public class PersistenceConfiguration { + + @Bean + public IBarService barSpringDataJpaService() { + return new BarSpringDataJpaService(); + } + +} \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/ArticleRepository.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/ArticleRepository.java similarity index 90% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/ArticleRepository.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/ArticleRepository.java index 8402c099d9..73397ad42e 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/ArticleRepository.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/ArticleRepository.java @@ -1,10 +1,11 @@ -package com.baeldung.dao.repositories; +package com.baeldung.boot.daos; -import com.baeldung.domain.Article; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; +import com.baeldung.boot.domain.Article; + import java.util.Date; import java.util.List; diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/CustomItemRepository.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/CustomItemRepository.java similarity index 54% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/CustomItemRepository.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/CustomItemRepository.java index 4299f9e3bb..0aebe34921 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/CustomItemRepository.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/CustomItemRepository.java @@ -1,10 +1,8 @@ -package com.baeldung.dao.repositories; - -import java.util.List; +package com.baeldung.boot.daos; import org.springframework.stereotype.Repository; -import com.baeldung.domain.Item; +import com.baeldung.boot.domain.Item; @Repository public interface CustomItemRepository { @@ -15,7 +13,4 @@ public interface CustomItemRepository { void findThenDelete(Long id); - List findItemsByColorAndGrade(); - - List findItemByColorOrGrade(); } diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/CustomItemTypeRepository.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/CustomItemTypeRepository.java similarity index 71% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/CustomItemTypeRepository.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/CustomItemTypeRepository.java index 81ebdf3fda..832d61408c 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/CustomItemTypeRepository.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/CustomItemTypeRepository.java @@ -1,8 +1,8 @@ -package com.baeldung.dao.repositories; +package com.baeldung.boot.daos; import org.springframework.stereotype.Repository; -import com.baeldung.domain.ItemType; +import com.baeldung.boot.domain.ItemType; @Repository public interface CustomItemTypeRepository { diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/CustomerRepository.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/CustomerRepository.java new file mode 100644 index 0000000000..2f1af6ac55 --- /dev/null +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/CustomerRepository.java @@ -0,0 +1,15 @@ +package com.baeldung.boot.daos; + +import org.springframework.data.repository.CrudRepository; + +import com.baeldung.boot.domain.Customer; + +/** + * JPA CrudRepository interface + * + * @author ysharma2512 + * + */ +public interface CustomerRepository extends CrudRepository{ + +} diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/ExtendedRepository.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/ExtendedRepository.java similarity index 90% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/ExtendedRepository.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/ExtendedRepository.java index 9e82f02fa6..adb2af4320 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/ExtendedRepository.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/ExtendedRepository.java @@ -1,4 +1,4 @@ -package com.baeldung.dao.repositories; +package com.baeldung.boot.daos; import java.io.Serializable; import java.util.List; diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/ExtendedStudentRepository.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/ExtendedStudentRepository.java similarity index 54% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/ExtendedStudentRepository.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/ExtendedStudentRepository.java index 199e4e5ff6..c9b0192536 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/ExtendedStudentRepository.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/ExtendedStudentRepository.java @@ -1,6 +1,6 @@ -package com.baeldung.dao.repositories; +package com.baeldung.boot.daos; -import com.baeldung.domain.Student; +import com.baeldung.boot.domain.Student; public interface ExtendedStudentRepository extends ExtendedRepository { } diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/IBarCrudRepository.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/IBarCrudRepository.java similarity index 71% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/IBarCrudRepository.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/IBarCrudRepository.java index 54a7d77691..921fabe3fb 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/IBarCrudRepository.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/IBarCrudRepository.java @@ -1,8 +1,9 @@ -package com.baeldung.dao.repositories; +package com.baeldung.boot.daos; -import com.baeldung.domain.Bar; import org.springframework.data.repository.CrudRepository; +import com.baeldung.boot.domain.Bar; + import java.io.Serializable; public interface IBarCrudRepository extends CrudRepository { diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/IFooDao.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/IFooDao.java similarity index 83% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/IFooDao.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/IFooDao.java index bb3c229945..d537772076 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/IFooDao.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/IFooDao.java @@ -1,10 +1,11 @@ -package com.baeldung.dao; +package com.baeldung.boot.daos; -import com.baeldung.domain.Foo; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; +import com.baeldung.boot.domain.Foo; + public interface IFooDao extends JpaRepository { @Query("SELECT f FROM Foo f WHERE LOWER(f.name) = LOWER(:name)") diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/InventoryRepository.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/InventoryRepository.java similarity index 63% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/InventoryRepository.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/InventoryRepository.java index a575f0b915..606f3993d5 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/InventoryRepository.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/InventoryRepository.java @@ -1,7 +1,8 @@ -package com.baeldung.dao.repositories; +package com.baeldung.boot.daos; -import com.baeldung.domain.MerchandiseEntity; import org.springframework.data.repository.CrudRepository; +import com.baeldung.boot.domain.MerchandiseEntity; + public interface InventoryRepository extends CrudRepository { } diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/ItemTypeRepository.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/ItemTypeRepository.java similarity index 76% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/ItemTypeRepository.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/ItemTypeRepository.java index 2af83bc322..413c09e968 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/ItemTypeRepository.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/ItemTypeRepository.java @@ -1,9 +1,9 @@ -package com.baeldung.dao.repositories; +package com.baeldung.boot.daos; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; -import com.baeldung.domain.ItemType; +import com.baeldung.boot.domain.ItemType; @Repository public interface ItemTypeRepository extends JpaRepository, CustomItemTypeRepository, CustomItemRepository { diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/LocationRepository.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/LocationRepository.java similarity index 72% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/LocationRepository.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/LocationRepository.java index 27bbe27af0..697ce295d0 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/LocationRepository.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/LocationRepository.java @@ -1,9 +1,9 @@ -package com.baeldung.dao.repositories; +package com.baeldung.boot.daos; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; -import com.baeldung.domain.Location; +import com.baeldung.boot.domain.Location; @Repository public interface LocationRepository extends JpaRepository { diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/ReadOnlyLocationRepository.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/ReadOnlyLocationRepository.java similarity index 79% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/ReadOnlyLocationRepository.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/ReadOnlyLocationRepository.java index 8f68cdbbe5..3a2ea3cda5 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/ReadOnlyLocationRepository.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/ReadOnlyLocationRepository.java @@ -1,10 +1,10 @@ -package com.baeldung.dao.repositories; +package com.baeldung.boot.daos; import java.util.Optional; import org.springframework.data.repository.Repository; -import com.baeldung.domain.Location; +import com.baeldung.boot.domain.Location; @org.springframework.stereotype.Repository public interface ReadOnlyLocationRepository extends Repository { diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/StoreRepository.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/StoreRepository.java similarity index 79% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/StoreRepository.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/StoreRepository.java index 9318c32ee9..ae13f75f66 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/StoreRepository.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/StoreRepository.java @@ -1,11 +1,11 @@ -package com.baeldung.dao.repositories; +package com.baeldung.boot.daos; import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; -import com.baeldung.domain.Store; +import com.baeldung.boot.domain.Store; @Repository public interface StoreRepository extends JpaRepository { diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/impl/CustomItemRepositoryImpl.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/impl/CustomItemRepositoryImpl.java new file mode 100644 index 0000000000..820a2cdd41 --- /dev/null +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/impl/CustomItemRepositoryImpl.java @@ -0,0 +1,33 @@ +package com.baeldung.boot.daos.impl; + +import javax.persistence.EntityManager; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Repository; + +import com.baeldung.boot.daos.CustomItemRepository; +import com.baeldung.boot.domain.Item; + +@Repository +public class CustomItemRepositoryImpl implements CustomItemRepository { + + @Autowired + private EntityManager entityManager; + + @Override + public void deleteCustom(Item item) { + entityManager.remove(item); + } + + @Override + public Item findItemById(Long id) { + return entityManager.find(Item.class, id); + } + + @Override + public void findThenDelete(Long id) { + final Item item = entityManager.find(Item.class, id); + entityManager.remove(item); + } + +} diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/impl/CustomItemTypeRepositoryImpl.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/impl/CustomItemTypeRepositoryImpl.java similarity index 84% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/impl/CustomItemTypeRepositoryImpl.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/impl/CustomItemTypeRepositoryImpl.java index 2b49f2380c..d7cba7c2c6 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/impl/CustomItemTypeRepositoryImpl.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/impl/CustomItemTypeRepositoryImpl.java @@ -1,4 +1,4 @@ -package com.baeldung.dao.repositories.impl; +package com.baeldung.boot.daos.impl; import javax.persistence.EntityManager; @@ -7,8 +7,8 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; -import com.baeldung.domain.ItemType; -import com.baeldung.dao.repositories.CustomItemTypeRepository; +import com.baeldung.boot.daos.CustomItemTypeRepository; +import com.baeldung.boot.domain.ItemType; @Repository public class CustomItemTypeRepositoryImpl implements CustomItemTypeRepository { diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/impl/ExtendedRepositoryImpl.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/impl/ExtendedRepositoryImpl.java similarity index 93% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/impl/ExtendedRepositoryImpl.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/impl/ExtendedRepositoryImpl.java index f6f06efb51..fbe6695844 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/impl/ExtendedRepositoryImpl.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/impl/ExtendedRepositoryImpl.java @@ -1,4 +1,4 @@ -package com.baeldung.dao.repositories.impl; +package com.baeldung.boot.daos.impl; import java.io.Serializable; import java.util.List; @@ -10,10 +10,11 @@ import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Root; import javax.transaction.Transactional; -import com.baeldung.dao.repositories.ExtendedRepository; import org.springframework.data.jpa.repository.support.JpaEntityInformation; import org.springframework.data.jpa.repository.support.SimpleJpaRepository; +import com.baeldung.boot.daos.ExtendedRepository; + public class ExtendedRepositoryImpl extends SimpleJpaRepository implements ExtendedRepository { private EntityManager entityManager; diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/impl/PersonInsertRepository.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/impl/PersonInsertRepository.java similarity index 90% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/impl/PersonInsertRepository.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/impl/PersonInsertRepository.java index d809385456..373532e1c3 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/impl/PersonInsertRepository.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/impl/PersonInsertRepository.java @@ -1,8 +1,9 @@ -package com.baeldung.dao.repositories.impl; +package com.baeldung.boot.daos.impl; -import com.baeldung.domain.Person; import org.springframework.stereotype.Repository; +import com.baeldung.boot.domain.Person; + import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.transaction.Transactional; diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/user/PossessionRepository.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/user/PossessionRepository.java similarity index 62% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/user/PossessionRepository.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/user/PossessionRepository.java index f0eeb475c1..e102754c18 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/user/PossessionRepository.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/user/PossessionRepository.java @@ -1,8 +1,9 @@ -package com.baeldung.dao.repositories.user; +package com.baeldung.boot.daos.user; -import com.baeldung.domain.user.Possession; import org.springframework.data.jpa.repository.JpaRepository; +import com.baeldung.boot.domain.Possession; + public interface PossessionRepository extends JpaRepository { } diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/user/UserRepository.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/user/UserRepository.java similarity index 92% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/user/UserRepository.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/user/UserRepository.java index 1d05a17414..d6a060740d 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/user/UserRepository.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/user/UserRepository.java @@ -1,6 +1,5 @@ -package com.baeldung.dao.repositories.user; +package com.baeldung.boot.daos.user; -import com.baeldung.domain.user.User; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; @@ -9,6 +8,8 @@ import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; +import com.baeldung.boot.domain.User; + import java.time.LocalDate; import java.util.Collection; import java.util.List; @@ -18,11 +19,11 @@ public interface UserRepository extends JpaRepository , UserRepos Stream findAllByName(String name); - @Query("select u from User u where u.email like '%@gmail.com'") - List findUsersWithGmailAddress(); - @Query("SELECT u FROM User u WHERE u.status = 1") Collection findAllActiveUsers(); + + @Query("select u from User u where u.email like '%@gmail.com'") + List findUsersWithGmailAddress(); @Query(value = "SELECT * FROM Users u WHERE u.status = 1", nativeQuery = true) Collection findAllActiveUsersNative(); @@ -74,14 +75,14 @@ public interface UserRepository extends JpaRepository , UserRepos @Query(value = "INSERT INTO Users (name, age, email, status, active) VALUES (:name, :age, :email, :status, :active)", nativeQuery = true) @Modifying void insertUser(@Param("name") String name, @Param("age") Integer age, @Param("email") String email, @Param("status") Integer status, @Param("active") boolean active); - + @Modifying @Query(value = "UPDATE Users u SET status = ? WHERE u.name = ?", nativeQuery = true) int updateUserSetStatusForNameNativePostgres(Integer status, String name); - + @Query(value = "SELECT u FROM User u WHERE u.name IN :names") - List findUserByNameList(@Param("names") Collection names); - + List findUserByNameList(@Param("names") Collection names); + void deleteAllByCreationDateAfter(LocalDate date); @Modifying(clearAutomatically = true, flushAutomatically = true) @@ -89,11 +90,10 @@ public interface UserRepository extends JpaRepository , UserRepos void deactivateUsersNotLoggedInSince(@Param("date") LocalDate date); @Modifying(clearAutomatically = true, flushAutomatically = true) - @Query("delete from User u where u.active = false") + @Query("delete User u where u.active = false") int deleteDeactivatedUsers(); @Modifying(clearAutomatically = true, flushAutomatically = true) - @Query(value = "alter table Users add column deleted int(1) not null default 0", nativeQuery = true) + @Query(value = "alter table USERS.USERS add column deleted int(1) not null default 0", nativeQuery = true) void addDeletedColumn(); - } diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/user/UserRepositoryCustom.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/user/UserRepositoryCustom.java similarity index 77% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/user/UserRepositoryCustom.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/user/UserRepositoryCustom.java index 0f29cd656e..c586b54027 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/user/UserRepositoryCustom.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/user/UserRepositoryCustom.java @@ -1,14 +1,14 @@ -package com.baeldung.dao.repositories.user; +package com.baeldung.boot.daos.user; import java.util.Collection; import java.util.List; import java.util.Set; import java.util.function.Predicate; -import com.baeldung.domain.user.User; +import com.baeldung.boot.domain.User; public interface UserRepositoryCustom { List findUserByEmails(Set emails); - + List findAllUsersByPredicates(Collection> predicates); } diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/user/UserRepositoryCustomImpl.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/user/UserRepositoryCustomImpl.java similarity index 95% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/user/UserRepositoryCustomImpl.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/user/UserRepositoryCustomImpl.java index 7b2a7ab123..63a743b6b5 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/user/UserRepositoryCustomImpl.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/daos/user/UserRepositoryCustomImpl.java @@ -1,4 +1,4 @@ -package com.baeldung.dao.repositories.user; +package com.baeldung.boot.daos.user; import java.util.ArrayList; import java.util.Collection; @@ -15,7 +15,7 @@ import javax.persistence.criteria.Path; import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Root; -import com.baeldung.domain.user.User; +import com.baeldung.boot.domain.User; public class UserRepositoryCustomImpl implements UserRepositoryCustom { @@ -42,7 +42,7 @@ public class UserRepositoryCustomImpl implements UserRepositoryCustom { return entityManager.createQuery(query) .getResultList(); } - + @Override public List findAllUsersByPredicates(Collection> predicates) { List allUsers = entityManager.createQuery("select u from User u", User.class).getResultList(); diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/ddd/event/Aggregate.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/ddd/event/Aggregate.java similarity index 95% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/ddd/event/Aggregate.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/ddd/event/Aggregate.java index bf6ff0a0b9..e435f4c85c 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/ddd/event/Aggregate.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/ddd/event/Aggregate.java @@ -1,7 +1,7 @@ /** * */ -package com.baeldung.ddd.event; +package com.baeldung.boot.ddd.event; import javax.persistence.Entity; import javax.persistence.Id; diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/ddd/event/Aggregate2.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/ddd/event/Aggregate2.java similarity index 95% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/ddd/event/Aggregate2.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/ddd/event/Aggregate2.java index 3d2816299a..08f61db812 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/ddd/event/Aggregate2.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/ddd/event/Aggregate2.java @@ -1,7 +1,7 @@ /** * */ -package com.baeldung.ddd.event; +package com.baeldung.boot.ddd.event; import java.util.ArrayList; import java.util.Collection; diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/ddd/event/Aggregate2Repository.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/ddd/event/Aggregate2Repository.java similarity index 80% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/ddd/event/Aggregate2Repository.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/ddd/event/Aggregate2Repository.java index 2a95abe347..7f09c410fc 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/ddd/event/Aggregate2Repository.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/ddd/event/Aggregate2Repository.java @@ -1,7 +1,7 @@ /** * */ -package com.baeldung.ddd.event; +package com.baeldung.boot.ddd.event; import org.springframework.data.repository.CrudRepository; diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/ddd/event/Aggregate3.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/ddd/event/Aggregate3.java similarity index 91% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/ddd/event/Aggregate3.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/ddd/event/Aggregate3.java index e0c3131b06..f664322a59 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/ddd/event/Aggregate3.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/ddd/event/Aggregate3.java @@ -1,7 +1,7 @@ /** * */ -package com.baeldung.ddd.event; +package com.baeldung.boot.ddd.event; import javax.persistence.Entity; import javax.persistence.GeneratedValue; diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/ddd/event/Aggregate3Repository.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/ddd/event/Aggregate3Repository.java similarity index 83% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/ddd/event/Aggregate3Repository.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/ddd/event/Aggregate3Repository.java index e442bdb210..93f50bb5cf 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/ddd/event/Aggregate3Repository.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/ddd/event/Aggregate3Repository.java @@ -1,7 +1,7 @@ /** * */ -package com.baeldung.ddd.event; +package com.baeldung.boot.ddd.event; import org.springframework.data.repository.CrudRepository; diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/ddd/event/AggregateRepository.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/ddd/event/AggregateRepository.java similarity index 80% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/ddd/event/AggregateRepository.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/ddd/event/AggregateRepository.java index 5a15156d03..1c2d3884bf 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/ddd/event/AggregateRepository.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/ddd/event/AggregateRepository.java @@ -1,7 +1,7 @@ /** * */ -package com.baeldung.ddd.event; +package com.baeldung.boot.ddd.event; import org.springframework.data.repository.CrudRepository; diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/ddd/event/DddConfig.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/ddd/event/DddConfig.java similarity index 89% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/ddd/event/DddConfig.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/ddd/event/DddConfig.java index 1315b11875..34cf21463b 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/ddd/event/DddConfig.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/ddd/event/DddConfig.java @@ -1,7 +1,7 @@ /** * */ -package com.baeldung.ddd.event; +package com.baeldung.boot.ddd.event; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/ddd/event/DomainEvent.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/ddd/event/DomainEvent.java new file mode 100644 index 0000000000..e7626e742d --- /dev/null +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/ddd/event/DomainEvent.java @@ -0,0 +1,8 @@ +/** + * + */ +package com.baeldung.boot.ddd.event; + +class DomainEvent { + +} diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/ddd/event/DomainService.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/ddd/event/DomainService.java similarity index 95% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/ddd/event/DomainService.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/ddd/event/DomainService.java index 082c9bd88e..80aa5ca6cb 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/ddd/event/DomainService.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/ddd/event/DomainService.java @@ -1,7 +1,7 @@ /** * */ -package com.baeldung.ddd.event; +package com.baeldung.boot.ddd.event; import javax.transaction.Transactional; diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/domain/Article.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/domain/Article.java similarity index 92% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/domain/Article.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/domain/Article.java index 3b5a8be088..de4dbed1a0 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/domain/Article.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/domain/Article.java @@ -1,4 +1,4 @@ -package com.baeldung.domain; +package com.baeldung.boot.domain; import javax.persistence.*; import java.util.Date; diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/domain/Bar.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/domain/Bar.java similarity index 99% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/domain/Bar.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/domain/Bar.java index efd297bafc..35d1903801 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/domain/Bar.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/domain/Bar.java @@ -1,4 +1,4 @@ -package com.baeldung.domain; +package com.baeldung.boot.domain; import com.google.common.collect.Sets; import org.hibernate.annotations.OrderBy; diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/domain/Customer.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/domain/Customer.java new file mode 100644 index 0000000000..af88be0be6 --- /dev/null +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/domain/Customer.java @@ -0,0 +1,56 @@ +package com.baeldung.boot.domain; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; + +/** + * Customer Entity class + * @author ysharma2512 + * + */ +@Entity +public class Customer { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private Long id; + private String firstName; + private String lastName; + + public Customer(String firstName, String lastName) { + this.firstName = firstName; + this.lastName = lastName; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + @Override + public String toString() { + return String.format("Customer[id=%d, firstName='%s', lastName='%s']", id, firstName, lastName); + } + +} diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/domain/Foo.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/domain/Foo.java similarity index 98% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/domain/Foo.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/domain/Foo.java index ef88840746..5030e5600b 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/domain/Foo.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/domain/Foo.java @@ -1,4 +1,4 @@ -package com.baeldung.domain; +package com.baeldung.boot.domain; import org.hibernate.envers.Audited; diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/domain/Item.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/domain/Item.java similarity index 97% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/domain/Item.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/domain/Item.java index 1e58fb25ba..8ac06af15a 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/domain/Item.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/domain/Item.java @@ -1,4 +1,4 @@ -package com.baeldung.domain; +package com.baeldung.boot.domain; import java.math.BigDecimal; diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/domain/ItemType.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/domain/ItemType.java similarity index 96% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/domain/ItemType.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/domain/ItemType.java index b0349e0471..8a52a9847c 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/domain/ItemType.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/domain/ItemType.java @@ -1,4 +1,4 @@ -package com.baeldung.domain; +package com.baeldung.boot.domain; import java.util.ArrayList; import java.util.List; diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/domain/KVTag.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/domain/KVTag.java similarity index 94% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/domain/KVTag.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/domain/KVTag.java index b3e7d78b30..1901f43c0a 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/domain/KVTag.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/domain/KVTag.java @@ -1,4 +1,4 @@ -package com.baeldung.domain; +package com.baeldung.boot.domain; import javax.persistence.Embeddable; diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/domain/Location.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/domain/Location.java similarity index 96% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/domain/Location.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/domain/Location.java index 4ca7295986..9c1b93d551 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/domain/Location.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/domain/Location.java @@ -1,4 +1,4 @@ -package com.baeldung.domain; +package com.baeldung.boot.domain; import java.util.ArrayList; import java.util.List; diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/domain/MerchandiseEntity.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/domain/MerchandiseEntity.java similarity index 97% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/domain/MerchandiseEntity.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/domain/MerchandiseEntity.java index bfc690e0e2..e94c23de86 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/domain/MerchandiseEntity.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/domain/MerchandiseEntity.java @@ -1,4 +1,4 @@ -package com.baeldung.domain; +package com.baeldung.boot.domain; import javax.persistence.Entity; import javax.persistence.GeneratedValue; diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/domain/Person.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/domain/Person.java similarity index 95% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/domain/Person.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/domain/Person.java index 30d7370982..88894ccc72 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/domain/Person.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/domain/Person.java @@ -1,4 +1,4 @@ -package com.baeldung.domain; +package com.baeldung.boot.domain; import javax.persistence.Entity; import javax.persistence.Id; diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/domain/user/Possession.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/domain/Possession.java similarity index 95% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/domain/user/Possession.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/domain/Possession.java index b1427c0270..f13491ad82 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/domain/user/Possession.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/domain/Possession.java @@ -1,6 +1,7 @@ -package com.baeldung.domain.user; +package com.baeldung.boot.domain; import javax.persistence.*; +import com.baeldung.boot.domain.Possession; @Entity @Table diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/domain/SkillTag.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/domain/SkillTag.java similarity index 93% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/domain/SkillTag.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/domain/SkillTag.java index 1f2778c589..0933a3e6af 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/domain/SkillTag.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/domain/SkillTag.java @@ -1,4 +1,4 @@ -package com.baeldung.domain; +package com.baeldung.boot.domain; import javax.persistence.Embeddable; diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/domain/Store.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/domain/Store.java similarity index 97% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/domain/Store.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/domain/Store.java index 4172051c71..5b4b831cc7 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/domain/Store.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/domain/Store.java @@ -1,4 +1,4 @@ -package com.baeldung.domain; +package com.baeldung.boot.domain; import java.util.ArrayList; import java.util.List; diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/domain/Student.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/domain/Student.java similarity index 97% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/domain/Student.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/domain/Student.java index bd7eaeb24b..1003167cc7 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/domain/Student.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/domain/Student.java @@ -1,4 +1,4 @@ -package com.baeldung.domain; +package com.baeldung.boot.domain; import javax.persistence.ElementCollection; import javax.persistence.Entity; diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/domain/user/User.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/domain/User.java similarity index 96% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/domain/user/User.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/domain/User.java index 7109271eeb..cca00e52a2 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/domain/user/User.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/domain/User.java @@ -1,6 +1,7 @@ -package com.baeldung.domain.user; +package com.baeldung.boot.domain; import javax.persistence.*; + import java.time.LocalDate; import java.util.List; import java.util.Objects; @@ -27,7 +28,7 @@ public class User { super(); } - public User(String name, LocalDate creationDate, String email, Integer status) { + public User(String name, LocalDate creationDate,String email, Integer status) { this.name = name; this.creationDate = creationDate; this.email = email; @@ -51,10 +52,6 @@ public class User { this.name = name; } - public LocalDate getCreationDate() { - return creationDate; - } - public String getEmail() { return email; } @@ -78,6 +75,10 @@ public class User { public void setAge(final int age) { this.age = age; } + + public LocalDate getCreationDate() { + return creationDate; + } public List getPossessionList() { return possessionList; @@ -93,7 +94,7 @@ public class User { builder.append("User [name=").append(name).append(", id=").append(id).append("]"); return builder.toString(); } - + @Override public boolean equals(Object o) { if (this == o) return true; @@ -127,4 +128,5 @@ public class User { public void setActive(boolean active) { this.active = active; } + } \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/passenger/CustomPassengerRepository.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/passenger/CustomPassengerRepository.java similarity index 77% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/passenger/CustomPassengerRepository.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/passenger/CustomPassengerRepository.java index 7ae44bfbda..7152286c83 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/passenger/CustomPassengerRepository.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/passenger/CustomPassengerRepository.java @@ -1,4 +1,4 @@ -package com.baeldung.passenger; +package com.baeldung.boot.passenger; import java.util.List; 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/boot/passenger/Passenger.java similarity index 98% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/passenger/Passenger.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/passenger/Passenger.java index a96b1edb20..c75107a783 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/boot/passenger/Passenger.java @@ -1,4 +1,4 @@ -package com.baeldung.passenger; +package com.baeldung.boot.passenger; import javax.persistence.Basic; import javax.persistence.Column; diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/passenger/PassengerRepository.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/passenger/PassengerRepository.java similarity index 75% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/passenger/PassengerRepository.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/passenger/PassengerRepository.java index 6ae6afb403..cdb8cc98fb 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/passenger/PassengerRepository.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/passenger/PassengerRepository.java @@ -1,4 +1,4 @@ -package com.baeldung.passenger; +package com.baeldung.boot.passenger; import org.springframework.data.domain.Sort; import org.springframework.data.jpa.repository.JpaRepository; @@ -9,9 +9,14 @@ interface PassengerRepository extends JpaRepository, CustomPass Passenger findFirstByOrderBySeatNumberAsc(); + Passenger findTopByOrderBySeatNumberAsc(); + List findByOrderBySeatNumberAsc(); List findByLastNameOrderBySeatNumberAsc(String lastName); List findByLastName(String lastName, Sort sort); + + List findByFirstNameIgnoreCase(String firstName); + } diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/passenger/PassengerRepositoryImpl.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/passenger/PassengerRepositoryImpl.java similarity index 93% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/passenger/PassengerRepositoryImpl.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/passenger/PassengerRepositoryImpl.java index bd6e535e3e..508c669066 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/passenger/PassengerRepositoryImpl.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/passenger/PassengerRepositoryImpl.java @@ -1,4 +1,4 @@ -package com.baeldung.passenger; +package com.baeldung.boot.passenger; import org.springframework.stereotype.Repository; diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/services/IBarService.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/services/IBarService.java new file mode 100644 index 0000000000..8054cbba59 --- /dev/null +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/services/IBarService.java @@ -0,0 +1,7 @@ +package com.baeldung.boot.services; + +import com.baeldung.boot.domain.Bar; + +public interface IBarService extends IOperations { + // +} diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/services/IFooService.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/services/IFooService.java similarity index 76% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/services/IFooService.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/services/IFooService.java index 7e16ace5b6..871cccdd45 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/services/IFooService.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/services/IFooService.java @@ -1,9 +1,10 @@ -package com.baeldung.services; +package com.baeldung.boot.services; -import com.baeldung.domain.Foo; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; +import com.baeldung.boot.domain.Foo; + public interface IFooService extends IOperations { Foo retrieveByName(String name); diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/services/IOperations.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/services/IOperations.java similarity index 92% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/services/IOperations.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/services/IOperations.java index d50d465639..ec2b866b6f 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/services/IOperations.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/services/IOperations.java @@ -1,4 +1,4 @@ -package com.baeldung.services; +package com.baeldung.boot.services; import org.springframework.data.domain.Page; diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/services/impl/AbstractService.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/services/impl/AbstractService.java similarity index 94% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/services/impl/AbstractService.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/services/impl/AbstractService.java index 708524225b..8e4f643adc 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/services/impl/AbstractService.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/services/impl/AbstractService.java @@ -1,6 +1,6 @@ -package com.baeldung.services.impl; +package com.baeldung.boot.services.impl; -import com.baeldung.services.IOperations; +import com.baeldung.boot.services.IOperations; import com.google.common.collect.Lists; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/services/impl/AbstractSpringDataJpaService.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/services/impl/AbstractSpringDataJpaService.java similarity index 92% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/services/impl/AbstractSpringDataJpaService.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/services/impl/AbstractSpringDataJpaService.java index 28c86bee28..a73a6bd7fc 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/services/impl/AbstractSpringDataJpaService.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/services/impl/AbstractSpringDataJpaService.java @@ -1,6 +1,6 @@ -package com.baeldung.services.impl; +package com.baeldung.boot.services.impl; -import com.baeldung.services.IOperations; +import com.baeldung.boot.services.IOperations; import com.google.common.collect.Lists; import org.springframework.data.repository.CrudRepository; import org.springframework.transaction.annotation.Transactional; diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/services/impl/BarSpringDataJpaService.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/services/impl/BarSpringDataJpaService.java similarity index 79% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/services/impl/BarSpringDataJpaService.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/services/impl/BarSpringDataJpaService.java index ca3e5f868d..80568f2fd4 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/services/impl/BarSpringDataJpaService.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/services/impl/BarSpringDataJpaService.java @@ -1,8 +1,9 @@ -package com.baeldung.services.impl; +package com.baeldung.boot.services.impl; + +import com.baeldung.boot.daos.IBarCrudRepository; +import com.baeldung.boot.domain.Bar; +import com.baeldung.boot.services.IBarService; -import com.baeldung.domain.Bar; -import com.baeldung.dao.repositories.IBarCrudRepository; -import com.baeldung.services.IBarService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.repository.CrudRepository; diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/services/impl/FooService.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/services/impl/FooService.java similarity index 87% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/services/impl/FooService.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/services/impl/FooService.java index 319ab3a825..04eec63854 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/services/impl/FooService.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/services/impl/FooService.java @@ -1,9 +1,10 @@ -package com.baeldung.services.impl; +package com.baeldung.boot.services.impl; import com.google.common.collect.Lists; -import com.baeldung.dao.IFooDao; -import com.baeldung.domain.Foo; -import com.baeldung.services.IFooService; +import com.baeldung.boot.daos.IFooDao; +import com.baeldung.boot.domain.Foo; +import com.baeldung.boot.services.IFooService; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/web/controllers/CustomerController.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/web/controllers/CustomerController.java new file mode 100644 index 0000000000..69a1e5507e --- /dev/null +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/boot/web/controllers/CustomerController.java @@ -0,0 +1,43 @@ +package com.baeldung.boot.web.controllers; + +import java.net.URISyntaxException; +import java.util.Arrays; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.baeldung.boot.daos.CustomerRepository; +import com.baeldung.boot.domain.Customer; + +/** + * A simple controller to test the JPA CrudRepository operations + * controllers + * + * @author ysharma2512 + * + */ +@RestController +public class CustomerController { + + @Autowired + CustomerRepository customerRepository; + + public CustomerController(CustomerRepository customerRepository2) { + this.customerRepository = customerRepository2; + } + + @PostMapping("/customers") + public ResponseEntity> insertCustomers() throws URISyntaxException { + Customer c1 = new Customer("James", "Gosling"); + Customer c2 = new Customer("Doug", "Lea"); + Customer c3 = new Customer("Martin", "Fowler"); + Customer c4 = new Customer("Brian", "Goetz"); + List customers = Arrays.asList(c1, c2, c3, c4); + customerRepository.saveAll(customers); + return ResponseEntity.ok(customers); + } + +} diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/config/PersistenceConfiguration.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/config/PersistenceConfiguration.java deleted file mode 100644 index 891624443b..0000000000 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/config/PersistenceConfiguration.java +++ /dev/null @@ -1,97 +0,0 @@ -package com.baeldung.config; - -import com.baeldung.dao.repositories.impl.ExtendedRepositoryImpl; -import com.baeldung.services.IBarService; -import com.baeldung.services.impl.BarSpringDataJpaService; -import com.google.common.base.Preconditions; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.*; -import org.springframework.core.env.Environment; -import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor; -import org.springframework.data.jpa.repository.config.EnableJpaAuditing; -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.JpaVendorAdapter; -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 javax.sql.DataSource; -import java.util.Properties; - -@Configuration -@ComponentScan({ "com.baeldung.dao", "com.baeldung.services" }) -@EnableTransactionManagement -@EnableJpaRepositories(basePackages = { "com.baeldung.dao" }, repositoryBaseClass = ExtendedRepositoryImpl.class) -@EnableJpaAuditing -@PropertySource("classpath:persistence.properties") -@Profile("!tc") -public class PersistenceConfiguration { - - @Autowired - private Environment env; - - public PersistenceConfiguration() { - super(); - } - - @Bean - public LocalContainerEntityManagerFactoryBean entityManagerFactory() { - final LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean(); - emf.setDataSource(dataSource()); - emf.setPackagesToScan("com.baeldung.domain"); - - final JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); - emf.setJpaVendorAdapter(vendorAdapter); - emf.setJpaProperties(hibernateProperties()); - - return emf; - } - - @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(); - } - - @Bean - public IBarService barSpringDataJpaService() { - return new BarSpringDataJpaService(); - } - - private final Properties hibernateProperties() { - 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.show_sql", "true"); - // hibernateProperties.setProperty("hibernate.format_sql", "true"); - // hibernateProperties.setProperty("hibernate.globally_quoted_identifiers", "true"); - - // Envers properties - hibernateProperties.setProperty("org.hibernate.envers.audit_table_suffix", - env.getProperty("envers.audit_table_suffix")); - - return hibernateProperties; - } - -} \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/product/ProductRepository.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/product/ProductRepository.java deleted file mode 100755 index 1f9f5f9195..0000000000 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/product/ProductRepository.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.baeldung.dao.repositories.product; - -import com.baeldung.domain.product.Product; - -import java.util.List; - -import org.springframework.data.domain.Pageable; -import org.springframework.data.repository.PagingAndSortingRepository; - -public interface ProductRepository extends PagingAndSortingRepository { - - List findAllByPrice(double price, Pageable pageable); -} diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/ddd/event/DomainEvent.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/ddd/event/DomainEvent.java deleted file mode 100644 index 1e6479d4fc..0000000000 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/ddd/event/DomainEvent.java +++ /dev/null @@ -1,8 +0,0 @@ -/** - * - */ -package com.baeldung.ddd.event; - -class DomainEvent { - -} diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/multipledb/MultipleDbApplication.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/multipledb/MultipleDbApplication.java new file mode 100644 index 0000000000..8ff6799e31 --- /dev/null +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/multipledb/MultipleDbApplication.java @@ -0,0 +1,14 @@ +package com.baeldung.multipledb; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class MultipleDbApplication { + + public static void main(String[] args) { + SpringApplication.run(MultipleDbApplication.class, args); + } + +} + diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/config/PersistenceProductConfiguration.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/multipledb/PersistenceProductConfiguration.java similarity index 90% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/config/PersistenceProductConfiguration.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/multipledb/PersistenceProductConfiguration.java index ecaee82ae5..bcf2cd84eb 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/config/PersistenceProductConfiguration.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/multipledb/PersistenceProductConfiguration.java @@ -1,4 +1,4 @@ -package com.baeldung.config; +package com.baeldung.multipledb; import com.google.common.base.Preconditions; import org.springframework.beans.factory.annotation.Autowired; @@ -19,7 +19,7 @@ import java.util.HashMap; @Configuration @PropertySource({"classpath:persistence-multiple-db.properties"}) -@EnableJpaRepositories(basePackages = "com.baeldung.dao.repositories.product", entityManagerFactoryRef = "productEntityManager", transactionManagerRef = "productTransactionManager") +@EnableJpaRepositories(basePackages = "com.baeldung.multipledb.dao.product", entityManagerFactoryRef = "productEntityManager", transactionManagerRef = "productTransactionManager") @Profile("!tc") public class PersistenceProductConfiguration { @Autowired @@ -35,7 +35,7 @@ public class PersistenceProductConfiguration { public LocalContainerEntityManagerFactoryBean productEntityManager() { final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); em.setDataSource(productDataSource()); - em.setPackagesToScan("com.baeldung.domain.product"); + em.setPackagesToScan("com.baeldung.multipledb.model.product"); final HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); em.setJpaVendorAdapter(vendorAdapter); diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/config/PersistenceUserConfiguration.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/multipledb/PersistenceUserConfiguration.java similarity index 88% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/config/PersistenceUserConfiguration.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/multipledb/PersistenceUserConfiguration.java index 6893d889e6..6b48455c0c 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/config/PersistenceUserConfiguration.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/multipledb/PersistenceUserConfiguration.java @@ -1,4 +1,4 @@ -package com.baeldung.config; +package com.baeldung.multipledb; import com.google.common.base.Preconditions; import org.springframework.beans.factory.annotation.Autowired; @@ -16,7 +16,7 @@ import java.util.HashMap; @Configuration @PropertySource({"classpath:persistence-multiple-db.properties"}) -@EnableJpaRepositories(basePackages = "com.baeldung.dao.repositories.user", entityManagerFactoryRef = "userEntityManager", transactionManagerRef = "userTransactionManager") +@EnableJpaRepositories(basePackages = "com.baeldung.multipledb.dao.user", entityManagerFactoryRef = "userEntityManager", transactionManagerRef = "userTransactionManager") @Profile("!tc") public class PersistenceUserConfiguration { @Autowired @@ -31,9 +31,10 @@ public class PersistenceUserConfiguration { @Primary @Bean public LocalContainerEntityManagerFactoryBean userEntityManager() { + System.out.println("loading config"); final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); em.setDataSource(userDataSource()); - em.setPackagesToScan("com.baeldung.domain.user"); + em.setPackagesToScan("com.baeldung.multipledb.model.user"); final HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); em.setJpaVendorAdapter(vendorAdapter); diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/multipledb/dao/product/ProductRepository.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/multipledb/dao/product/ProductRepository.java new file mode 100755 index 0000000000..022099eed0 --- /dev/null +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/multipledb/dao/product/ProductRepository.java @@ -0,0 +1,13 @@ +package com.baeldung.multipledb.dao.product; + +import java.util.List; + +import org.springframework.data.domain.Pageable; +import org.springframework.data.repository.PagingAndSortingRepository; + +import com.baeldung.multipledb.model.product.ProductMultipleDB; + +public interface ProductRepository extends PagingAndSortingRepository { + + List findAllByPrice(double price, Pageable pageable); +} diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/multipledb/dao/user/PossessionRepository.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/multipledb/dao/user/PossessionRepository.java new file mode 100644 index 0000000000..ae37fde20d --- /dev/null +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/multipledb/dao/user/PossessionRepository.java @@ -0,0 +1,9 @@ +package com.baeldung.multipledb.dao.user; + +import org.springframework.data.jpa.repository.JpaRepository; + +import com.baeldung.multipledb.model.user.PossessionMultipleDB; + +public interface PossessionRepository extends JpaRepository { + +} diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/multipledb/dao/user/UserRepository.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/multipledb/dao/user/UserRepository.java new file mode 100644 index 0000000000..267a61a93f --- /dev/null +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/multipledb/dao/user/UserRepository.java @@ -0,0 +1,8 @@ +package com.baeldung.multipledb.dao.user; + +import org.springframework.data.jpa.repository.JpaRepository; + +import com.baeldung.multipledb.model.user.UserMultipleDB; + +public interface UserRepository extends JpaRepository { +} \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/domain/product/Product.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/multipledb/model/product/ProductMultipleDB.java similarity index 76% rename from persistence-modules/spring-data-jpa/src/main/java/com/baeldung/domain/product/Product.java rename to persistence-modules/spring-data-jpa/src/main/java/com/baeldung/multipledb/model/product/ProductMultipleDB.java index 2f82e3e318..8bdff340ac 100755 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/domain/product/Product.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/multipledb/model/product/ProductMultipleDB.java @@ -1,4 +1,4 @@ -package com.baeldung.domain.product; +package com.baeldung.multipledb.model.product; import javax.persistence.Entity; import javax.persistence.Id; @@ -6,7 +6,7 @@ import javax.persistence.Table; @Entity @Table(schema = "products") -public class Product { +public class ProductMultipleDB { @Id private int id; @@ -15,19 +15,19 @@ public class Product { private double price; - public Product() { + public ProductMultipleDB() { super(); } - private Product(int id, String name, double price) { + private ProductMultipleDB(int id, String name, double price) { super(); this.id = id; this.name = name; this.price = price; } - public static Product from(int id, String name, double price) { - return new Product(id, name, price); + public static ProductMultipleDB from(int id, String name, double price) { + return new ProductMultipleDB(id, name, price); } public int getId() { diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/multipledb/model/user/PossessionMultipleDB.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/multipledb/model/user/PossessionMultipleDB.java new file mode 100644 index 0000000000..a6a3c88bd0 --- /dev/null +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/multipledb/model/user/PossessionMultipleDB.java @@ -0,0 +1,82 @@ +package com.baeldung.multipledb.model.user; + +import javax.persistence.*; + +@Entity +@Table +public class PossessionMultipleDB { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + + private String name; + + public PossessionMultipleDB() { + super(); + } + + public PossessionMultipleDB(final String name) { + super(); + + this.name = name; + } + + public long getId() { + return id; + } + + public void setId(final int 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) + (int) (id ^ (id >>> 32)); + result = (prime * result) + ((name == null) ? 0 : name.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final PossessionMultipleDB other = (PossessionMultipleDB) obj; + if (id != other.id) { + return false; + } + 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("Possesion [id=").append(id).append(", name=").append(name).append("]"); + return builder.toString(); + } + +} diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/multipledb/model/user/UserMultipleDB.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/multipledb/model/user/UserMultipleDB.java new file mode 100644 index 0000000000..c7cd07f7a1 --- /dev/null +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/multipledb/model/user/UserMultipleDB.java @@ -0,0 +1,88 @@ +package com.baeldung.multipledb.model.user; + +import javax.persistence.*; + +import java.util.List; + +@Entity +@Table(name = "users") +public class UserMultipleDB { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private int id; + private String name; + private int age; + @Column(unique = true, nullable = false) + private String email; + private Integer status; + + @OneToMany + List possessionList; + + public UserMultipleDB() { + super(); + } + + public UserMultipleDB(String name, String email, Integer status) { + this.name = name; + this.email = email; + this.status = status; + } + + public int getId() { + return id; + } + + public void setId(final int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(final String name) { + this.name = name; + } + + public String getEmail() { + return email; + } + + public void setEmail(final String email) { + this.email = email; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public int getAge() { + return age; + } + + public void setAge(final int age) { + this.age = age; + } + + public List getPossessionList() { + return possessionList; + } + + public void setPossessionList(List possessionList) { + this.possessionList = possessionList; + } + + @Override + public String toString() { + final StringBuilder builder = new StringBuilder(); + builder.append("User [name=").append(name).append(", id=").append(id).append("]"); + return builder.toString(); + } + +} \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/services/IBarService.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/services/IBarService.java deleted file mode 100644 index 7e127488db..0000000000 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/services/IBarService.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.baeldung.services; - -import com.baeldung.domain.Bar; - -public interface IBarService extends IOperations { - // -} diff --git a/persistence-modules/spring-data-jpa/src/main/resources/application.properties b/persistence-modules/spring-data-jpa/src/main/resources/application.properties index 37fb9ca9c4..f127dd5e50 100644 --- a/persistence-modules/spring-data-jpa/src/main/resources/application.properties +++ b/persistence-modules/spring-data-jpa/src/main/resources/application.properties @@ -1,17 +1,6 @@ -# spring.datasource.x -spring.datasource.driver-class-name=org.h2.Driver -spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1 -spring.datasource.username=sa -spring.datasource.password=sa +spring.main.allow-bean-definition-overriding=true -# hibernate.X -hibernate.dialect=org.hibernate.dialect.H2Dialect -hibernate.show_sql=true -hibernate.hbm2ddl.auto=create-drop -hibernate.cache.use_second_level_cache=true -hibernate.cache.use_query_cache=true -hibernate.cache.region.factory_class=org.hibernate.cache.ehcache.EhCacheRegionFactory - -spring.datasource.data=import_entities.sql - -spring.main.allow-bean-definition-overriding=true \ No newline at end of file +spring.jpa.properties.hibernate.jdbc.batch_size=4 +spring.jpa.properties.hibernate.order_inserts=true +spring.jpa.properties.hibernate.order_updates=true +spring.jpa.properties.hibernate.generate_statistics=true diff --git a/persistence-modules/spring-data-jpa/src/main/resources/persistence.properties b/persistence-modules/spring-data-jpa/src/main/resources/persistence.properties index 3543e1b52b..6bc83edf34 100644 --- a/persistence-modules/spring-data-jpa/src/main/resources/persistence.properties +++ b/persistence-modules/spring-data-jpa/src/main/resources/persistence.properties @@ -12,5 +12,3 @@ hibernate.cache.use_second_level_cache=true hibernate.cache.use_query_cache=true hibernate.cache.region.factory_class=org.hibernate.cache.ehcache.EhCacheRegionFactory -# envers.X -envers.audit_table_suffix=_audit_log \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/batchinserts/BatchInsertIntegrationTest.java b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/batchinserts/BatchInsertIntegrationTest.java new file mode 100644 index 0000000000..7ddf36d3f0 --- /dev/null +++ b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/batchinserts/BatchInsertIntegrationTest.java @@ -0,0 +1,40 @@ +package com.baeldung.batchinserts; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import org.junit.Before; +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.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + +import com.baeldung.boot.Application; +import com.baeldung.boot.daos.CustomerRepository; +import com.baeldung.boot.web.controllers.CustomerController; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes=Application.class) +@AutoConfigureMockMvc +public class BatchInsertIntegrationTest { + + @Autowired + private CustomerRepository customerRepository; + private MockMvc mockMvc; + @Before + public void setUp() throws Exception { + mockMvc = MockMvcBuilders.standaloneSetup( new CustomerController(customerRepository)) + .build(); + } + + @Test + public void whenInsertingCustomers_thenCustomersAreCreated() throws Exception { + this.mockMvc.perform(post("/customers")) + .andExpect(status().isOk()); + } + +} \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/ArticleRepositoryIntegrationTest.java b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/boot/daos/ArticleRepositoryIntegrationTest.java similarity index 82% rename from persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/ArticleRepositoryIntegrationTest.java rename to persistence-modules/spring-data-jpa/src/test/java/com/baeldung/boot/daos/ArticleRepositoryIntegrationTest.java index 093e744003..dfb04b3dfb 100644 --- a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/ArticleRepositoryIntegrationTest.java +++ b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/boot/daos/ArticleRepositoryIntegrationTest.java @@ -1,13 +1,16 @@ -package com.baeldung.dao.repositories; +package com.baeldung.boot.daos; + +import com.baeldung.boot.Application; +import com.baeldung.boot.config.PersistenceConfiguration; +import com.baeldung.boot.daos.ArticleRepository; +import com.baeldung.boot.domain.Article; -import com.baeldung.config.PersistenceConfiguration; -import com.baeldung.config.PersistenceProductConfiguration; -import com.baeldung.config.PersistenceUserConfiguration; -import com.baeldung.domain.Article; 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.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Import; import org.springframework.test.context.junit4.SpringRunner; import java.text.SimpleDateFormat; @@ -18,7 +21,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @RunWith(SpringRunner.class) -@DataJpaTest(excludeAutoConfiguration = {PersistenceConfiguration.class, PersistenceUserConfiguration.class, PersistenceProductConfiguration.class}) +@DataJpaTest(properties="spring.datasource.data=classpath:import_entities.sql") public class ArticleRepositoryIntegrationTest { @Autowired diff --git a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/ExtendedStudentRepositoryIntegrationTest.java b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/boot/daos/ExtendedStudentRepositoryIntegrationTest.java similarity index 80% rename from persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/ExtendedStudentRepositoryIntegrationTest.java rename to persistence-modules/spring-data-jpa/src/test/java/com/baeldung/boot/daos/ExtendedStudentRepositoryIntegrationTest.java index b19a34df82..66de5911db 100644 --- a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/ExtendedStudentRepositoryIntegrationTest.java +++ b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/boot/daos/ExtendedStudentRepositoryIntegrationTest.java @@ -1,7 +1,10 @@ -package com.baeldung.dao.repositories; +package com.baeldung.boot.daos; + +import com.baeldung.boot.Application; +import com.baeldung.boot.config.PersistenceConfiguration; +import com.baeldung.boot.daos.ExtendedStudentRepository; +import com.baeldung.boot.domain.Student; -import com.baeldung.config.PersistenceConfiguration; -import com.baeldung.domain.Student; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -15,7 +18,7 @@ import java.util.List; import static org.assertj.core.api.Assertions.assertThat; @RunWith(SpringRunner.class) -@ContextConfiguration(classes = {PersistenceConfiguration.class}) +@ContextConfiguration(classes = {Application.class}) @DirtiesContext public class ExtendedStudentRepositoryIntegrationTest { @Resource diff --git a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/InventoryRepositoryIntegrationTest.java b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/boot/daos/InventoryRepositoryIntegrationTest.java similarity index 85% rename from persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/InventoryRepositoryIntegrationTest.java rename to persistence-modules/spring-data-jpa/src/test/java/com/baeldung/boot/daos/InventoryRepositoryIntegrationTest.java index 9d6334445c..877e59d5a2 100644 --- a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/InventoryRepositoryIntegrationTest.java +++ b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/boot/daos/InventoryRepositoryIntegrationTest.java @@ -1,11 +1,15 @@ -package com.baeldung.dao.repositories; +package com.baeldung.boot.daos; + +import com.baeldung.boot.Application; +import com.baeldung.boot.config.PersistenceConfiguration; +import com.baeldung.boot.daos.InventoryRepository; +import com.baeldung.boot.domain.MerchandiseEntity; -import com.baeldung.config.PersistenceConfiguration; -import com.baeldung.domain.MerchandiseEntity; 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.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import java.math.BigDecimal; @@ -15,7 +19,7 @@ import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; @RunWith(SpringRunner.class) -@DataJpaTest(excludeAutoConfiguration = {PersistenceConfiguration.class}) +@SpringBootTest(classes=Application.class) public class InventoryRepositoryIntegrationTest { private static final String ORIGINAL_TITLE = "Pair of Pants"; diff --git a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/JpaRepositoriesIntegrationTest.java b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/boot/daos/JpaRepositoriesIntegrationTest.java similarity index 80% rename from persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/JpaRepositoriesIntegrationTest.java rename to persistence-modules/spring-data-jpa/src/test/java/com/baeldung/boot/daos/JpaRepositoriesIntegrationTest.java index 01405c0b8a..30925d9b68 100644 --- a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/JpaRepositoriesIntegrationTest.java +++ b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/boot/daos/JpaRepositoriesIntegrationTest.java @@ -1,4 +1,4 @@ -package com.baeldung.dao.repositories; +package com.baeldung.boot.daos; import static junit.framework.TestCase.assertEquals; import static junit.framework.TestCase.assertFalse; @@ -13,18 +13,24 @@ 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.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; -import com.baeldung.config.PersistenceConfiguration; -import com.baeldung.config.PersistenceProductConfiguration; -import com.baeldung.config.PersistenceUserConfiguration; -import com.baeldung.domain.Item; -import com.baeldung.domain.ItemType; -import com.baeldung.domain.Location; -import com.baeldung.domain.Store; +import com.baeldung.boot.Application; +import com.baeldung.boot.config.PersistenceConfiguration; +import com.baeldung.boot.daos.ItemTypeRepository; +import com.baeldung.boot.daos.LocationRepository; +import com.baeldung.boot.daos.ReadOnlyLocationRepository; +import com.baeldung.boot.daos.StoreRepository; +import com.baeldung.boot.domain.Item; +import com.baeldung.boot.domain.ItemType; +import com.baeldung.boot.domain.Location; +import com.baeldung.boot.domain.Store; +import com.baeldung.multipledb.PersistenceProductConfiguration; +import com.baeldung.multipledb.PersistenceUserConfiguration; @RunWith(SpringRunner.class) -@DataJpaTest(excludeAutoConfiguration = { PersistenceConfiguration.class, PersistenceUserConfiguration.class, PersistenceProductConfiguration.class }) +@DataJpaTest(properties="spring.datasource.data=classpath:import_entities.sql") public class JpaRepositoriesIntegrationTest { @Autowired private LocationRepository locationRepository; diff --git a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/PersonInsertRepositoryIntegrationTest.java b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/boot/daos/PersonInsertRepositoryIntegrationTest.java similarity index 94% rename from persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/PersonInsertRepositoryIntegrationTest.java rename to persistence-modules/spring-data-jpa/src/test/java/com/baeldung/boot/daos/PersonInsertRepositoryIntegrationTest.java index b248cf8bf1..9d45c17035 100644 --- a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/PersonInsertRepositoryIntegrationTest.java +++ b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/boot/daos/PersonInsertRepositoryIntegrationTest.java @@ -1,7 +1,8 @@ -package com.baeldung.dao.repositories; +package com.baeldung.boot.daos; + +import com.baeldung.boot.daos.impl.PersonInsertRepository; +import com.baeldung.boot.domain.Person; -import com.baeldung.dao.repositories.impl.PersonInsertRepository; -import com.baeldung.domain.Person; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; diff --git a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/UserRepositoryCommon.java b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/boot/daos/UserRepositoryCommon.java similarity index 99% rename from persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/UserRepositoryCommon.java rename to persistence-modules/spring-data-jpa/src/test/java/com/baeldung/boot/daos/UserRepositoryCommon.java index abd758cec2..4aeeaf5209 100644 --- a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/UserRepositoryCommon.java +++ b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/boot/daos/UserRepositoryCommon.java @@ -1,7 +1,5 @@ -package com.baeldung.dao.repositories; +package com.baeldung.boot.daos; -import com.baeldung.dao.repositories.user.UserRepository; -import com.baeldung.domain.user.User; import org.junit.After; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -12,6 +10,9 @@ import org.springframework.data.jpa.domain.JpaSort; import org.springframework.data.mapping.PropertyReferenceException; import org.springframework.transaction.annotation.Transactional; +import com.baeldung.boot.daos.user.UserRepository; +import com.baeldung.boot.domain.User; + import javax.persistence.EntityManager; import javax.persistence.Query; import java.time.LocalDate; diff --git a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/UserRepositoryIntegrationTest.java b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/boot/daos/UserRepositoryIntegrationTest.java similarity index 86% rename from persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/UserRepositoryIntegrationTest.java rename to persistence-modules/spring-data-jpa/src/test/java/com/baeldung/boot/daos/UserRepositoryIntegrationTest.java index 09f937c8f2..1b1d264574 100644 --- a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/UserRepositoryIntegrationTest.java +++ b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/boot/daos/UserRepositoryIntegrationTest.java @@ -1,7 +1,7 @@ -package com.baeldung.dao.repositories; +package com.baeldung.boot.daos; -import com.baeldung.config.PersistenceConfiguration; -import com.baeldung.domain.user.User; +import com.baeldung.boot.Application; +import com.baeldung.boot.domain.User; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; @@ -17,7 +17,7 @@ import static org.assertj.core.api.Assertions.assertThat; * Created by adam. */ @RunWith(SpringRunner.class) -@SpringBootTest(classes = PersistenceConfiguration.class) +@SpringBootTest(classes = Application.class) @DirtiesContext public class UserRepositoryIntegrationTest extends UserRepositoryCommon { diff --git a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/UserRepositoryTCAutoIntegrationTest.java b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/boot/daos/UserRepositoryTCAutoIntegrationTest.java similarity index 91% rename from persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/UserRepositoryTCAutoIntegrationTest.java rename to persistence-modules/spring-data-jpa/src/test/java/com/baeldung/boot/daos/UserRepositoryTCAutoIntegrationTest.java index 6a851823e3..2f3e9c9032 100644 --- a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/UserRepositoryTCAutoIntegrationTest.java +++ b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/boot/daos/UserRepositoryTCAutoIntegrationTest.java @@ -1,6 +1,7 @@ -package com.baeldung.dao.repositories; +package com.baeldung.boot.daos; -import com.baeldung.domain.user.User; +import com.baeldung.boot.Application; +import com.baeldung.boot.domain.User; import com.baeldung.util.BaeldungPostgresqlContainer; import org.junit.ClassRule; import org.junit.Test; @@ -19,7 +20,7 @@ import static org.assertj.core.api.Assertions.assertThat; * Created by adam. */ @RunWith(SpringRunner.class) -@SpringBootTest +@SpringBootTest(classes = Application.class) @ActiveProfiles({"tc", "tc-auto"}) public class UserRepositoryTCAutoIntegrationTest extends UserRepositoryCommon { diff --git a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/UserRepositoryTCIntegrationTest.java b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/boot/daos/UserRepositoryTCIntegrationTest.java similarity index 94% rename from persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/UserRepositoryTCIntegrationTest.java rename to persistence-modules/spring-data-jpa/src/test/java/com/baeldung/boot/daos/UserRepositoryTCIntegrationTest.java index c300a07ab9..afdf60cc81 100644 --- a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/UserRepositoryTCIntegrationTest.java +++ b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/boot/daos/UserRepositoryTCIntegrationTest.java @@ -1,6 +1,7 @@ -package com.baeldung.dao.repositories; +package com.baeldung.boot.daos; -import com.baeldung.domain.user.User; +import com.baeldung.boot.Application; +import com.baeldung.boot.domain.User; import org.junit.ClassRule; import org.junit.Test; import org.junit.runner.RunWith; @@ -19,7 +20,7 @@ import java.time.LocalDate; import static org.assertj.core.api.Assertions.assertThat; @RunWith(SpringRunner.class) -@SpringBootTest +@SpringBootTest(classes = Application.class) @ActiveProfiles("tc") @ContextConfiguration(initializers = {UserRepositoryTCIntegrationTest.Initializer.class}) public class UserRepositoryTCIntegrationTest extends UserRepositoryCommon { diff --git a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/ddd/event/Aggregate2EventsIntegrationTest.java b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/boot/ddd/event/Aggregate2EventsIntegrationTest.java similarity index 90% rename from persistence-modules/spring-data-jpa/src/test/java/com/baeldung/ddd/event/Aggregate2EventsIntegrationTest.java rename to persistence-modules/spring-data-jpa/src/test/java/com/baeldung/boot/ddd/event/Aggregate2EventsIntegrationTest.java index 3f650d4d63..e76b932cb9 100644 --- a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/ddd/event/Aggregate2EventsIntegrationTest.java +++ b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/boot/ddd/event/Aggregate2EventsIntegrationTest.java @@ -1,7 +1,7 @@ /** * */ -package com.baeldung.ddd.event; +package com.baeldung.boot.ddd.event; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.times; @@ -15,6 +15,10 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; +import com.baeldung.boot.ddd.event.Aggregate2; +import com.baeldung.boot.ddd.event.Aggregate2Repository; +import com.baeldung.boot.ddd.event.DomainEvent; + @SpringJUnitConfig @SpringBootTest class Aggregate2EventsIntegrationTest { diff --git a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/ddd/event/Aggregate3EventsIntegrationTest.java b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/boot/ddd/event/Aggregate3EventsIntegrationTest.java similarity index 90% rename from persistence-modules/spring-data-jpa/src/test/java/com/baeldung/ddd/event/Aggregate3EventsIntegrationTest.java rename to persistence-modules/spring-data-jpa/src/test/java/com/baeldung/boot/ddd/event/Aggregate3EventsIntegrationTest.java index 893dcac3f8..4193e932ee 100644 --- a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/ddd/event/Aggregate3EventsIntegrationTest.java +++ b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/boot/ddd/event/Aggregate3EventsIntegrationTest.java @@ -1,7 +1,7 @@ /** * */ -package com.baeldung.ddd.event; +package com.baeldung.boot.ddd.event; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.times; @@ -14,6 +14,10 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; +import com.baeldung.boot.ddd.event.Aggregate3; +import com.baeldung.boot.ddd.event.Aggregate3Repository; +import com.baeldung.boot.ddd.event.DomainEvent; + @SpringJUnitConfig @SpringBootTest class Aggregate3EventsIntegrationTest { diff --git a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/ddd/event/AggregateEventsIntegrationTest.java b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/boot/ddd/event/AggregateEventsIntegrationTest.java similarity index 91% rename from persistence-modules/spring-data-jpa/src/test/java/com/baeldung/ddd/event/AggregateEventsIntegrationTest.java rename to persistence-modules/spring-data-jpa/src/test/java/com/baeldung/boot/ddd/event/AggregateEventsIntegrationTest.java index f0e1147245..ac607063b2 100644 --- a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/ddd/event/AggregateEventsIntegrationTest.java +++ b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/boot/ddd/event/AggregateEventsIntegrationTest.java @@ -1,4 +1,4 @@ -package com.baeldung.ddd.event; +package com.baeldung.boot.ddd.event; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.times; @@ -16,6 +16,11 @@ import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.annotation.Bean; import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; +import com.baeldung.boot.ddd.event.Aggregate; +import com.baeldung.boot.ddd.event.AggregateRepository; +import com.baeldung.boot.ddd.event.DomainEvent; +import com.baeldung.boot.ddd.event.DomainService; + @SpringJUnitConfig @SpringBootTest class AggregateEventsIntegrationTest { diff --git a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/ddd/event/TestEventHandler.java b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/boot/ddd/event/TestEventHandler.java similarity index 68% rename from persistence-modules/spring-data-jpa/src/test/java/com/baeldung/ddd/event/TestEventHandler.java rename to persistence-modules/spring-data-jpa/src/test/java/com/baeldung/boot/ddd/event/TestEventHandler.java index 721402c17a..0f499834eb 100644 --- a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/ddd/event/TestEventHandler.java +++ b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/boot/ddd/event/TestEventHandler.java @@ -1,10 +1,12 @@ /** * */ -package com.baeldung.ddd.event; +package com.baeldung.boot.ddd.event; import org.springframework.transaction.event.TransactionalEventListener; +import com.baeldung.boot.ddd.event.DomainEvent; + interface TestEventHandler { @TransactionalEventListener void handleEvent(DomainEvent event); 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/boot/passenger/PassengerRepositoryIntegrationTest.java similarity index 86% rename from persistence-modules/spring-data-jpa/src/test/java/com/baeldung/passenger/PassengerRepositoryIntegrationTest.java rename to persistence-modules/spring-data-jpa/src/test/java/com/baeldung/boot/passenger/PassengerRepositoryIntegrationTest.java index 8cd19cec03..f082350019 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/boot/passenger/PassengerRepositoryIntegrationTest.java @@ -1,16 +1,4 @@ -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; +package com.baeldung.boot.passenger; import org.junit.Before; import org.junit.Test; @@ -24,6 +12,21 @@ import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Sort; import org.springframework.test.context.junit4.SpringRunner; +import com.baeldung.boot.passenger.Passenger; +import com.baeldung.boot.passenger.PassengerRepository; + +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.hamcrest.core.IsNot.not; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + + @DataJpaTest @RunWith(SpringRunner.class) public class PassengerRepositoryIntegrationTest { @@ -152,18 +155,36 @@ public class PassengerRepositoryIntegrationTest { 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"); - + ExampleMatcher.GenericPropertyMatchers.startsWith().ignoreCase()).withIgnorePaths("firstName", "seatNumber"); + Example example = Example.of(Passenger.from(null, "b", null), - ignoringExampleMatcher); - + 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))); } + + @Test + public void givenPassengers_whenMatchingIgnoreCase_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); + + List passengers = repository.findByFirstNameIgnoreCase("FRED"); + + assertThat(passengers, contains(fred)); + assertThat(passengers, not(contains(eve))); + assertThat(passengers, not(contains(siya))); + assertThat(passengers, not(contains(jill))); + assertThat(passengers, not(contains(ricki))); + + } } diff --git a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/services/AbstractServicePersistenceIntegrationTest.java b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/boot/services/AbstractServicePersistenceIntegrationTest.java similarity index 98% rename from persistence-modules/spring-data-jpa/src/test/java/com/baeldung/services/AbstractServicePersistenceIntegrationTest.java rename to persistence-modules/spring-data-jpa/src/test/java/com/baeldung/boot/services/AbstractServicePersistenceIntegrationTest.java index acac66f2f7..bf0c85fca6 100644 --- a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/services/AbstractServicePersistenceIntegrationTest.java +++ b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/boot/services/AbstractServicePersistenceIntegrationTest.java @@ -1,6 +1,7 @@ -package com.baeldung.services; +package com.baeldung.boot.services; -import com.baeldung.domain.Foo; +import com.baeldung.boot.domain.Foo; +import com.baeldung.boot.services.IOperations; import com.baeldung.util.IDUtil; import org.hamcrest.Matchers; import org.junit.Ignore; diff --git a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/services/FooServicePersistenceIntegrationTest.java b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/boot/services/FooServicePersistenceIntegrationTest.java similarity index 85% rename from persistence-modules/spring-data-jpa/src/test/java/com/baeldung/services/FooServicePersistenceIntegrationTest.java rename to persistence-modules/spring-data-jpa/src/test/java/com/baeldung/boot/services/FooServicePersistenceIntegrationTest.java index fd17d033e1..f0e4aa7317 100644 --- a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/services/FooServicePersistenceIntegrationTest.java +++ b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/boot/services/FooServicePersistenceIntegrationTest.java @@ -1,11 +1,16 @@ -package com.baeldung.services; +package com.baeldung.boot.services; + +import com.baeldung.boot.Application; +import com.baeldung.boot.config.PersistenceConfiguration; +import com.baeldung.boot.domain.Foo; +import com.baeldung.boot.services.IFooService; +import com.baeldung.boot.services.IOperations; -import com.baeldung.config.PersistenceConfiguration; -import com.baeldung.domain.Foo; import org.junit.Ignore; 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.dao.DataIntegrityViolationException; import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.test.context.ContextConfiguration; @@ -16,7 +21,7 @@ import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic; import static org.junit.Assert.assertNotNull; @RunWith(SpringRunner.class) -@ContextConfiguration(classes = {PersistenceConfiguration.class}, loader = AnnotationConfigContextLoader.class) +@SpringBootTest(classes=Application.class) public class FooServicePersistenceIntegrationTest extends AbstractServicePersistenceIntegrationTest { @Autowired diff --git a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/services/SpringDataJPABarAuditIntegrationTest.java b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/boot/services/SpringDataJPABarAuditIntegrationTest.java similarity index 87% rename from persistence-modules/spring-data-jpa/src/test/java/com/baeldung/services/SpringDataJPABarAuditIntegrationTest.java rename to persistence-modules/spring-data-jpa/src/test/java/com/baeldung/boot/services/SpringDataJPABarAuditIntegrationTest.java index f3b857c73d..810cf70769 100644 --- a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/services/SpringDataJPABarAuditIntegrationTest.java +++ b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/boot/services/SpringDataJPABarAuditIntegrationTest.java @@ -1,4 +1,4 @@ -package com.baeldung.services; +package com.baeldung.boot.services; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -16,16 +16,19 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.test.context.SpringBootTest; import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.context.support.AnnotationConfigContextLoader; -import com.baeldung.config.PersistenceConfiguration; -import com.baeldung.domain.Bar; +import com.baeldung.boot.Application; +import com.baeldung.boot.config.PersistenceConfiguration; +import com.baeldung.boot.domain.Bar; +import com.baeldung.boot.services.IBarService; @RunWith(SpringRunner.class) -@ContextConfiguration(classes = { PersistenceConfiguration.class }, loader = AnnotationConfigContextLoader.class) +@SpringBootTest(classes=Application.class) public class SpringDataJPABarAuditIntegrationTest { private static Logger logger = LoggerFactory.getLogger(SpringDataJPABarAuditIntegrationTest.class); diff --git a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/impl/CustomItemRepositoryIntegrationTest.java b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/impl/CustomItemRepositoryIntegrationTest.java deleted file mode 100644 index c5fb7fa25f..0000000000 --- a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/impl/CustomItemRepositoryIntegrationTest.java +++ /dev/null @@ -1,94 +0,0 @@ -package com.baeldung.dao.repositories.impl; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; - -import java.util.List; - -import javax.persistence.EntityManager; - -import org.junit.Before; -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.test.context.junit4.SpringRunner; -import org.springframework.util.CollectionUtils; - -import com.baeldung.config.PersistenceConfiguration; -import com.baeldung.config.PersistenceProductConfiguration; -import com.baeldung.config.PersistenceUserConfiguration; -import com.baeldung.dao.repositories.CustomItemRepository; -import com.baeldung.domain.Item; - -@RunWith(SpringRunner.class) -@DataJpaTest(excludeAutoConfiguration = { PersistenceConfiguration.class, PersistenceUserConfiguration.class, PersistenceProductConfiguration.class }) -public class CustomItemRepositoryIntegrationTest { - - @Autowired - CustomItemRepository customItemRepositoryImpl; - - @Autowired - EntityManager entityManager; - - @Before - public void setUp() { - - Item firstItem = new Item(); - firstItem.setColor("blue"); - firstItem.setGrade("C"); - firstItem.setId(10l); - - entityManager.persist(firstItem); - - Item secondItem = new Item(); - secondItem.setColor("red"); - secondItem.setGrade("C"); - secondItem.setId(11l); - - entityManager.persist(secondItem); - - Item thirdItem = new Item(); - thirdItem.setColor("blue"); - thirdItem.setGrade("A"); - thirdItem.setId(12l); - - entityManager.persist(thirdItem); - - Item fourthItem = new Item(); - fourthItem.setColor("red"); - fourthItem.setGrade("D"); - fourthItem.setId(13l); - - entityManager.persist(fourthItem); - } - - @Test - public void givenItems_whenFindItemsByColorAndGrade_thenReturnItems() { - - List items = customItemRepositoryImpl.findItemsByColorAndGrade(); - - assertFalse("No items found", CollectionUtils.isEmpty(items)); - assertEquals("There should be only one item", 1, items.size()); - - Item item = items.get(0); - - assertEquals("this item do not have blue color", "blue", item.getColor()); - assertEquals("this item does not belong to A grade", "A", item.getGrade()); - } - - @Test - public void givenItems_whenFindItemByColorOrGrade_thenReturnItems() { - - List items = customItemRepositoryImpl.findItemByColorOrGrade(); - - assertFalse("No items found", CollectionUtils.isEmpty(items)); - assertEquals("There should be only one item", 1, items.size()); - - Item item = items.get(0); - - assertEquals("this item do not have red color", "red", item.getColor()); - assertEquals("this item does not belong to D grade", "D", item.getGrade()); - } - -} diff --git a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/services/JpaMultipleDBIntegrationTest.java b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/multipledb/JpaMultipleDBIntegrationTest.java similarity index 74% rename from persistence-modules/spring-data-jpa/src/test/java/com/baeldung/services/JpaMultipleDBIntegrationTest.java rename to persistence-modules/spring-data-jpa/src/test/java/com/baeldung/multipledb/JpaMultipleDBIntegrationTest.java index 71a3fb0b44..bcc4103d08 100644 --- a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/services/JpaMultipleDBIntegrationTest.java +++ b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/multipledb/JpaMultipleDBIntegrationTest.java @@ -1,4 +1,4 @@ -package com.baeldung.services; +package com.baeldung.multipledb; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -10,26 +10,23 @@ import java.util.Optional; 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.dao.DataIntegrityViolationException; import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.transaction.annotation.EnableTransactionManagement; import org.springframework.transaction.annotation.Transactional; -import com.baeldung.config.PersistenceProductConfiguration; -import com.baeldung.config.PersistenceUserConfiguration; -import com.baeldung.dao.repositories.product.ProductRepository; -import com.baeldung.dao.repositories.user.PossessionRepository; -import com.baeldung.dao.repositories.user.UserRepository; -import com.baeldung.domain.product.Product; -import com.baeldung.domain.user.Possession; -import com.baeldung.domain.user.User; +import com.baeldung.multipledb.dao.product.ProductRepository; +import com.baeldung.multipledb.dao.user.PossessionRepository; +import com.baeldung.multipledb.dao.user.UserRepository; +import com.baeldung.multipledb.model.product.ProductMultipleDB; +import com.baeldung.multipledb.model.user.PossessionMultipleDB; +import com.baeldung.multipledb.model.user.UserMultipleDB; @RunWith(SpringRunner.class) -@ContextConfiguration(classes = { PersistenceUserConfiguration.class, PersistenceProductConfiguration.class }) +@SpringBootTest(classes=MultipleDbApplication.class) @EnableTransactionManagement -@DirtiesContext public class JpaMultipleDBIntegrationTest { @Autowired @@ -46,15 +43,15 @@ public class JpaMultipleDBIntegrationTest { @Test @Transactional("userTransactionManager") public void whenCreatingUser_thenCreated() { - User user = new User(); + UserMultipleDB user = new UserMultipleDB(); user.setName("John"); user.setEmail("john@test.com"); user.setAge(20); - Possession p = new Possession("sample"); + PossessionMultipleDB p = new PossessionMultipleDB("sample"); p = possessionRepository.save(p); user.setPossessionList(Collections.singletonList(p)); user = userRepository.save(user); - final Optional result = userRepository.findById(user.getId()); + final Optional result = userRepository.findById(user.getId()); assertTrue(result.isPresent()); System.out.println(result.get().getPossessionList()); assertEquals(1, result.get().getPossessionList().size()); @@ -63,14 +60,14 @@ public class JpaMultipleDBIntegrationTest { @Test @Transactional("userTransactionManager") public void whenCreatingUsersWithSameEmail_thenRollback() { - User user1 = new User(); + UserMultipleDB user1 = new UserMultipleDB(); user1.setName("John"); user1.setEmail("john@test.com"); user1.setAge(20); user1 = userRepository.save(user1); assertTrue(userRepository.findById(user1.getId()).isPresent()); - User user2 = new User(); + UserMultipleDB user2 = new UserMultipleDB(); user2.setName("Tom"); user2.setEmail("john@test.com"); user2.setAge(10); @@ -88,7 +85,7 @@ public class JpaMultipleDBIntegrationTest { @Test @Transactional("productTransactionManager") public void whenCreatingProduct_thenCreated() { - Product product = new Product(); + ProductMultipleDB product = new ProductMultipleDB(); product.setName("Book"); product.setId(2); product.setPrice(20); diff --git a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/product/ProductRepositoryIntegrationTest.java b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/multipledb/ProductRepositoryIntegrationTest.java similarity index 69% rename from persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/product/ProductRepositoryIntegrationTest.java rename to persistence-modules/spring-data-jpa/src/test/java/com/baeldung/multipledb/ProductRepositoryIntegrationTest.java index 4caa0f0ca4..2c965f72f3 100644 --- a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/product/ProductRepositoryIntegrationTest.java +++ b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/multipledb/ProductRepositoryIntegrationTest.java @@ -1,4 +1,4 @@ -package com.baeldung.dao.repositories.product; +package com.baeldung.multipledb; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasSize; @@ -13,6 +13,7 @@ import org.junit.Before; 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.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; @@ -22,11 +23,12 @@ import org.springframework.test.context.junit4.SpringRunner; import org.springframework.transaction.annotation.EnableTransactionManagement; import org.springframework.transaction.annotation.Transactional; -import com.baeldung.config.PersistenceProductConfiguration; -import com.baeldung.domain.product.Product; +import com.baeldung.multipledb.PersistenceProductConfiguration; +import com.baeldung.multipledb.dao.product.ProductRepository; +import com.baeldung.multipledb.model.product.ProductMultipleDB; @RunWith(SpringRunner.class) -@ContextConfiguration(classes = { PersistenceProductConfiguration.class }) +@SpringBootTest(classes=MultipleDbApplication.class) @EnableTransactionManagement public class ProductRepositoryIntegrationTest { @@ -36,22 +38,22 @@ public class ProductRepositoryIntegrationTest { @Before @Transactional("productTransactionManager") public void setUp() { - productRepository.save(Product.from(1001, "Book", 21)); - productRepository.save(Product.from(1002, "Coffee", 10)); - productRepository.save(Product.from(1003, "Jeans", 30)); - productRepository.save(Product.from(1004, "Shirt", 32)); - productRepository.save(Product.from(1005, "Bacon", 10)); + productRepository.save(ProductMultipleDB.from(1001, "Book", 21)); + productRepository.save(ProductMultipleDB.from(1002, "Coffee", 10)); + productRepository.save(ProductMultipleDB.from(1003, "Jeans", 30)); + productRepository.save(ProductMultipleDB.from(1004, "Shirt", 32)); + productRepository.save(ProductMultipleDB.from(1005, "Bacon", 10)); } @Test public void whenRequestingFirstPageOfSizeTwo_ThenReturnFirstPage() { Pageable pageRequest = PageRequest.of(0, 2); - Page result = productRepository.findAll(pageRequest); + Page result = productRepository.findAll(pageRequest); assertThat(result.getContent(), hasSize(2)); assertTrue(result.stream() - .map(Product::getId) + .map(ProductMultipleDB::getId) .allMatch(id -> Arrays.asList(1001, 1002) .contains(id))); } @@ -60,11 +62,11 @@ public class ProductRepositoryIntegrationTest { public void whenRequestingSecondPageOfSizeTwo_ThenReturnSecondPage() { Pageable pageRequest = PageRequest.of(1, 2); - Page result = productRepository.findAll(pageRequest); + Page result = productRepository.findAll(pageRequest); assertThat(result.getContent(), hasSize(2)); assertTrue(result.stream() - .map(Product::getId) + .map(ProductMultipleDB::getId) .allMatch(id -> Arrays.asList(1003, 1004) .contains(id))); } @@ -73,11 +75,11 @@ public class ProductRepositoryIntegrationTest { public void whenRequestingLastPage_ThenReturnLastPageWithRemData() { Pageable pageRequest = PageRequest.of(2, 2); - Page result = productRepository.findAll(pageRequest); + Page result = productRepository.findAll(pageRequest); assertThat(result.getContent(), hasSize(1)); assertTrue(result.stream() - .map(Product::getId) + .map(ProductMultipleDB::getId) .allMatch(id -> Arrays.asList(1005) .contains(id))); } @@ -86,12 +88,12 @@ public class ProductRepositoryIntegrationTest { public void whenSortingByNameAscAndPaging_ThenReturnSortedPagedResult() { Pageable pageRequest = PageRequest.of(0, 3, Sort.by("name")); - Page result = productRepository.findAll(pageRequest); + Page result = productRepository.findAll(pageRequest); assertThat(result.getContent(), hasSize(3)); assertThat(result.getContent() .stream() - .map(Product::getId) + .map(ProductMultipleDB::getId) .collect(Collectors.toList()), equalTo(Arrays.asList(1005, 1001, 1002))); } @@ -101,12 +103,12 @@ public class ProductRepositoryIntegrationTest { Pageable pageRequest = PageRequest.of(0, 3, Sort.by("price") .descending()); - Page result = productRepository.findAll(pageRequest); + Page result = productRepository.findAll(pageRequest); assertThat(result.getContent(), hasSize(3)); assertThat(result.getContent() .stream() - .map(Product::getId) + .map(ProductMultipleDB::getId) .collect(Collectors.toList()), equalTo(Arrays.asList(1004, 1003, 1001))); } @@ -117,12 +119,12 @@ public class ProductRepositoryIntegrationTest { .descending() .and(Sort.by("name"))); - Page result = productRepository.findAll(pageRequest); + Page result = productRepository.findAll(pageRequest); assertThat(result.getContent(), hasSize(5)); assertThat(result.getContent() .stream() - .map(Product::getId) + .map(ProductMultipleDB::getId) .collect(Collectors.toList()), equalTo(Arrays.asList(1004, 1003, 1001, 1005, 1002))); } @@ -131,11 +133,11 @@ public class ProductRepositoryIntegrationTest { public void whenRequestingFirstPageOfSizeTwoUsingCustomMethod_ThenReturnFirstPage() { Pageable pageRequest = PageRequest.of(0, 2); - List result = productRepository.findAllByPrice(10, pageRequest); + List result = productRepository.findAllByPrice(10, pageRequest); assertThat(result, hasSize(2)); assertTrue(result.stream() - .map(Product::getId) + .map(ProductMultipleDB::getId) .allMatch(id -> Arrays.asList(1002, 1005) .contains(id))); } diff --git a/persistence-modules/spring-data-jpa/src/test/java/org/baeldung/SpringContextIntegrationTest.java b/persistence-modules/spring-data-jpa/src/test/java/org/baeldung/SpringContextIntegrationTest.java index 7f906bdbcd..e885d0fe51 100644 --- a/persistence-modules/spring-data-jpa/src/test/java/org/baeldung/SpringContextIntegrationTest.java +++ b/persistence-modules/spring-data-jpa/src/test/java/org/baeldung/SpringContextIntegrationTest.java @@ -5,7 +5,7 @@ import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; -import com.baeldung.Application; +import com.baeldung.boot.Application; @RunWith(SpringRunner.class) @SpringBootTest(classes = Application.class) diff --git a/persistence-modules/spring-data-jpa/src/test/java/org/baeldung/SpringJpaContextIntegrationTest.java b/persistence-modules/spring-data-jpa/src/test/java/org/baeldung/SpringJpaContextIntegrationTest.java index 66b5b20b97..4a36407884 100644 --- a/persistence-modules/spring-data-jpa/src/test/java/org/baeldung/SpringJpaContextIntegrationTest.java +++ b/persistence-modules/spring-data-jpa/src/test/java/org/baeldung/SpringJpaContextIntegrationTest.java @@ -6,10 +6,10 @@ import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringRunner; -import com.baeldung.Application; -import com.baeldung.config.PersistenceConfiguration; -import com.baeldung.config.PersistenceProductConfiguration; -import com.baeldung.config.PersistenceUserConfiguration; +import com.baeldung.boot.Application; +import com.baeldung.boot.config.PersistenceConfiguration; +import com.baeldung.multipledb.PersistenceProductConfiguration; +import com.baeldung.multipledb.PersistenceUserConfiguration; @RunWith(SpringRunner.class) @DataJpaTest(excludeAutoConfiguration = { diff --git a/persistence-modules/spring-jpa/pom.xml b/persistence-modules/spring-jpa/pom.xml index 29a6996791..3daba6cd55 100644 --- a/persistence-modules/spring-jpa/pom.xml +++ b/persistence-modules/spring-jpa/pom.xml @@ -156,13 +156,13 @@ - 4.3.8.RELEASE + 5.1.5.RELEASE 3.21.0-GA - 5.2.10.Final + 5.2.17.Final 6.0.6 - 1.11.3.RELEASE + 2.1.5.RELEASE 1.4.195 @@ -170,7 +170,7 @@ 2.5 - 5.4.1.Final + 6.0.15.Final 1.4.01 2.2.5 diff --git a/persistence-modules/spring-jpa/src/test/java/com/baeldung/SpringContextIntegrationTest.java b/persistence-modules/spring-jpa/src/test/java/com/baeldung/SpringContextIntegrationTest.java index aa85128628..822cbb8ed5 100644 --- a/persistence-modules/spring-jpa/src/test/java/com/baeldung/SpringContextIntegrationTest.java +++ b/persistence-modules/spring-jpa/src/test/java/com/baeldung/SpringContextIntegrationTest.java @@ -3,6 +3,7 @@ package com.baeldung; import org.baeldung.config.PersistenceJPAConfigL2Cache; import org.junit.Test; import org.junit.runner.RunWith; +import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.support.AnnotationConfigContextLoader; @@ -11,6 +12,7 @@ import org.springframework.test.context.web.WebAppConfiguration; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = { PersistenceJPAConfigL2Cache.class }, loader = AnnotationConfigContextLoader.class) @WebAppConfiguration +@DirtiesContext public class SpringContextIntegrationTest { @Test diff --git a/persistence-modules/spring-jpa/src/test/java/org/baeldung/persistence/repository/InMemoryDBIntegrationTest.java b/persistence-modules/spring-jpa/src/test/java/org/baeldung/persistence/repository/InMemoryDBIntegrationTest.java index 9ddc48460a..4d1bcbe1b2 100644 --- a/persistence-modules/spring-jpa/src/test/java/org/baeldung/persistence/repository/InMemoryDBIntegrationTest.java +++ b/persistence-modules/spring-jpa/src/test/java/org/baeldung/persistence/repository/InMemoryDBIntegrationTest.java @@ -35,7 +35,7 @@ public class InMemoryDBIntegrationTest { Student student = new Student(ID, NAME); studentRepository.save(student); - Student student2 = studentRepository.findOne(ID); + Student student2 = studentRepository.findById(ID).get(); assertEquals("name incorrect", NAME, student2.getName()); } diff --git a/picocli/pom.xml b/picocli/pom.xml new file mode 100644 index 0000000000..0334f5463d --- /dev/null +++ b/picocli/pom.xml @@ -0,0 +1,28 @@ + + + 4.0.0 + + com.baeldung + parent-java + 0.0.1-SNAPSHOT + ../parent-java + + + picocli + + + + info.picocli + picocli + 3.9.6 + + + + org.springframework.boot + spring-boot-starter + 2.1.4.RELEASE + + + \ No newline at end of file diff --git a/picocli/src/main/java/com/baeldung/picocli/git/Application.java b/picocli/src/main/java/com/baeldung/picocli/git/Application.java new file mode 100644 index 0000000000..04af524e45 --- /dev/null +++ b/picocli/src/main/java/com/baeldung/picocli/git/Application.java @@ -0,0 +1,41 @@ +package com.baeldung.picocli.git; + +import com.baeldung.picocli.git.commands.programmative.GitCommand; +import com.baeldung.picocli.git.commands.subcommands.GitAddCommand; +import com.baeldung.picocli.git.commands.subcommands.GitCommitCommand; +import com.baeldung.picocli.git.commands.subcommands.GitConfigCommand; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import picocli.CommandLine; + +@SpringBootApplication +public class Application implements CommandLineRunner { + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + + private GitCommand gitCommand; + private GitAddCommand addCommand; + private GitCommitCommand commitCommand; + private GitConfigCommand configCommand; + + @Autowired + public Application(GitCommand gitCommand, GitAddCommand addCommand, GitCommitCommand commitCommand, GitConfigCommand configCommand) { + this.gitCommand = gitCommand; + this.addCommand = addCommand; + this.commitCommand = commitCommand; + this.configCommand = configCommand; + } + + @Override + public void run(String... args) { + CommandLine commandLine = new CommandLine(gitCommand); + commandLine.addSubcommand("add", addCommand); + commandLine.addSubcommand("commit", commitCommand); + commandLine.addSubcommand("config", configCommand); + + commandLine.parseWithHandler(new CommandLine.RunLast(), args); + } +} diff --git a/picocli/src/main/java/com/baeldung/picocli/git/commands/declarative/GitCommand.java b/picocli/src/main/java/com/baeldung/picocli/git/commands/declarative/GitCommand.java new file mode 100644 index 0000000000..f3c690a3e6 --- /dev/null +++ b/picocli/src/main/java/com/baeldung/picocli/git/commands/declarative/GitCommand.java @@ -0,0 +1,32 @@ +package com.baeldung.picocli.git.commands.declarative; + +import com.baeldung.picocli.git.model.ConfigElement; +import com.baeldung.picocli.git.commands.subcommands.GitAddCommand; +import com.baeldung.picocli.git.commands.subcommands.GitCommitCommand; +import com.baeldung.picocli.git.commands.subcommands.GitConfigCommand; +import picocli.CommandLine; + +import static picocli.CommandLine.*; +import static picocli.CommandLine.Command; + +@Command( + name = "git", + subcommands = { + GitAddCommand.class, + GitCommitCommand.class, + GitConfigCommand.class + } +) +public class GitCommand implements Runnable { + public static void main(String[] args) { + CommandLine commandLine = new CommandLine(new GitCommand()); + commandLine.registerConverter(ConfigElement.class, ConfigElement::from); + + commandLine.parseWithHandler(new RunLast(), args); + } + + @Override + public void run() { + System.out.println("The popular git command"); + } +} diff --git a/picocli/src/main/java/com/baeldung/picocli/git/commands/methods/GitCommand.java b/picocli/src/main/java/com/baeldung/picocli/git/commands/methods/GitCommand.java new file mode 100644 index 0000000000..2c3e440b8b --- /dev/null +++ b/picocli/src/main/java/com/baeldung/picocli/git/commands/methods/GitCommand.java @@ -0,0 +1,27 @@ +package com.baeldung.picocli.git.commands.methods; + +import picocli.CommandLine; + +import static picocli.CommandLine.Command; + +@Command(name = "git") +public class GitCommand implements Runnable { + public static void main(String[] args) { + CommandLine.run(new GitCommand(), args); + } + + @Override + public void run() { + System.out.println("The popular git command"); + } + + @Command(name = "add") + public void addCommand() { + System.out.println("Adding some files to the staging area"); + } + + @Command(name = "commit") + public void commitCommand() { + System.out.println("Committing files in the staging area, how wonderful?"); + } +} diff --git a/picocli/src/main/java/com/baeldung/picocli/git/commands/programmative/GitCommand.java b/picocli/src/main/java/com/baeldung/picocli/git/commands/programmative/GitCommand.java new file mode 100644 index 0000000000..81ecfd78be --- /dev/null +++ b/picocli/src/main/java/com/baeldung/picocli/git/commands/programmative/GitCommand.java @@ -0,0 +1,26 @@ +package com.baeldung.picocli.git.commands.programmative; + +import com.baeldung.picocli.git.commands.subcommands.GitAddCommand; +import com.baeldung.picocli.git.commands.subcommands.GitCommitCommand; +import org.springframework.stereotype.Component; +import picocli.CommandLine; + +import static picocli.CommandLine.Command; +import static picocli.CommandLine.RunLast; + +@Command(name = "git") +@Component +public class GitCommand implements Runnable { + public static void main(String[] args) { + CommandLine commandLine = new CommandLine(new GitCommand()); + commandLine.addSubcommand("add", new GitAddCommand()); + commandLine.addSubcommand("commit", new GitCommitCommand()); + + commandLine.parseWithHandler(new RunLast(), args); + } + + @Override + public void run() { + System.out.println("The popular git command"); + } +} diff --git a/picocli/src/main/java/com/baeldung/picocli/git/commands/subcommands/GitAddCommand.java b/picocli/src/main/java/com/baeldung/picocli/git/commands/subcommands/GitAddCommand.java new file mode 100644 index 0000000000..803cd8dc7d --- /dev/null +++ b/picocli/src/main/java/com/baeldung/picocli/git/commands/subcommands/GitAddCommand.java @@ -0,0 +1,31 @@ +package com.baeldung.picocli.git.commands.subcommands; + +import org.springframework.stereotype.Component; + +import java.nio.file.Path; +import java.util.List; + +import static picocli.CommandLine.*; + +@Command( + name = "add" +) +@Component +public class GitAddCommand implements Runnable { + @Option(names = "-A") + private boolean allFiles; + + @Parameters(index = "0..*") + private List files; + + @Override + public void run() { + if (allFiles) { + System.out.println("Adding all files to the staging area"); + } + + if (files != null) { + files.forEach(path -> System.out.println("Adding " + path + " to the staging area")); + } + } +} diff --git a/picocli/src/main/java/com/baeldung/picocli/git/commands/subcommands/GitCommitCommand.java b/picocli/src/main/java/com/baeldung/picocli/git/commands/subcommands/GitCommitCommand.java new file mode 100644 index 0000000000..df4928983c --- /dev/null +++ b/picocli/src/main/java/com/baeldung/picocli/git/commands/subcommands/GitCommitCommand.java @@ -0,0 +1,26 @@ +package com.baeldung.picocli.git.commands.subcommands; + +import org.springframework.stereotype.Component; + +import static picocli.CommandLine.Command; +import static picocli.CommandLine.Option; + +@Command( + name = "commit" +) +@Component +public class GitCommitCommand implements Runnable { + @Option(names = {"-m", "--message"}, required = true) + private String[] messages; + + @Override + public void run() { + System.out.println("Committing files in the staging area, how wonderful?"); + if (messages != null) { + System.out.println("The commit message is"); + for (String message : messages) { + System.out.println(message); + } + } + } +} diff --git a/picocli/src/main/java/com/baeldung/picocli/git/commands/subcommands/GitConfigCommand.java b/picocli/src/main/java/com/baeldung/picocli/git/commands/subcommands/GitConfigCommand.java new file mode 100644 index 0000000000..80e14c0121 --- /dev/null +++ b/picocli/src/main/java/com/baeldung/picocli/git/commands/subcommands/GitConfigCommand.java @@ -0,0 +1,24 @@ +package com.baeldung.picocli.git.commands.subcommands; + +import com.baeldung.picocli.git.model.ConfigElement; +import org.springframework.stereotype.Component; + +import static picocli.CommandLine.Command; +import static picocli.CommandLine.Parameters; + +@Command( + name = "config" +) +@Component +public class GitConfigCommand implements Runnable { + @Parameters(index = "0") + private ConfigElement element; + + @Parameters(index = "1") + private String value; + + @Override + public void run() { + System.out.println("Setting " + element.value() + " to " + value); + } +} diff --git a/picocli/src/main/java/com/baeldung/picocli/git/model/ConfigElement.java b/picocli/src/main/java/com/baeldung/picocli/git/model/ConfigElement.java new file mode 100644 index 0000000000..edc6573d88 --- /dev/null +++ b/picocli/src/main/java/com/baeldung/picocli/git/model/ConfigElement.java @@ -0,0 +1,25 @@ +package com.baeldung.picocli.git.model; + +import java.util.Arrays; + +public enum ConfigElement { + USERNAME("user.name"), + EMAIL("user.email"); + + private final String value; + + ConfigElement(String value) { + this.value = value; + } + + public String value() { + return value; + } + + public static ConfigElement from(String value) { + return Arrays.stream(values()) + .filter(element -> element.value.equals(value)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("The argument " + value + " doesn't match any ConfigElement")); + } +} diff --git a/picocli/src/main/java/com/baeldung/picocli/helloworld/HelloWorldCommand.java b/picocli/src/main/java/com/baeldung/picocli/helloworld/HelloWorldCommand.java new file mode 100644 index 0000000000..97a861e2f0 --- /dev/null +++ b/picocli/src/main/java/com/baeldung/picocli/helloworld/HelloWorldCommand.java @@ -0,0 +1,20 @@ +package com.baeldung.picocli.helloworld; + +import picocli.CommandLine; + +import static picocli.CommandLine.Command; + +@Command( + name = "hello", + description = "Says hello" +) +public class HelloWorldCommand implements Runnable { + public static void main(String[] args) { + CommandLine.run(new HelloWorldCommand(), args); + } + + @Override + public void run() { + System.out.println("Hello World!"); + } +} diff --git a/pom.xml b/pom.xml index d26b96ea8e..b896514b3a 100644 --- a/pom.xml +++ b/pom.xml @@ -7,12 +7,14 @@ com.baeldung parent-modules 1.0.0-SNAPSHOT - - lombok-custom - parent-modules pom + + lombok-custom + picocli + + @@ -232,7 +234,7 @@ ${maven-war-plugin.version} - + com.vackosar.gitflowincrementalbuilder @@ -332,11 +334,12 @@ parent-spring-5 parent-java parent-kotlin - + akka-streams algorithms-genetic algorithms-miscellaneous-1 algorithms-miscellaneous-2 + algorithms-miscellaneous-3 algorithms-sorting animal-sniffer-mvn-plugin annotations @@ -375,13 +378,20 @@ cdi checker-plugin core-groovy + core-groovy-2 + core-groovy-collections - + + core-java-8 + core-java-8-2 + core-java-lambdas + core-java-arrays core-java-collections core-java-collections-list + core-java-collections-set core-java-concurrency-basic core-java-concurrency-collections core-java-io @@ -389,14 +399,17 @@ core-java-lang-syntax core-java-lang core-java-lang-oop + core-java-lang-oop-2 + core-java-modules core-java-networking core-java-perf core-java-sun - core-java + core-java + core-java-jvm core-scala couchbase custom-pmd - + dagger data-structures ddd @@ -404,13 +417,13 @@ disruptor dozer drools - dubbo - + dubbo + ethereum - + feign flyway-cdi-extension - + geotools google-cloud google-web-toolkit @@ -424,26 +437,33 @@ guava-modules guice - + hazelcast helidon httpclient + httpclient-simple hystrix - + image-processing immutables jackson + jackson-2 + jackson-simple java-collections-conversions java-collections-maps + java-collections-maps-2 + java-lite java-numbers java-rmi java-spi java-streams + java-streams-2 java-strings + java-strings-2 java-vavr-stream java-websocket javafx @@ -456,6 +476,8 @@ jersey JGit jgroups + jhipster + jhipster-5 jib jjwt jmeter @@ -470,11 +492,14 @@ kotlin-libraries - + kotlin-libraries-2 + libraries + libraries-2 libraries-data libraries-apache-commons + libraries-primitive libraries-security libraries-server linkrest @@ -496,9 +521,8 @@ mustache mybatis - - noexception - + + optaplanner orika osgi @@ -508,9 +532,9 @@ performance-tests protobuffer - + persistence-modules - + rabbitmq ratpack @@ -522,12 +546,17 @@ rule-engines rsocket rxjava - rxjava-2 + rxjava-2 software-security/sql-injection-samples + + tensorflow-java + spring-boot-flowable + spring-security-kerberos + - + default-second @@ -561,13 +590,15 @@ parent-spring-5 parent-java parent-kotlin - + saas spark-java - + spring-4 - + spring-5 + spring-5-webflux + spring-5-data-reactive spring-5-mvc spring-5-reactive spring-5-reactive-client @@ -575,75 +606,82 @@ spring-5-reactive-security spring-5-security spring-5-security-oauth - + spring-activiti spring-akka spring-all spring-amqp + spring-amqp-simple spring-aop spring-apache-camel spring-batch spring-bom - + spring-boot spring-boot-admin + spring-boot-angular spring-boot-angular-ecommerce spring-boot-autoconfiguration spring-boot-bootstrap spring-boot-camel spring-boot-client + spring-boot-crud spring-boot-ctx-fluent spring-boot-custom-starter spring-boot-disable-console-logging + spring-boot-exceptions spring-boot-jasypt spring-boot-keycloak spring-boot-logging-log4j2 spring-boot-mvc + spring-boot-mvc-birt spring-boot-ops + spring-boot-ops-2 spring-boot-rest + spring-boot-data spring-boot-property-exp spring-boot-security spring-boot-testing spring-boot-vue spring-boot-libraries - + spring-cloud spring-cloud-bus spring-cloud-data-flow - + spring-core spring-cucumber - + spring-data-rest spring-data-rest-querydsl spring-dispatcher-servlet spring-drools - + spring-ehcache spring-ejb spring-exceptions - + spring-freemarker - + spring-groovy - + spring-integration - + spring-jenkins-pipeline spring-jersey spring-jinq spring-jms spring-jooq - + spring-kafka spring-katharsis - + spring-ldap - + spring-mobile spring-mockito spring-mvc-forms-jsp @@ -651,14 +689,16 @@ spring-mvc-java spring-mvc-kotlin spring-mvc-simple + spring-mvc-simple-2 spring-mvc-velocity spring-mvc-webflow spring-mvc-xml - + spring-protobuf - + + spring-quartz - + spring-reactive-kotlin spring-reactor spring-remoting @@ -674,9 +714,9 @@ spring-security-acl spring-security-angular/server spring-security-cache-control - + spring-security-client - + spring-security-core spring-security-mvc-boot spring-security-mvc-custom @@ -704,46 +744,50 @@ spring-state-machine spring-static-resources spring-swagger-codegen - + spring-thymeleaf - + spring-userservice - + spring-vault spring-vertx - + spring-webflux-amqp - + spring-zuul - + static-analysis stripe structurizr struts-2 - + testing-modules - + twilio Twitter4J - + undertow - + vavr vertx vertx-and-rxjava video-tutorials vraptor - + wicket - + xml xmlunit-2 xstream - + + tensorflow-java + spring-boot-flowable + spring-security-kerberos + - + spring-context @@ -786,7 +830,8 @@ spring-boot-camel spring-boot-client spring-boot-custom-starter - greeter-spring-boot-autoconfigure + spring-boot-exceptions + greeter-spring-boot-autoconfigure greeter-spring-boot-sample-app persistence-modules/spring-boot-h2/spring-boot-h2-database spring-boot-jasypt @@ -881,6 +926,9 @@ persistence-modules/spring-data-eclipselink persistence-modules/spring-data-solr persistence-modules/spring-hibernate-5 + + spring-boot-flowable + spring-security-kerberos @@ -918,29 +966,27 @@ parent-spring-5 parent-java parent-kotlin - + core-java-concurrency-advanced core-kotlin core-kotlin-2 + core-kotlin-io jenkins/hello-world - jhipster jws libraries persistence-modules/hibernate5 + persistence-modules/hibernate-mapping persistence-modules/java-jpa persistence-modules/java-mongodb - persistence-modules/jnosql + persistence-modules/jnosql - spring-5-data-reactive - spring-amqp-simple - - vaadin + vaadin - + integration-lite-first @@ -970,11 +1016,12 @@ parent-spring-5 parent-java parent-kotlin - + akka-streams algorithms-genetic algorithms-miscellaneous-1 algorithms-miscellaneous-2 + algorithms-miscellaneous-3 algorithms-sorting animal-sniffer-mvn-plugin annotations @@ -1011,13 +1058,18 @@ cdi checker-plugin core-groovy + core-groovy-2 + core-groovy-collections - + core-java-8 + core-java-8-2 + core-java-arrays core-java-collections core-java-collections-list + core-java-collections-set core-java-concurrency-basic core-java-concurrency-collections core-java-io @@ -1025,13 +1077,15 @@ core-java-lang-syntax core-java-lang core-java-lang-oop + core-java-lang-oop-2 + core-java-modules core-java-networking core-java-perf core-java-sun core-scala couchbase custom-pmd - + dagger data-structures ddd @@ -1039,13 +1093,13 @@ disruptor dozer drools - dubbo - + dubbo + ethereum - + feign flyway-cdi-extension - + geotools google-cloud google-web-toolkit @@ -1059,18 +1113,22 @@ guava-modules guice - + hazelcast helidon httpclient + httpclient-simple hystrix - + image-processing immutables jackson + jackson-2 + jackson-simple java-collections-conversions java-collections-maps + java-collections-maps-2 java-ee-8-security-api java-lite @@ -1078,7 +1136,9 @@ java-rmi java-spi java-streams + java-streams-2 java-strings + java-strings-2 java-vavr-stream java-websocket javafx @@ -1091,6 +1151,8 @@ jersey JGit jgroups + jhipster + jhipster-5 jib jjwt jmeter @@ -1105,7 +1167,7 @@ kotlin-libraries - + libraries libraries-data @@ -1119,6 +1181,7 @@ mapstruct maven + maven-archetype maven-polyglot/maven-polyglot-json-extension @@ -1131,9 +1194,8 @@ mustache mybatis - - noexception - + + optaplanner orika osgi @@ -1143,9 +1205,9 @@ performance-tests protobuffer - + persistence-modules - + rabbitmq ratpack @@ -1157,8 +1219,8 @@ rule-engines rsocket rxjava - rxjava-2 - + rxjava-2 + @@ -1192,13 +1254,14 @@ parent-spring-5 parent-java parent-kotlin - + saas spark-java - + spring-4 - + spring-5 + spring-5-data-reactive spring-5-mvc spring-5-reactive spring-5-reactive-client @@ -1206,18 +1269,20 @@ spring-5-reactive-security spring-5-security spring-5-security-oauth - + spring-activiti spring-akka spring-all spring-amqp + spring-amqp-simple spring-aop spring-apache-camel spring-batch spring-bom - + spring-boot spring-boot-admin + spring-boot-angular spring-boot-angular-ecommerce spring-boot-autoconfiguration spring-boot-bootstrap @@ -1228,51 +1293,55 @@ spring-boot-ctx-fluent spring-boot-custom-starter spring-boot-disable-console-logging + spring-boot-exceptions spring-boot-jasypt spring-boot-keycloak spring-boot-logging-log4j2 spring-boot-mvc + spring-boot-mvc-birt spring-boot-ops + spring-boot-ops-2 spring-boot-rest + spring-boot-data spring-boot-property-exp spring-boot-security spring-boot-vue - + spring-cloud spring-cloud-bus spring-cloud-data-flow - + spring-core spring-cucumber - + spring-data-rest spring-data-rest-querydsl spring-dispatcher-servlet spring-drools - - spring-ehcache + + spring-ehcache spring-ejb spring-exceptions - + spring-freemarker - + spring-groovy - + spring-integration - + spring-jenkins-pipeline spring-jersey spring-jinq spring-jms spring-jooq - + spring-kafka spring-katharsis - + spring-ldap - + spring-mobile spring-mockito spring-mvc-forms-jsp @@ -1280,14 +1349,16 @@ spring-mvc-java spring-mvc-kotlin spring-mvc-simple + spring-mvc-simple-2 spring-mvc-velocity spring-mvc-webflow spring-mvc-xml - + spring-protobuf - + + spring-quartz - + spring-reactive-kotlin spring-reactor spring-remoting @@ -1300,13 +1371,13 @@ spring-rest-simple spring-resttemplate spring-roo - + spring-security-acl spring-security-angular/server spring-security-cache-control - + spring-security-client - + spring-security-core spring-security-mvc-boot spring-security-mvc-custom @@ -1333,42 +1404,42 @@ spring-state-machine spring-static-resources spring-swagger-codegen - + spring-thymeleaf - + spring-userservice - + spring-vault spring-vertx - + spring-webflux-amqp - + spring-zuul - + static-analysis stripe structurizr struts-2 - + testing-modules - + twilio Twitter4J - + undertow - + vavr vertx vertx-and-rxjava video-tutorials vraptor - + wicket - + xml xmlunit-2 xstream - + @@ -1402,14 +1473,13 @@ parent-spring-5 parent-java parent-kotlin - - core-java + + core-java core-java-concurrency-advanced core-kotlin core-kotlin-2 jenkins/hello-world - jhipster jws libraries @@ -1417,12 +1487,9 @@ persistence-modules/hibernate5 persistence-modules/java-jpa persistence-modules/java-mongodb - persistence-modules/jnosql + persistence-modules/jnosql - spring-5-data-reactive - spring-amqp-simple - - vaadin + vaadin @@ -1443,20 +1510,21 @@ UTF-8 UTF-8 - refs/remotes/origin/master - true + refs/remotes/origin/master + true + false false false false - + 4.12 1.3 2.21.0 - + 1.7.21 1.1.7 - + 2.21.0 3.7.0 @@ -1478,14 +1546,14 @@ 2.3.1 1.9.13 1.2 - 2.9.7 + 2.9.8 1.3 1.2.0 5.2.0 0.3.1 2.5.1 0.0.1 - 3.4 + 3.8 2.3 3.8 diff --git a/reactor-core/README.md b/reactor-core/README.md index 6f90e59894..5f9d2d1bc2 100644 --- a/reactor-core/README.md +++ b/reactor-core/README.md @@ -2,3 +2,4 @@ - [Intro To Reactor Core](http://www.baeldung.com/reactor-core) - [Combining Publishers in Project Reactor](http://www.baeldung.com/reactor-combine-streams) +- [Programmatically Creating Sequences with Project Reactor](https://www.baeldung.com/flux-sequences-reactor) diff --git a/reactor-core/pom.xml b/reactor-core/pom.xml index db9550df7b..66c634e113 100644 --- a/reactor-core/pom.xml +++ b/reactor-core/pom.xml @@ -16,7 +16,13 @@ io.projectreactor reactor-core - ${reactor-core.version} + ${reactor.version} + + + io.projectreactor + reactor-test + ${reactor.version} + test org.assertj @@ -24,16 +30,10 @@ ${assertj.version} test - - io.projectreactor - reactor-test - ${reactor-core.version} - test - - 3.1.3.RELEASE + 3.2.6.RELEASE 3.6.1 diff --git a/reactor-core/src/main/java/com/baeldung/reactor/creation/FibonacciState.java b/reactor-core/src/main/java/com/baeldung/reactor/creation/FibonacciState.java new file mode 100644 index 0000000000..291002e1f9 --- /dev/null +++ b/reactor-core/src/main/java/com/baeldung/reactor/creation/FibonacciState.java @@ -0,0 +1,27 @@ +package com.baeldung.reactor.creation; + +public class FibonacciState { + private int former; + private int latter; + + public FibonacciState(int former, int latter) { + this.former = former; + this.latter = latter; + } + + public int getFormer() { + return former; + } + + public void setFormer(int former) { + this.former = former; + } + + public int getLatter() { + return latter; + } + + public void setLatter(int latter) { + this.latter = latter; + } +} diff --git a/reactor-core/src/main/java/com/baeldung/reactor/creation/SequenceCreator.java b/reactor-core/src/main/java/com/baeldung/reactor/creation/SequenceCreator.java new file mode 100644 index 0000000000..fb53b1cab1 --- /dev/null +++ b/reactor-core/src/main/java/com/baeldung/reactor/creation/SequenceCreator.java @@ -0,0 +1,14 @@ +package com.baeldung.reactor.creation; + +import reactor.core.publisher.Flux; + +import java.util.List; +import java.util.function.Consumer; + +public class SequenceCreator { + public Consumer> consumer; + + public Flux createNumberSequence() { + return Flux.create(sink -> SequenceCreator.this.consumer = items -> items.forEach(sink::next)); + } +} diff --git a/reactor-core/src/main/java/com/baeldung/reactor/creation/SequenceGenerator.java b/reactor-core/src/main/java/com/baeldung/reactor/creation/SequenceGenerator.java new file mode 100644 index 0000000000..44d83d06bf --- /dev/null +++ b/reactor-core/src/main/java/com/baeldung/reactor/creation/SequenceGenerator.java @@ -0,0 +1,31 @@ +package com.baeldung.reactor.creation; + +import reactor.core.publisher.Flux; +import reactor.util.function.Tuples; + +public class SequenceGenerator { + public Flux generateFibonacciWithTuples() { + return Flux.generate( + () -> Tuples.of(0, 1), + (state, sink) -> { + sink.next(state.getT1()); + return Tuples.of(state.getT2(), state.getT1() + state.getT2()); + } + ); + } + + public Flux generateFibonacciWithCustomClass(int limit) { + return Flux.generate( + () -> new FibonacciState(0, 1), + (state, sink) -> { + sink.next(state.getFormer()); + if (state.getLatter() > limit) { + sink.complete(); + } + int temp = state.getFormer(); + state.setFormer(state.getLatter()); + state.setLatter(temp + state.getLatter()); + return state; + }); + } +} diff --git a/reactor-core/src/main/java/com/baeldung/reactor/creation/SequenceHandler.java b/reactor-core/src/main/java/com/baeldung/reactor/creation/SequenceHandler.java new file mode 100644 index 0000000000..a9611c63e2 --- /dev/null +++ b/reactor-core/src/main/java/com/baeldung/reactor/creation/SequenceHandler.java @@ -0,0 +1,13 @@ +package com.baeldung.reactor.creation; + +import reactor.core.publisher.Flux; + +public class SequenceHandler { + public Flux handleIntegerSequence(Flux sequence) { + return sequence.handle((number, sink) -> { + if (number % 2 == 0) { + sink.next(number / 2); + } + }); + } +} diff --git a/reactor-core/src/test/java/com/baeldung/reactor/creation/SequenceUnitTest.java b/reactor-core/src/test/java/com/baeldung/reactor/creation/SequenceUnitTest.java new file mode 100644 index 0000000000..78af1d2478 --- /dev/null +++ b/reactor-core/src/test/java/com/baeldung/reactor/creation/SequenceUnitTest.java @@ -0,0 +1,70 @@ +package com.baeldung.reactor.creation; + +import org.junit.Test; +import reactor.core.publisher.Flux; +import reactor.test.StepVerifier; + +import java.util.ArrayList; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class SequenceUnitTest { + @Test + public void whenGeneratingNumbersWithTuplesState_thenFibonacciSequenceIsProduced() { + SequenceGenerator sequenceGenerator = new SequenceGenerator(); + Flux fibonacciFlux = sequenceGenerator.generateFibonacciWithTuples().take(5); + + StepVerifier.create(fibonacciFlux) + .expectNext(0, 1, 1, 2, 3) + .expectComplete() + .verify(); + } + + @Test + public void whenGeneratingNumbersWithCustomClass_thenFibonacciSequenceIsProduced() { + SequenceGenerator sequenceGenerator = new SequenceGenerator(); + + StepVerifier.create(sequenceGenerator.generateFibonacciWithCustomClass(10)) + .expectNext(0, 1, 1, 2, 3, 5, 8) + .expectComplete() + .verify(); + } + + @Test + public void whenCreatingNumbers_thenSequenceIsProducedAsynchronously() throws InterruptedException { + SequenceGenerator sequenceGenerator = new SequenceGenerator(); + List sequence1 = sequenceGenerator.generateFibonacciWithTuples().take(3).collectList().block(); + List sequence2 = sequenceGenerator.generateFibonacciWithTuples().take(4).collectList().block(); + + SequenceCreator sequenceCreator = new SequenceCreator(); + Thread producingThread1 = new Thread( + () -> sequenceCreator.consumer.accept(sequence1) + ); + Thread producingThread2 = new Thread( + () -> sequenceCreator.consumer.accept(sequence2) + ); + + List consolidated = new ArrayList<>(); + sequenceCreator.createNumberSequence().subscribe(consolidated::add); + + producingThread1.start(); + producingThread2.start(); + producingThread1.join(); + producingThread2.join(); + + assertThat(consolidated).containsExactlyInAnyOrder(0, 1, 1, 0, 1, 1, 2); + } + + @Test + public void whenHandlingNumbers_thenSequenceIsMappedAndFiltered() { + SequenceHandler sequenceHandler = new SequenceHandler(); + SequenceGenerator sequenceGenerator = new SequenceGenerator(); + Flux sequence = sequenceGenerator.generateFibonacciWithTuples().take(10); + + StepVerifier.create(sequenceHandler.handleIntegerSequence(sequence)) + .expectNext(0, 1, 4, 17) + .expectComplete() + .verify(); + } +} diff --git a/rxjava-2/README.md b/rxjava-2/README.md index d0bdeec684..4182f3fa00 100644 --- a/rxjava-2/README.md +++ b/rxjava-2/README.md @@ -2,8 +2,8 @@ - [RxJava and Error Handling](http://www.baeldung.com/rxjava-error-handling) - [RxJava 2 – Flowable](http://www.baeldung.com/rxjava-2-flowable) -- [RxJava 2 - Completable](http://www.baeldung.com/rxjava-completable) - [RxJava Maybe](http://www.baeldung.com/rxjava-maybe) - [Introduction to RxRelay for RxJava](http://www.baeldung.com/rx-relay) - [Combining RxJava Completables](https://www.baeldung.com/rxjava-completable) - [Converting Synchronous and Asynchronous APIs to Observables using RxJava2](https://www.baeldung.com/rxjava-apis-to-observables) +- [RxJava Hooks](https://www.baeldung.com/rxjava-hooks) diff --git a/rxjava-2/src/test/java/com/baeldung/rxjava/RxJavaHooksManualTest.java b/rxjava-2/src/test/java/com/baeldung/rxjava/RxJavaHooksManualTest.java new file mode 100644 index 0000000000..b79fa9af22 --- /dev/null +++ b/rxjava-2/src/test/java/com/baeldung/rxjava/RxJavaHooksManualTest.java @@ -0,0 +1,84 @@ +package com.baeldung.rxjava; + +import static org.junit.Assert.assertTrue; + +import org.junit.After; +import org.junit.Test; + +import io.reactivex.Observable; +import io.reactivex.plugins.RxJavaPlugins; +import io.reactivex.schedulers.Schedulers; + +public class RxJavaHooksManualTest { + + private boolean initHookCalled = false; + private boolean hookCalled = false; + + @Test + public void givenIOScheduler_whenCalled_shouldExecuteTheHooks() { + + RxJavaPlugins.setInitIoSchedulerHandler((scheduler) -> { + initHookCalled = true; + return scheduler.call(); + }); + + RxJavaPlugins.setIoSchedulerHandler((scheduler) -> { + hookCalled = true; + return scheduler; + }); + + Observable.range(1, 10) + .map(v -> v * 2) + .subscribeOn(Schedulers.io()) + .test(); + assertTrue(hookCalled && initHookCalled); + } + + @Test + public void givenNewThreadScheduler_whenCalled_shouldExecuteTheHook() { + + RxJavaPlugins.setInitNewThreadSchedulerHandler((scheduler) -> { + initHookCalled = true; + return scheduler.call(); + }); + + RxJavaPlugins.setNewThreadSchedulerHandler((scheduler) -> { + hookCalled = true; + return scheduler; + }); + + Observable.range(1, 15) + .map(v -> v * 2) + .subscribeOn(Schedulers.newThread()) + .test(); + assertTrue(hookCalled && initHookCalled); + } + + @Test + public void givenSingleScheduler_whenCalled_shouldExecuteTheHooks() { + + RxJavaPlugins.setInitSingleSchedulerHandler((scheduler) -> { + initHookCalled = true; + return scheduler.call(); + }); + + RxJavaPlugins.setSingleSchedulerHandler((scheduler) -> { + hookCalled = true; + return scheduler; + }); + + Observable.range(1, 10) + .map(v -> v * 2) + .subscribeOn(Schedulers.single()) + .test(); + assertTrue(hookCalled && initHookCalled); + + } + + @After + public void reset() { + hookCalled = false; + initHookCalled = false; + RxJavaPlugins.reset(); + } +} diff --git a/rxjava-2/src/test/java/com/baeldung/rxjava/RxJavaHooksUnitTest.java b/rxjava-2/src/test/java/com/baeldung/rxjava/RxJavaHooksUnitTest.java new file mode 100644 index 0000000000..dd4287a4a9 --- /dev/null +++ b/rxjava-2/src/test/java/com/baeldung/rxjava/RxJavaHooksUnitTest.java @@ -0,0 +1,244 @@ +package com.baeldung.rxjava; + +import static org.junit.Assert.assertTrue; + +import org.junit.After; +import org.junit.Test; + +import io.reactivex.Completable; +import io.reactivex.Flowable; +import io.reactivex.Maybe; +import io.reactivex.Observable; +import io.reactivex.Single; +import io.reactivex.flowables.ConnectableFlowable; +import io.reactivex.observables.ConnectableObservable; +import io.reactivex.plugins.RxJavaPlugins; +import io.reactivex.schedulers.Schedulers; + +public class RxJavaHooksUnitTest { + + private boolean initHookCalled = false; + private boolean hookCalled = false; + + @Test + public void givenObservable_whenError_shouldExecuteTheHook() { + RxJavaPlugins.setErrorHandler(throwable -> { + hookCalled = true; + }); + + Observable.error(new IllegalStateException()) + .subscribe(); + assertTrue(hookCalled); + } + + @Test + public void givenCompletable_whenAssembled_shouldExecuteTheHook() { + + RxJavaPlugins.setOnCompletableAssembly(completable -> { + hookCalled = true; + return completable; + }); + Completable.fromSingle(Single.just(1)); + assertTrue(hookCalled); + } + + @Test + public void givenCompletable_whenSubscribed_shouldExecuteTheHook() { + + RxJavaPlugins.setOnCompletableSubscribe((completable, observer) -> { + hookCalled = true; + return observer; + }); + + Completable.fromSingle(Single.just(1)) + .test(); + assertTrue(hookCalled); + } + + @Test + public void givenObservable_whenAssembled_shouldExecuteTheHook() { + + RxJavaPlugins.setOnObservableAssembly(observable -> { + hookCalled = true; + return observable; + }); + + Observable.range(1, 10); + assertTrue(hookCalled); + } + + @Test + public void givenObservable_whenSubscribed_shouldExecuteTheHook() { + + RxJavaPlugins.setOnObservableSubscribe((observable, observer) -> { + hookCalled = true; + return observer; + }); + + Observable.range(1, 10) + .test(); + assertTrue(hookCalled); + } + + @Test + public void givenConnectableObservable_whenAssembled_shouldExecuteTheHook() { + + RxJavaPlugins.setOnConnectableObservableAssembly(connectableObservable -> { + hookCalled = true; + return connectableObservable; + }); + + ConnectableObservable.range(1, 10) + .publish() + .connect(); + assertTrue(hookCalled); + } + + @Test + public void givenFlowable_whenAssembled_shouldExecuteTheHook() { + + RxJavaPlugins.setOnFlowableAssembly(flowable -> { + hookCalled = true; + return flowable; + }); + + Flowable.range(1, 10); + assertTrue(hookCalled); + } + + @Test + public void givenFlowable_whenSubscribed_shouldExecuteTheHook() { + + RxJavaPlugins.setOnFlowableSubscribe((flowable, observer) -> { + hookCalled = true; + return observer; + }); + + Flowable.range(1, 10) + .test(); + assertTrue(hookCalled); + } + + @Test + public void givenConnectableFlowable_whenAssembled_shouldExecuteTheHook() { + + RxJavaPlugins.setOnConnectableFlowableAssembly(connectableFlowable -> { + hookCalled = true; + return connectableFlowable; + }); + + ConnectableFlowable.range(1, 10) + .publish() + .connect(); + assertTrue(hookCalled); + } + + @Test + public void givenParallel_whenAssembled_shouldExecuteTheHook() { + + RxJavaPlugins.setOnParallelAssembly(parallelFlowable -> { + hookCalled = true; + return parallelFlowable; + }); + + Flowable.range(1, 10) + .parallel(); + assertTrue(hookCalled); + } + + @Test + public void givenMaybe_whenAssembled_shouldExecuteTheHook() { + + RxJavaPlugins.setOnMaybeAssembly(maybe -> { + hookCalled = true; + return maybe; + }); + + Maybe.just(1); + assertTrue(hookCalled); + } + + @Test + public void givenMaybe_whenSubscribed_shouldExecuteTheHook() { + + RxJavaPlugins.setOnMaybeSubscribe((maybe, observer) -> { + hookCalled = true; + return observer; + }); + + Maybe.just(1) + .test(); + assertTrue(hookCalled); + } + + @Test + public void givenSingle_whenAssembled_shouldExecuteTheHook() { + + RxJavaPlugins.setOnSingleAssembly(single -> { + hookCalled = true; + return single; + }); + + Single.just(1); + assertTrue(hookCalled); + } + + @Test + public void givenSingle_whenSubscribed_shouldExecuteTheHook() { + + RxJavaPlugins.setOnSingleSubscribe((single, observer) -> { + hookCalled = true; + return observer; + }); + + Single.just(1) + .test(); + assertTrue(hookCalled); + } + + @Test + public void givenAnyScheduler_whenCalled_shouldExecuteTheHook() { + + RxJavaPlugins.setScheduleHandler((runnable) -> { + hookCalled = true; + return runnable; + }); + + Observable.range(1, 10) + .map(v -> v * 2) + .subscribeOn(Schedulers.single()) + .test(); + hookCalled = false; + Observable.range(1, 10) + .map(v -> v * 2) + .subscribeOn(Schedulers.computation()) + .test(); + assertTrue(hookCalled); + } + + @Test + public void givenComputationScheduler_whenCalled_shouldExecuteTheHooks() { + + RxJavaPlugins.setInitComputationSchedulerHandler((scheduler) -> { + initHookCalled = true; + return scheduler.call(); + }); + RxJavaPlugins.setComputationSchedulerHandler((scheduler) -> { + hookCalled = true; + return scheduler; + }); + + Observable.range(1, 10) + .map(v -> v * 2) + .subscribeOn(Schedulers.computation()) + .test(); + assertTrue(hookCalled && initHookCalled); + } + + @After + public void reset() { + initHookCalled = false; + hookCalled = false; + RxJavaPlugins.reset(); + } +} diff --git a/software-security/sql-injection-samples/pom.xml b/software-security/sql-injection-samples/pom.xml index 5b33c674d4..0a28a96a07 100644 --- a/software-security/sql-injection-samples/pom.xml +++ b/software-security/sql-injection-samples/pom.xml @@ -17,7 +17,6 @@ - org.springframework.boot spring-boot-starter-jdbc @@ -54,7 +53,6 @@ hibernate-jpamodelgen - diff --git a/spring-5-data-reactive/src/test/java/com/baeldung/reactive/repository/AccountCrudRepositoryIntegrationTest.java b/spring-5-data-reactive/src/test/java/com/baeldung/reactive/repository/AccountCrudRepositoryManualTest.java similarity index 97% rename from spring-5-data-reactive/src/test/java/com/baeldung/reactive/repository/AccountCrudRepositoryIntegrationTest.java rename to spring-5-data-reactive/src/test/java/com/baeldung/reactive/repository/AccountCrudRepositoryManualTest.java index f425826dce..d4b1d0eeda 100644 --- a/spring-5-data-reactive/src/test/java/com/baeldung/reactive/repository/AccountCrudRepositoryIntegrationTest.java +++ b/spring-5-data-reactive/src/test/java/com/baeldung/reactive/repository/AccountCrudRepositoryManualTest.java @@ -17,7 +17,7 @@ import static org.junit.Assert.assertNotNull; @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Spring5ReactiveApplication.class) -public class AccountCrudRepositoryIntegrationTest { +public class AccountCrudRepositoryManualTest { @Autowired AccountCrudRepository repository; diff --git a/spring-5-data-reactive/src/test/java/com/baeldung/reactive/repository/AccountMongoRepositoryIntegrationTest.java b/spring-5-data-reactive/src/test/java/com/baeldung/reactive/repository/AccountMongoRepositoryManualTest.java similarity index 97% rename from spring-5-data-reactive/src/test/java/com/baeldung/reactive/repository/AccountMongoRepositoryIntegrationTest.java rename to spring-5-data-reactive/src/test/java/com/baeldung/reactive/repository/AccountMongoRepositoryManualTest.java index bfa6a789b2..2ca075aa5e 100644 --- a/spring-5-data-reactive/src/test/java/com/baeldung/reactive/repository/AccountMongoRepositoryIntegrationTest.java +++ b/spring-5-data-reactive/src/test/java/com/baeldung/reactive/repository/AccountMongoRepositoryManualTest.java @@ -19,7 +19,7 @@ import static org.springframework.data.domain.ExampleMatcher.GenericPropertyMatc @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Spring5ReactiveApplication.class) -public class AccountMongoRepositoryIntegrationTest { +public class AccountMongoRepositoryManualTest { @Autowired AccountMongoRepository repository; diff --git a/spring-5-data-reactive/src/test/java/com/baeldung/reactive/repository/AccountRxJavaRepositoryIntegrationTest.java b/spring-5-data-reactive/src/test/java/com/baeldung/reactive/repository/AccountRxJavaRepositoryManualTest.java similarity index 97% rename from spring-5-data-reactive/src/test/java/com/baeldung/reactive/repository/AccountRxJavaRepositoryIntegrationTest.java rename to spring-5-data-reactive/src/test/java/com/baeldung/reactive/repository/AccountRxJavaRepositoryManualTest.java index e9b3eb1c40..d91acd24e2 100644 --- a/spring-5-data-reactive/src/test/java/com/baeldung/reactive/repository/AccountRxJavaRepositoryIntegrationTest.java +++ b/spring-5-data-reactive/src/test/java/com/baeldung/reactive/repository/AccountRxJavaRepositoryManualTest.java @@ -15,7 +15,7 @@ import static org.junit.Assert.assertNotNull; @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Spring5ReactiveApplication.class) -public class AccountRxJavaRepositoryIntegrationTest { +public class AccountRxJavaRepositoryManualTest { @Autowired AccountRxJavaRepository repository; diff --git a/spring-5-data-reactive/src/test/java/com/baeldung/reactive/template/AccountTemplateOperationsIntegrationTest.java b/spring-5-data-reactive/src/test/java/com/baeldung/reactive/template/AccountTemplateOperationsManualTest.java similarity index 97% rename from spring-5-data-reactive/src/test/java/com/baeldung/reactive/template/AccountTemplateOperationsIntegrationTest.java rename to spring-5-data-reactive/src/test/java/com/baeldung/reactive/template/AccountTemplateOperationsManualTest.java index 373da0e393..5fa0e39317 100644 --- a/spring-5-data-reactive/src/test/java/com/baeldung/reactive/template/AccountTemplateOperationsIntegrationTest.java +++ b/spring-5-data-reactive/src/test/java/com/baeldung/reactive/template/AccountTemplateOperationsManualTest.java @@ -16,7 +16,7 @@ import static org.junit.jupiter.api.Assertions.*; @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Spring5ReactiveApplication.class) -public class AccountTemplateOperationsIntegrationTest { +public class AccountTemplateOperationsManualTest { @Autowired AccountTemplateOperations accountTemplate; diff --git a/spring-5-mvc/README.md b/spring-5-mvc/README.md index fa9d48ab72..7e83077f54 100644 --- a/spring-5-mvc/README.md +++ b/spring-5-mvc/README.md @@ -2,4 +2,3 @@ - [Spring Boot and Kotlin](http://www.baeldung.com/spring-boot-kotlin) - [Spring MVC Streaming and SSE Request Processing](https://www.baeldung.com/spring-mvc-sse-streams) - [Overview and Need for DelegatingFilterProxy in Spring](https://www.baeldung.com/spring-delegating-filter-proxy) -- [A Controller, Service and DAO Example with Spring Boot and JSF](https://www.baeldung.com/jsf-spring-boot-controller-service-dao) diff --git a/spring-5-reactive/README.md b/spring-5-reactive/README.md index ef2f7d07eb..538a15c879 100644 --- a/spring-5-reactive/README.md +++ b/spring-5-reactive/README.md @@ -19,3 +19,4 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring - [Logging a Reactive Sequence](https://www.baeldung.com/spring-reactive-sequence-logging) - [Testing Reactive Streams Using StepVerifier and TestPublisher](https://www.baeldung.com/reactive-streams-step-verifier-test-publisher) - [Debugging Reactive Streams in Spring 5](https://www.baeldung.com/spring-debugging-reactive-streams) +- [Static Content in Spring WebFlux](https://www.baeldung.com/spring-webflux-static-content) diff --git a/spring-5-security-oauth/README.md b/spring-5-security-oauth/README.md index 5a444d4784..a5cec370c7 100644 --- a/spring-5-security-oauth/README.md +++ b/spring-5-security-oauth/README.md @@ -1,5 +1,5 @@ ## Relevant articles: -- [Spring Security 5 -OAuth2 Login](http://www.baeldung.com/spring-security-5-oauth2-login) +- [Spring Security 5 – OAuth2 Login](http://www.baeldung.com/spring-security-5-oauth2-login) - [Extracting Principal and Authorities using Spring Security OAuth](https://www.baeldung.com/spring-security-oauth-principal-authorities-extractor) - [Customizing Authorization and Token Requests with Spring Security 5.1 Client](https://www.baeldung.com/spring-security-custom-oauth-requests) diff --git a/spring-5-security-oauth/src/main/java/com/baeldung/cognito/CognitoWebConfiguration.java b/spring-5-security-oauth/src/main/java/com/baeldung/cognito/CognitoWebConfiguration.java new file mode 100644 index 0000000000..ae03e0a802 --- /dev/null +++ b/spring-5-security-oauth/src/main/java/com/baeldung/cognito/CognitoWebConfiguration.java @@ -0,0 +1,16 @@ +package com.baeldung.cognito; + +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; +import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +@PropertySource("cognito/application_cognito.yml") +public class CognitoWebConfiguration implements WebMvcConfigurer { + + @Override + public void addViewControllers(ViewControllerRegistry registry) { + registry.addViewController("/").setViewName("home"); + } +} diff --git a/spring-5-security-oauth/src/main/java/com/baeldung/cognito/SpringCognitoApplication.java b/spring-5-security-oauth/src/main/java/com/baeldung/cognito/SpringCognitoApplication.java new file mode 100644 index 0000000000..7f7b751cd9 --- /dev/null +++ b/spring-5-security-oauth/src/main/java/com/baeldung/cognito/SpringCognitoApplication.java @@ -0,0 +1,14 @@ +package com.baeldung.cognito; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.PropertySource; + +@SpringBootApplication +@PropertySource("cognito/application_cognito.yml") +public class SpringCognitoApplication { + + public static void main(String[] args) { + SpringApplication.run(SpringCognitoApplication.class, args); + } +} diff --git a/spring-5-security-oauth/src/main/resources/cognito/application_cognito.yml b/spring-5-security-oauth/src/main/resources/cognito/application_cognito.yml new file mode 100644 index 0000000000..0a28dbccb4 --- /dev/null +++ b/spring-5-security-oauth/src/main/resources/cognito/application_cognito.yml @@ -0,0 +1,15 @@ +spring: + security: + oauth2: + client: + registration: + cognito: + client-id: clientId + client-secret: clientSecret + scope: openid + redirectUriTemplate: "http://localhost:8080/login/oauth2/code/cognito" + clientName: cognito-client-name + provider: + cognito: + issuerUri: https://cognito-idp.{region}.amazonaws.com/{poolId} + usernameAttribute: cognito:username diff --git a/spring-5-security-oauth/src/main/resources/cognito/home.html b/spring-5-security-oauth/src/main/resources/cognito/home.html new file mode 100644 index 0000000000..f0bd9e52a8 --- /dev/null +++ b/spring-5-security-oauth/src/main/resources/cognito/home.html @@ -0,0 +1,32 @@ + + + + + + OAuth2 Cognito Demo + + + + + +
+
+
+

OAuth2 Spring Security Cognito Demo

+ +
+
+ Hello, ! +
+
+ + +
+
+
+ + diff --git a/spring-5-security-oauth/src/main/resources/cognito/style.css b/spring-5-security-oauth/src/main/resources/cognito/style.css new file mode 100644 index 0000000000..45190d6d70 --- /dev/null +++ b/spring-5-security-oauth/src/main/resources/cognito/style.css @@ -0,0 +1,9 @@ +.login { + background-color: #7289da; + color: #fff; +} + +.login:hover { + background-color: #697ec4; + color: #fff; +} diff --git a/spring-5-webflux/.gitignore b/spring-5-webflux/.gitignore new file mode 100644 index 0000000000..aa4871eeea --- /dev/null +++ b/spring-5-webflux/.gitignore @@ -0,0 +1,2 @@ +# Files # +*.log \ No newline at end of file diff --git a/spring-5-webflux/README.md b/spring-5-webflux/README.md new file mode 100644 index 0000000000..4345c8746b --- /dev/null +++ b/spring-5-webflux/README.md @@ -0,0 +1,5 @@ +## Relevant articles: + +- [Spring Boot Reactor Netty Configuration](https://www.baeldung.com/spring-boot-reactor-netty) +- [How to Return 404 with Spring WebFlux](https://www.baeldung.com/spring-webflux-404) +- [WebClient request with parameters](https://www.baeldung.com/webclient-request-with-parameters) diff --git a/spring-5-webflux/pom.xml b/spring-5-webflux/pom.xml new file mode 100644 index 0000000000..3306fd1729 --- /dev/null +++ b/spring-5-webflux/pom.xml @@ -0,0 +1,63 @@ + + + + 4.0.0 + com.baeldung + spring-5-webflux + 1.0-SNAPSHOT + spring-5-webflux + http://www.baeldung.com + + + com.baeldung + parent-boot-2 + 0.0.1-SNAPSHOT + ../parent-boot-2 + + + + + + org.springframework.boot + spring-boot-dependencies + ${spring-boot.version} + pom + import + + + + + + + org.springframework.boot + spring-boot-starter-webflux + + + + org.projectlombok + lombok + + + + org.springframework.boot + spring-boot-starter-test + test + + + + junit + junit + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/spring-5-webflux/src/main/java/com/baeldung/spring/responsestatus/ResponseStatusController.java b/spring-5-webflux/src/main/java/com/baeldung/spring/responsestatus/ResponseStatusController.java new file mode 100644 index 0000000000..bc4f628ab1 --- /dev/null +++ b/spring-5-webflux/src/main/java/com/baeldung/spring/responsestatus/ResponseStatusController.java @@ -0,0 +1,64 @@ +package com.baeldung.spring.responsestatus; + +import org.springframework.context.annotation.Bean; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.http.server.reactive.ServerHttpResponse; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.reactive.function.server.RouterFunction; +import org.springframework.web.reactive.function.server.RouterFunctions; +import org.springframework.web.reactive.function.server.ServerResponse; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import static org.springframework.web.reactive.function.server.RequestPredicates.GET; + +@RequestMapping("/statuses") +@RestController +public class ResponseStatusController { + + @GetMapping(value = "/ok", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + public Flux ok() { + return Flux.just("ok"); + } + + @GetMapping(value = "/no-content", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + @ResponseStatus(HttpStatus.NO_CONTENT) + public Flux noContent() { + return Flux.empty(); + } + + @GetMapping(value = "/accepted", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + public Flux accepted(ServerHttpResponse response) { + response.setStatusCode(HttpStatus.ACCEPTED); + return Flux.just("accepted"); + } + + @GetMapping(value = "/bad-request") + public Mono badRequest() { + return Mono.error(new IllegalArgumentException()); + } + + @ResponseStatus(value = HttpStatus.BAD_REQUEST, reason = "Illegal arguments") + @ExceptionHandler(IllegalArgumentException.class) + public void illegalArgument() { + + } + + @GetMapping(value = "/unauthorized") + public ResponseEntity> unathorized() { + return ResponseEntity + .status(HttpStatus.UNAUTHORIZED) + .header("X-Reason", "user-invalid") + .body(Mono.just("unauthorized")); + } + + @Bean + public RouterFunction notFound() { + return RouterFunctions.route(GET("/statuses/not-found"), request -> ServerResponse + .notFound() + .build()); + } + +} diff --git a/spring-5-webflux/src/main/java/com/baeldung/spring/responsestatus/SpringResponseStatusApp.java b/spring-5-webflux/src/main/java/com/baeldung/spring/responsestatus/SpringResponseStatusApp.java new file mode 100644 index 0000000000..1d90511d9d --- /dev/null +++ b/spring-5-webflux/src/main/java/com/baeldung/spring/responsestatus/SpringResponseStatusApp.java @@ -0,0 +1,12 @@ +package com.baeldung.spring.responsestatus; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SpringResponseStatusApp { + + public static void main(String[] args) { + SpringApplication.run(SpringResponseStatusApp.class, args); + } +} diff --git a/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/CustomNettyWebServerFactory.java b/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/CustomNettyWebServerFactory.java new file mode 100644 index 0000000000..f9de3b4006 --- /dev/null +++ b/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/CustomNettyWebServerFactory.java @@ -0,0 +1,36 @@ +package com.baeldung.spring.serverconfig; + +import io.netty.channel.EventLoopGroup; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory; +import org.springframework.boot.web.embedded.netty.NettyServerCustomizer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import reactor.netty.http.server.HttpServer; + +@Configuration +@Profile("skipAutoConfig") +public class CustomNettyWebServerFactory { + + @Bean + public NettyReactiveWebServerFactory nettyReactiveWebServerFactory() { + NettyReactiveWebServerFactory webServerFactory = new NettyReactiveWebServerFactory(); + webServerFactory.addServerCustomizers(new EventLoopNettyCustomizer()); + return webServerFactory; + } + + private static class EventLoopNettyCustomizer implements NettyServerCustomizer { + + @Override + public HttpServer apply(HttpServer httpServer) { + EventLoopGroup parentGroup = new NioEventLoopGroup(); + EventLoopGroup childGroup = new NioEventLoopGroup(); + return httpServer + .tcpConfiguration(tcpServer -> tcpServer.bootstrap( + serverBootstrap -> serverBootstrap.group(parentGroup, childGroup).channel(NioServerSocketChannel.class) + )); + } + } +} diff --git a/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/GreetingController.java b/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/GreetingController.java new file mode 100644 index 0000000000..990ea5cf83 --- /dev/null +++ b/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/GreetingController.java @@ -0,0 +1,23 @@ +package com.baeldung.spring.serverconfig; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import reactor.core.publisher.Mono; + +@RestController +@RequestMapping("/greet") +public class GreetingController { + + private final GreetingService greetingService; + + public GreetingController(GreetingService greetingService) { + this.greetingService = greetingService; + } + + @GetMapping("/{name}") + private Mono greet(@PathVariable String name) { + return greetingService.greet(name); + } +} diff --git a/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/GreetingService.java b/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/GreetingService.java new file mode 100644 index 0000000000..a6243b2bd0 --- /dev/null +++ b/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/GreetingService.java @@ -0,0 +1,12 @@ +package com.baeldung.spring.serverconfig; + +import org.springframework.stereotype.Service; +import reactor.core.publisher.Mono; + +@Service +public class GreetingService { + + public Mono greet(String name) { + return Mono.just("Greeting " + name); + } +} diff --git a/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/NettyWebServerFactoryPortCustomizer.java b/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/NettyWebServerFactoryPortCustomizer.java new file mode 100644 index 0000000000..fdde130286 --- /dev/null +++ b/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/NettyWebServerFactoryPortCustomizer.java @@ -0,0 +1,30 @@ +package com.baeldung.spring.serverconfig; + +import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory; +import org.springframework.boot.web.embedded.netty.NettyServerCustomizer; +import org.springframework.boot.web.server.WebServerFactoryCustomizer; +import org.springframework.stereotype.Component; +import reactor.netty.http.server.HttpServer; + +@Component +public class NettyWebServerFactoryPortCustomizer implements WebServerFactoryCustomizer { + + @Override + public void customize(NettyReactiveWebServerFactory serverFactory) { + serverFactory.addServerCustomizers(new PortCustomizer(8443)); + } + + private static class PortCustomizer implements NettyServerCustomizer { + + private final int port; + + private PortCustomizer(int port) { + this.port = port; + } + + @Override + public HttpServer apply(HttpServer httpServer) { + return httpServer.port(port); + } + } +} diff --git a/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/NettyWebServerFactorySslCustomizer.java b/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/NettyWebServerFactorySslCustomizer.java new file mode 100644 index 0000000000..cf4e5ac8ea --- /dev/null +++ b/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/NettyWebServerFactorySslCustomizer.java @@ -0,0 +1,26 @@ +package com.baeldung.spring.serverconfig; + +import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory; +import org.springframework.boot.web.embedded.netty.SslServerCustomizer; +import org.springframework.boot.web.server.Http2; +import org.springframework.boot.web.server.Ssl; +import org.springframework.boot.web.server.WebServerFactoryCustomizer; +import org.springframework.stereotype.Component; + +@Component +public class NettyWebServerFactorySslCustomizer implements WebServerFactoryCustomizer { + + @Override + public void customize(NettyReactiveWebServerFactory serverFactory) { + Ssl ssl = new Ssl(); + ssl.setEnabled(true); + ssl.setKeyStore("classpath:sample.jks"); + ssl.setKeyAlias("alias"); + ssl.setKeyPassword("password"); + ssl.setKeyStorePassword("secret"); + Http2 http2 = new Http2(); + http2.setEnabled(false); + serverFactory.addServerCustomizers(new SslServerCustomizer(ssl, http2, null)); + serverFactory.setPort(8443); + } +} diff --git a/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/ServerConfigApplication.java b/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/ServerConfigApplication.java new file mode 100644 index 0000000000..b4f6006be3 --- /dev/null +++ b/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/ServerConfigApplication.java @@ -0,0 +1,12 @@ +package com.baeldung.spring.serverconfig; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class ServerConfigApplication { + + public static void main(String[] args) { + SpringApplication.run(ServerConfigApplication.class, args); + } +} diff --git a/spring-5-webflux/src/main/java/com/baeldung/spring/webclientrequests/SpringWebClientRequestsApp.java b/spring-5-webflux/src/main/java/com/baeldung/spring/webclientrequests/SpringWebClientRequestsApp.java new file mode 100644 index 0000000000..314fe2fdf9 --- /dev/null +++ b/spring-5-webflux/src/main/java/com/baeldung/spring/webclientrequests/SpringWebClientRequestsApp.java @@ -0,0 +1,12 @@ +package com.baeldung.spring.webclientrequests; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SpringWebClientRequestsApp { + + public static void main(String[] args) { + SpringApplication.run(SpringWebClientRequestsApp.class, args); + } +} diff --git a/spring-5-webflux/src/main/resources/logback.xml b/spring-5-webflux/src/main/resources/logback.xml new file mode 100644 index 0000000000..48b68c6bf1 --- /dev/null +++ b/spring-5-webflux/src/main/resources/logback.xml @@ -0,0 +1,31 @@ + + + + + + %black(%d{ISO8601}) %highlight(%-5level) [%blue(%t)] %yellow(%C{1.}): %msg%n%throwable + + + + + + netty-access.log + + %msg%n + + + + + + + + + + + + + + + + diff --git a/spring-5-webflux/src/main/resources/sample.jks b/spring-5-webflux/src/main/resources/sample.jks new file mode 100644 index 0000000000..6aa9a28053 Binary files /dev/null and b/spring-5-webflux/src/main/resources/sample.jks differ diff --git a/spring-5-webflux/src/test/java/com/baeldung/spring/responsestatus/ResponseStatusControllerLiveTest.java b/spring-5-webflux/src/test/java/com/baeldung/spring/responsestatus/ResponseStatusControllerLiveTest.java new file mode 100644 index 0000000000..4c6708e423 --- /dev/null +++ b/spring-5-webflux/src/test/java/com/baeldung/spring/responsestatus/ResponseStatusControllerLiveTest.java @@ -0,0 +1,70 @@ +package com.baeldung.spring.responsestatus; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.reactive.server.WebTestClient; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +public class ResponseStatusControllerLiveTest { + + @Autowired + private WebTestClient testClient; + + @Test + public void whenCallRest_thenStatusIsOk() { + testClient.get() + .uri("/statuses/ok") + .exchange() + .expectStatus() + .isOk(); + } + + @Test + public void whenCallRest_thenStatusIsNoContent() { + testClient.get() + .uri("/statuses/no-content") + .exchange() + .expectStatus() + .isNoContent(); + } + + @Test + public void whenCallRest_thenStatusIsAccepted() { + testClient.get() + .uri("/statuses/accepted") + .exchange() + .expectStatus() + .isAccepted(); + } + + @Test + public void whenCallRest_thenStatusIsBadRequest() { + testClient.get() + .uri("/statuses/bad-request") + .exchange() + .expectStatus() + .isBadRequest(); + } + + @Test + public void whenCallRest_thenStatusIsUnauthorized() { + testClient.get() + .uri("/statuses/unauthorized") + .exchange() + .expectStatus() + .isUnauthorized(); + } + + @Test + public void whenCallRest_thenStatusIsNotFound() { + testClient.get() + .uri("/statuses/not-found") + .exchange() + .expectStatus() + .isNotFound(); + } +} diff --git a/spring-5-webflux/src/test/java/com/baeldung/spring/serverconfig/GreetingControllerIntegrationTest.java b/spring-5-webflux/src/test/java/com/baeldung/spring/serverconfig/GreetingControllerIntegrationTest.java new file mode 100644 index 0000000000..ce156beb3f --- /dev/null +++ b/spring-5-webflux/src/test/java/com/baeldung/spring/serverconfig/GreetingControllerIntegrationTest.java @@ -0,0 +1,41 @@ +package com.baeldung.spring.serverconfig; + +import static org.mockito.Mockito.when; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.reactive.server.WebTestClient; +import reactor.core.publisher.Mono; + +@RunWith(SpringRunner.class) +@WebFluxTest +public class GreetingControllerIntegrationTest { + + @Autowired + private WebTestClient webClient; + + @MockBean + private GreetingService greetingService; + + private final String name = "Baeldung"; + + @Before + public void setUp() { + when(greetingService.greet(name)).thenReturn(Mono.just("Greeting Baeldung")); + } + + @Test + public void shouldGreet() { + webClient.get().uri("/greet/{name}", name) + .exchange() + .expectStatus() + .isOk() + .expectBody(String.class) + .isEqualTo("Greeting Baeldung"); + } +} diff --git a/spring-5-webflux/src/test/java/com/baeldung/spring/serverconfig/GreetingLiveTest.java b/spring-5-webflux/src/test/java/com/baeldung/spring/serverconfig/GreetingLiveTest.java new file mode 100644 index 0000000000..2400272c6e --- /dev/null +++ b/spring-5-webflux/src/test/java/com/baeldung/spring/serverconfig/GreetingLiveTest.java @@ -0,0 +1,57 @@ +package com.baeldung.spring.serverconfig; + +import io.netty.handler.ssl.SslContext; +import io.netty.handler.ssl.SslContextBuilder; +import io.netty.handler.ssl.util.InsecureTrustManagerFactory; +import javax.net.ssl.SSLException; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.http.client.reactive.ReactorClientHttpConnector; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.reactive.server.WebTestClient; +import org.springframework.test.web.reactive.server.WebTestClient.ResponseSpec; +import reactor.netty.http.client.HttpClient; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = WebEnvironment.DEFINED_PORT) +@DirtiesContext +public class GreetingLiveTest { + + private static final String BASE_URL = "https://localhost:8443"; + + private WebTestClient webTestClient; + + @Before + public void setup() throws SSLException { + webTestClient = WebTestClient.bindToServer(getConnector()) + .baseUrl(BASE_URL) + .build(); + } + + @Test + public void shouldGreet() { + final String name = "Baeldung"; + + ResponseSpec response = webTestClient.get() + .uri("/greet/{name}", name) + .exchange(); + + response.expectStatus() + .isOk() + .expectBody(String.class) + .isEqualTo("Greeting Baeldung"); + } + + private ReactorClientHttpConnector getConnector() throws SSLException { + SslContext sslContext = SslContextBuilder + .forClient() + .trustManager(InsecureTrustManagerFactory.INSTANCE) + .build(); + HttpClient httpClient = HttpClient.create().secure(t -> t.sslContext(sslContext)); + return new ReactorClientHttpConnector(httpClient); + } +} diff --git a/spring-5-webflux/src/test/java/com/baeldung/spring/serverconfig/GreetingSkipAutoConfigLiveTest.java b/spring-5-webflux/src/test/java/com/baeldung/spring/serverconfig/GreetingSkipAutoConfigLiveTest.java new file mode 100644 index 0000000000..45918dfd70 --- /dev/null +++ b/spring-5-webflux/src/test/java/com/baeldung/spring/serverconfig/GreetingSkipAutoConfigLiveTest.java @@ -0,0 +1,8 @@ +package com.baeldung.spring.serverconfig; + +import org.springframework.test.context.ActiveProfiles; + +@ActiveProfiles("skipAutoConfig") +public class GreetingSkipAutoConfigLiveTest extends GreetingLiveTest { + +} diff --git a/spring-5-webflux/src/test/java/com/baeldung/spring/webclientrequests/WebClientRequestsUnitTest.java b/spring-5-webflux/src/test/java/com/baeldung/spring/webclientrequests/WebClientRequestsUnitTest.java new file mode 100644 index 0000000000..8919daa9fb --- /dev/null +++ b/spring-5-webflux/src/test/java/com/baeldung/spring/webclientrequests/WebClientRequestsUnitTest.java @@ -0,0 +1,164 @@ +package com.baeldung.spring.webclientrequests; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.web.reactive.function.client.ClientRequest; +import org.springframework.web.reactive.function.client.ClientResponse; +import org.springframework.web.reactive.function.client.ExchangeFunction; +import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.web.util.DefaultUriBuilderFactory; +import reactor.core.publisher.Mono; + +import static org.mockito.Mockito.*; + +@RunWith(SpringRunner.class) +@WebFluxTest +public class WebClientRequestsUnitTest { + + private static final String BASE_URL = "https://example.com"; + + private WebClient webClient; + + @Captor + private ArgumentCaptor argumentCaptor; + + private ExchangeFunction exchangeFunction; + + @Before + public void init() { + MockitoAnnotations.initMocks(this); + this.exchangeFunction = mock(ExchangeFunction.class); + ClientResponse mockResponse = mock(ClientResponse.class); + when(this.exchangeFunction.exchange(this.argumentCaptor.capture())).thenReturn(Mono.just(mockResponse)); + this.webClient = WebClient + .builder() + .baseUrl(BASE_URL) + .exchangeFunction(exchangeFunction) + .build(); + } + + + @Test + public void whenCallSimpleURI_thenURIMatched() { + this.webClient.get() + .uri("/products") + .retrieve(); + verifyCalledUrl("/products"); + } + + @Test + public void whenCallSinglePathSegmentUri_thenURIMatched() { + this.webClient.get() + .uri(uriBuilder -> uriBuilder + .path("/products/{id}") + .build(2)) + .retrieve(); + verifyCalledUrl("/products/2"); + } + + @Test + public void whenCallMultiplePathSegmentsUri_thenURIMatched() { + this.webClient.get() + .uri(uriBuilder -> uriBuilder + .path("/products/{id}/attributes/{attributeId}") + .build(2, 13)) + .retrieve(); + verifyCalledUrl("/products/2/attributes/13"); + } + + @Test + public void whenCallSingleQueryParams_thenURIMatched() { + this.webClient.get() + .uri(uriBuilder -> uriBuilder + .path("/products/") + .queryParam("name", "AndroidPhone") + .queryParam("color", "black") + .queryParam("deliveryDate", "13/04/2019") + .build()) + .retrieve(); + verifyCalledUrl("/products/?name=AndroidPhone&color=black&deliveryDate=13/04/2019"); + } + + @Test + public void whenCallSingleQueryParamsPlaceholders_thenURIMatched() { + this.webClient.get() + .uri(uriBuilder -> uriBuilder + .path("/products/") + .queryParam("name", "{title}") + .queryParam("color", "{authorId}") + .queryParam("deliveryDate", "{date}") + .build("AndroidPhone", "black", "13/04/2019")) + .retrieve(); + verifyCalledUrl("/products/?name=AndroidPhone&color=black&deliveryDate=13%2F04%2F2019"); + } + + @Test + public void whenCallArrayQueryParamsBrackets_thenURIMatched() { + this.webClient.get() + .uri(uriBuilder -> uriBuilder + .path("/products/") + .queryParam("tag[]", "Snapdragon", "NFC") + .build()) + .retrieve(); + verifyCalledUrl("/products/?tag%5B%5D=Snapdragon&tag%5B%5D=NFC"); + } + + + @Test + public void whenCallArrayQueryParams_thenURIMatched() { + this.webClient.get() + .uri(uriBuilder -> uriBuilder + .path("/products/") + .queryParam("category", "Phones", "Tablets") + .build()) + .retrieve(); + verifyCalledUrl("/products/?category=Phones&category=Tablets"); + } + + @Test + public void whenCallArrayQueryParamsComma_thenURIMatched() { + this.webClient.get() + .uri(uriBuilder -> uriBuilder + .path("/products/") + .queryParam("category", String.join(",", "Phones", "Tablets")) + .build()) + .retrieve(); + verifyCalledUrl("/products/?category=Phones,Tablets"); + } + + @Test + public void whenUriComponentEncoding_thenQueryParamsNotEscaped() { + DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory(BASE_URL); + factory.setEncodingMode(DefaultUriBuilderFactory.EncodingMode.URI_COMPONENT); + this.webClient = WebClient + .builder() + .uriBuilderFactory(factory) + .baseUrl(BASE_URL) + .exchangeFunction(exchangeFunction) + .build(); + this.webClient.get() + .uri(uriBuilder -> uriBuilder + .path("/products/") + .queryParam("name", "AndroidPhone") + .queryParam("color", "black") + .queryParam("deliveryDate", "13/04/2019") + .build()) + .retrieve(); + verifyCalledUrl("/products/?name=AndroidPhone&color=black&deliveryDate=13/04/2019"); + } + + private void verifyCalledUrl(String relativeUrl) { + ClientRequest request = this.argumentCaptor.getValue(); + Assert.assertEquals(String.format("%s%s", BASE_URL, relativeUrl), request.url().toString()); + Mockito.verify(this.exchangeFunction).exchange(request); + verifyNoMoreInteractions(this.exchangeFunction); + } +} diff --git a/spring-5-webflux/src/test/resources/logback-test.xml b/spring-5-webflux/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..12cedf5952 --- /dev/null +++ b/spring-5-webflux/src/test/resources/logback-test.xml @@ -0,0 +1,13 @@ + + + + + + %black(%d{ISO8601}) %highlight(%-5level) [%blue(%t)] %yellow(%C{1.}): %msg%n%throwable + + + + + + + diff --git a/spring-akka/pom.xml b/spring-akka/pom.xml index 92b3f1162d..d8b943b5ae 100644 --- a/spring-akka/pom.xml +++ b/spring-akka/pom.xml @@ -19,7 +19,7 @@ com.typesafe.akka - akka-actor_2.11 + akka-actor_${scala.version} ${akka.version} @@ -44,6 +44,7 @@ 4.3.4.RELEASE 2.4.14 + 2.11 \ No newline at end of file diff --git a/spring-all/README.md b/spring-all/README.md index 81dd435007..b0805e5477 100644 --- a/spring-all/README.md +++ b/spring-all/README.md @@ -14,7 +14,7 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring - [Properties with Spring and Spring Boot](http://www.baeldung.com/properties-with-spring) - checkout the `org.baeldung.properties` package for all scenarios of properties injection and usage - [Spring Profiles](http://www.baeldung.com/spring-profiles) - [A Spring Custom Annotation for a Better DAO](http://www.baeldung.com/spring-annotation-bean-pre-processor) -- [What's New in Spring 4.3?](http://www.baeldung.com/whats-new-in-spring-4-3) +- [What’s New in Spring 4.3?](http://www.baeldung.com/whats-new-in-spring-4-3) - [Running Setup Data on Startup in Spring](http://www.baeldung.com/running-setup-logic-on-startup-in-spring) - [Quick Guide to Spring Controllers](http://www.baeldung.com/spring-controllers) - [Quick Guide to Spring Bean Scopes](http://www.baeldung.com/spring-bean-scopes) @@ -22,7 +22,6 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring - [A Guide to the Spring Task Scheduler](http://www.baeldung.com/spring-task-scheduler) - [Guide to Spring Retry](http://www.baeldung.com/spring-retry) - [Custom Scope in Spring](http://www.baeldung.com/spring-custom-scope) -- [New in Guava 21 common.util.concurrent](http://www.baeldung.com/guava-21-util-concurrent) - [A CLI with Spring Shell](http://www.baeldung.com/spring-shell-cli) - [JasperReports with Spring](http://www.baeldung.com/spring-jasper) - [Model, ModelMap, and ModelView in Spring MVC](http://www.baeldung.com/spring-mvc-model-model-map-model-view) @@ -34,3 +33,5 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring - [Spring @Primary Annotation](http://www.baeldung.com/spring-primary) - [Spring Events](https://www.baeldung.com/spring-events) - [Spring Null-Safety Annotations](https://www.baeldung.com/spring-null-safety-annotations) +- [Spring JDBC](https://www.baeldung.com/spring-jdbc-jdbctemplate) +- [Using @Autowired in Abstract Classes](https://www.baeldung.com/spring-autowired-abstract-class) diff --git a/spring-all/pom.xml b/spring-all/pom.xml index 5872fbdac5..8c88efb970 100644 --- a/spring-all/pom.xml +++ b/spring-all/pom.xml @@ -1,5 +1,5 @@ + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 spring-all 0.1-SNAPSHOT @@ -47,12 +47,16 @@ org.springframework spring-websocket - - + + org.springframework spring-messaging - - + + + javax.annotation + javax.annotation-api + ${annotation-api.version} + org.springframework @@ -227,13 +231,13 @@
- + org.baeldung.sample.App 5.0.6.RELEASE 1.2.0.RELEASE - + 1.3.2 5.2.5.Final diff --git a/spring-all/src/main/java/org/baeldung/properties/spring/PropertiesWithJavaConfig.java b/spring-all/src/main/java/org/baeldung/properties/spring/PropertiesWithJavaConfig.java index 08626bb4d2..6589143a94 100644 --- a/spring-all/src/main/java/org/baeldung/properties/spring/PropertiesWithJavaConfig.java +++ b/spring-all/src/main/java/org/baeldung/properties/spring/PropertiesWithJavaConfig.java @@ -7,6 +7,7 @@ import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; @Configuration @PropertySource("classpath:foo.properties") +@PropertySource("classpath:bar.properties") public class PropertiesWithJavaConfig { public PropertiesWithJavaConfig() { diff --git a/spring-all/src/main/java/org/baeldung/sampleabstract/BallService.java b/spring-all/src/main/java/org/baeldung/sampleabstract/BallService.java new file mode 100644 index 0000000000..9a75de7fa1 --- /dev/null +++ b/spring-all/src/main/java/org/baeldung/sampleabstract/BallService.java @@ -0,0 +1,28 @@ +package org.baeldung.sampleabstract; + +import org.springframework.beans.factory.annotation.Autowired; + +import javax.annotation.PostConstruct; + +public abstract class BallService { + + private RuleRepository ruleRepository; + + private LogRepository logRepository; + + public BallService(RuleRepository ruleRepository) { + this.ruleRepository = ruleRepository; + } + + @Autowired + public final void setLogRepository(LogRepository logRepository) { + this.logRepository = logRepository; + } + + @PostConstruct + public void afterInitialize() { + + System.out.println(ruleRepository.toString()); + System.out.println(logRepository.toString()); + } +} diff --git a/spring-all/src/main/java/org/baeldung/sampleabstract/BasketballService.java b/spring-all/src/main/java/org/baeldung/sampleabstract/BasketballService.java new file mode 100644 index 0000000000..c117231d3c --- /dev/null +++ b/spring-all/src/main/java/org/baeldung/sampleabstract/BasketballService.java @@ -0,0 +1,13 @@ +package org.baeldung.sampleabstract; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class BasketballService extends BallService { + + @Autowired + public BasketballService(RuleRepository ruleRepository) { + super(ruleRepository); + } +} diff --git a/spring-all/src/main/java/org/baeldung/sampleabstract/DemoApp.java b/spring-all/src/main/java/org/baeldung/sampleabstract/DemoApp.java new file mode 100644 index 0000000000..615d354ecf --- /dev/null +++ b/spring-all/src/main/java/org/baeldung/sampleabstract/DemoApp.java @@ -0,0 +1,18 @@ +package org.baeldung.sampleabstract; + +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ComponentScan(basePackages = "org.baeldung.sampleabstract") +public class DemoApp { + + + public static void main(String[] args) { + + ApplicationContext applicationContext = new AnnotationConfigApplicationContext(DemoApp.class); + } + +} diff --git a/spring-all/src/main/java/org/baeldung/sampleabstract/LogRepository.java b/spring-all/src/main/java/org/baeldung/sampleabstract/LogRepository.java new file mode 100644 index 0000000000..3a65671493 --- /dev/null +++ b/spring-all/src/main/java/org/baeldung/sampleabstract/LogRepository.java @@ -0,0 +1,12 @@ +package org.baeldung.sampleabstract; + +import org.springframework.stereotype.Component; + +@Component +public class LogRepository { + + @Override + public String toString() { + return "logRepository"; + } +} diff --git a/spring-all/src/main/java/org/baeldung/sampleabstract/RuleRepository.java b/spring-all/src/main/java/org/baeldung/sampleabstract/RuleRepository.java new file mode 100644 index 0000000000..fd42178ab6 --- /dev/null +++ b/spring-all/src/main/java/org/baeldung/sampleabstract/RuleRepository.java @@ -0,0 +1,12 @@ +package org.baeldung.sampleabstract; + +import org.springframework.stereotype.Component; + +@Component +public class RuleRepository { + + @Override + public String toString() { + return "ruleRepository"; + } +} diff --git a/spring-all/src/main/resources/configForProperties.xml b/spring-all/src/main/resources/configForProperties.xml index 0f766665eb..459aea3ec6 100644 --- a/spring-all/src/main/resources/configForProperties.xml +++ b/spring-all/src/main/resources/configForProperties.xml @@ -7,7 +7,7 @@ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd" > - + diff --git a/spring-all/src/test/java/org/baeldung/properties/multiple/MultiplePropertiesJavaConfigIntegrationTest.java b/spring-all/src/test/java/org/baeldung/properties/multiple/MultiplePropertiesJavaConfigIntegrationTest.java new file mode 100644 index 0000000000..9cb41c20f7 --- /dev/null +++ b/spring-all/src/test/java/org/baeldung/properties/multiple/MultiplePropertiesJavaConfigIntegrationTest.java @@ -0,0 +1,25 @@ +package org.baeldung.properties.multiple; + +import org.baeldung.properties.spring.PropertiesWithJavaConfig; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; + +import static org.assertj.core.api.Assertions.assertThat; + +@SpringJUnitConfig(PropertiesWithJavaConfig.class) +public class MultiplePropertiesJavaConfigIntegrationTest { + + @Value("${key.something}") + private String something; + + @Value("${key.something2}") + private String something2; + + + @Test + public void whenReadInjectedValues_thenGetCorrectValues() { + assertThat(something).isEqualTo("val"); + assertThat(something2).isEqualTo("val2"); + } +} diff --git a/spring-all/src/test/java/org/baeldung/properties/multiple/MultiplePropertiesXmlConfigIntegrationTest.java b/spring-all/src/test/java/org/baeldung/properties/multiple/MultiplePropertiesXmlConfigIntegrationTest.java new file mode 100644 index 0000000000..b4f81f3541 --- /dev/null +++ b/spring-all/src/test/java/org/baeldung/properties/multiple/MultiplePropertiesXmlConfigIntegrationTest.java @@ -0,0 +1,21 @@ +package org.baeldung.properties.multiple; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; + +import static org.assertj.core.api.Assertions.assertThat; + +@SpringJUnitConfig(locations = "classpath:configForProperties.xml") +public class MultiplePropertiesXmlConfigIntegrationTest { + + @Value("${key.something}") private String something; + + @Value("${key.something2}") private String something2; + + @Test + public void whenReadInjectedValues_thenGetCorrectValues() { + assertThat(something).isEqualTo("val"); + assertThat(something2).isEqualTo("val2"); + } +} diff --git a/spring-batch/README.md b/spring-batch/README.md index 737e7e13f5..ddd830cd47 100644 --- a/spring-batch/README.md +++ b/spring-batch/README.md @@ -6,5 +6,5 @@ ### Relevant Articles: - [Introduction to Spring Batch](http://www.baeldung.com/introduction-to-spring-batch) - [Spring Batch using Partitioner](http://www.baeldung.com/spring-batch-partitioner) -- [Spring Batch Tasklets vs Chunks Approach](http://www.baeldung.com/spring-batch-tasklet-chunk) +- [Spring Batch – Tasklets vs Chunks](http://www.baeldung.com/spring-batch-tasklet-chunk) - [How to Trigger and Stop a Scheduled Spring Batch Job](http://www.baeldung.com/spring-batch-start-stop-job) diff --git a/spring-boot-angular-ecommerce/src/main/frontend/package.json b/spring-boot-angular-ecommerce/src/main/frontend/package.json index 958e9f1023..17363ef961 100644 --- a/spring-boot-angular-ecommerce/src/main/frontend/package.json +++ b/spring-boot-angular-ecommerce/src/main/frontend/package.json @@ -7,7 +7,7 @@ "build": "ng build", "postbuild": "npm run deploy", "predeploy": "rimraf ../resources/static/ && mkdirp ../resources/static", - "deploy": "copyfiles -f dist/** ../resources/static", + "deploy": "copyfiles -f dist/frontend/** ../resources/static", "test": "ng test", "lint": "ng lint", "e2e": "ng e2e" diff --git a/spring-boot-angular/README.md b/spring-boot-angular/README.md new file mode 100644 index 0000000000..cfc1ea69f4 --- /dev/null +++ b/spring-boot-angular/README.md @@ -0,0 +1,3 @@ +### Relevant Articles: +- [Building a Web Application with Spring Boot and Angular](https://www.baeldung.com/spring-boot-angular-web) + diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/.angular-cli.json b/spring-boot-angular/angularclient/.angular-cli.json similarity index 100% rename from spring-boot-angular/src/main/java/com/baeldung/angularclient/.angular-cli.json rename to spring-boot-angular/angularclient/.angular-cli.json diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/.editorconfig b/spring-boot-angular/angularclient/.editorconfig similarity index 100% rename from spring-boot-angular/src/main/java/com/baeldung/angularclient/.editorconfig rename to spring-boot-angular/angularclient/.editorconfig diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/.gitignore b/spring-boot-angular/angularclient/.gitignore similarity index 100% rename from spring-boot-angular/src/main/java/com/baeldung/angularclient/.gitignore rename to spring-boot-angular/angularclient/.gitignore diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/README.md b/spring-boot-angular/angularclient/README.md similarity index 100% rename from spring-boot-angular/src/main/java/com/baeldung/angularclient/README.md rename to spring-boot-angular/angularclient/README.md diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/e2e/app.e2e-spec.ts b/spring-boot-angular/angularclient/e2e/app.e2e-spec.ts similarity index 100% rename from spring-boot-angular/src/main/java/com/baeldung/angularclient/e2e/app.e2e-spec.ts rename to spring-boot-angular/angularclient/e2e/app.e2e-spec.ts diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/e2e/app.po.ts b/spring-boot-angular/angularclient/e2e/app.po.ts similarity index 100% rename from spring-boot-angular/src/main/java/com/baeldung/angularclient/e2e/app.po.ts rename to spring-boot-angular/angularclient/e2e/app.po.ts diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/e2e/tsconfig.e2e.json b/spring-boot-angular/angularclient/e2e/tsconfig.e2e.json similarity index 100% rename from spring-boot-angular/src/main/java/com/baeldung/angularclient/e2e/tsconfig.e2e.json rename to spring-boot-angular/angularclient/e2e/tsconfig.e2e.json diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/karma.conf.js b/spring-boot-angular/angularclient/karma.conf.js similarity index 100% rename from spring-boot-angular/src/main/java/com/baeldung/angularclient/karma.conf.js rename to spring-boot-angular/angularclient/karma.conf.js diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/package-lock.json b/spring-boot-angular/angularclient/package-lock.json similarity index 100% rename from spring-boot-angular/src/main/java/com/baeldung/angularclient/package-lock.json rename to spring-boot-angular/angularclient/package-lock.json diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/package.json b/spring-boot-angular/angularclient/package.json similarity index 100% rename from spring-boot-angular/src/main/java/com/baeldung/angularclient/package.json rename to spring-boot-angular/angularclient/package.json diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/protractor.conf.js b/spring-boot-angular/angularclient/protractor.conf.js similarity index 100% rename from spring-boot-angular/src/main/java/com/baeldung/angularclient/protractor.conf.js rename to spring-boot-angular/angularclient/protractor.conf.js diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/app/app-routing.module.ts b/spring-boot-angular/angularclient/src/app/app-routing.module.ts similarity index 100% rename from spring-boot-angular/src/main/java/com/baeldung/angularclient/src/app/app-routing.module.ts rename to spring-boot-angular/angularclient/src/app/app-routing.module.ts diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/app/app.component.css b/spring-boot-angular/angularclient/src/app/app.component.css similarity index 100% rename from spring-boot-angular/src/main/java/com/baeldung/angularclient/src/app/app.component.css rename to spring-boot-angular/angularclient/src/app/app.component.css diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/app/app.component.html b/spring-boot-angular/angularclient/src/app/app.component.html similarity index 100% rename from spring-boot-angular/src/main/java/com/baeldung/angularclient/src/app/app.component.html rename to spring-boot-angular/angularclient/src/app/app.component.html diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/app/app.component.spec.ts b/spring-boot-angular/angularclient/src/app/app.component.spec.ts similarity index 100% rename from spring-boot-angular/src/main/java/com/baeldung/angularclient/src/app/app.component.spec.ts rename to spring-boot-angular/angularclient/src/app/app.component.spec.ts diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/app/app.component.ts b/spring-boot-angular/angularclient/src/app/app.component.ts similarity index 100% rename from spring-boot-angular/src/main/java/com/baeldung/angularclient/src/app/app.component.ts rename to spring-boot-angular/angularclient/src/app/app.component.ts diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/app/app.module.ts b/spring-boot-angular/angularclient/src/app/app.module.ts similarity index 100% rename from spring-boot-angular/src/main/java/com/baeldung/angularclient/src/app/app.module.ts rename to spring-boot-angular/angularclient/src/app/app.module.ts diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/app/model/user.ts b/spring-boot-angular/angularclient/src/app/model/user.ts similarity index 100% rename from spring-boot-angular/src/main/java/com/baeldung/angularclient/src/app/model/user.ts rename to spring-boot-angular/angularclient/src/app/model/user.ts diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/app/service/user.service.spec.ts b/spring-boot-angular/angularclient/src/app/service/user.service.spec.ts similarity index 100% rename from spring-boot-angular/src/main/java/com/baeldung/angularclient/src/app/service/user.service.spec.ts rename to spring-boot-angular/angularclient/src/app/service/user.service.spec.ts diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/app/service/user.service.ts b/spring-boot-angular/angularclient/src/app/service/user.service.ts similarity index 100% rename from spring-boot-angular/src/main/java/com/baeldung/angularclient/src/app/service/user.service.ts rename to spring-boot-angular/angularclient/src/app/service/user.service.ts diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/app/user-form/user-form.component.css b/spring-boot-angular/angularclient/src/app/user-form/user-form.component.css similarity index 100% rename from spring-boot-angular/src/main/java/com/baeldung/angularclient/src/app/user-form/user-form.component.css rename to spring-boot-angular/angularclient/src/app/user-form/user-form.component.css diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/app/user-form/user-form.component.html b/spring-boot-angular/angularclient/src/app/user-form/user-form.component.html similarity index 100% rename from spring-boot-angular/src/main/java/com/baeldung/angularclient/src/app/user-form/user-form.component.html rename to spring-boot-angular/angularclient/src/app/user-form/user-form.component.html diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/app/user-form/user-form.component.spec.ts b/spring-boot-angular/angularclient/src/app/user-form/user-form.component.spec.ts similarity index 100% rename from spring-boot-angular/src/main/java/com/baeldung/angularclient/src/app/user-form/user-form.component.spec.ts rename to spring-boot-angular/angularclient/src/app/user-form/user-form.component.spec.ts diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/app/user-form/user-form.component.ts b/spring-boot-angular/angularclient/src/app/user-form/user-form.component.ts similarity index 100% rename from spring-boot-angular/src/main/java/com/baeldung/angularclient/src/app/user-form/user-form.component.ts rename to spring-boot-angular/angularclient/src/app/user-form/user-form.component.ts diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/app/user-list/user-list.component.css b/spring-boot-angular/angularclient/src/app/user-list/user-list.component.css similarity index 100% rename from spring-boot-angular/src/main/java/com/baeldung/angularclient/src/app/user-list/user-list.component.css rename to spring-boot-angular/angularclient/src/app/user-list/user-list.component.css diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/app/user-list/user-list.component.html b/spring-boot-angular/angularclient/src/app/user-list/user-list.component.html similarity index 100% rename from spring-boot-angular/src/main/java/com/baeldung/angularclient/src/app/user-list/user-list.component.html rename to spring-boot-angular/angularclient/src/app/user-list/user-list.component.html diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/app/user-list/user-list.component.spec.ts b/spring-boot-angular/angularclient/src/app/user-list/user-list.component.spec.ts similarity index 100% rename from spring-boot-angular/src/main/java/com/baeldung/angularclient/src/app/user-list/user-list.component.spec.ts rename to spring-boot-angular/angularclient/src/app/user-list/user-list.component.spec.ts diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/app/user-list/user-list.component.ts b/spring-boot-angular/angularclient/src/app/user-list/user-list.component.ts similarity index 100% rename from spring-boot-angular/src/main/java/com/baeldung/angularclient/src/app/user-list/user-list.component.ts rename to spring-boot-angular/angularclient/src/app/user-list/user-list.component.ts diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/assets/.gitkeep b/spring-boot-angular/angularclient/src/assets/.gitkeep similarity index 100% rename from spring-boot-angular/src/main/java/com/baeldung/angularclient/src/assets/.gitkeep rename to spring-boot-angular/angularclient/src/assets/.gitkeep diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/environments/environment.prod.ts b/spring-boot-angular/angularclient/src/environments/environment.prod.ts similarity index 100% rename from spring-boot-angular/src/main/java/com/baeldung/angularclient/src/environments/environment.prod.ts rename to spring-boot-angular/angularclient/src/environments/environment.prod.ts diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/environments/environment.ts b/spring-boot-angular/angularclient/src/environments/environment.ts similarity index 100% rename from spring-boot-angular/src/main/java/com/baeldung/angularclient/src/environments/environment.ts rename to spring-boot-angular/angularclient/src/environments/environment.ts diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/favicon.ico b/spring-boot-angular/angularclient/src/favicon.ico similarity index 100% rename from spring-boot-angular/src/main/java/com/baeldung/angularclient/src/favicon.ico rename to spring-boot-angular/angularclient/src/favicon.ico diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/index.html b/spring-boot-angular/angularclient/src/index.html similarity index 100% rename from spring-boot-angular/src/main/java/com/baeldung/angularclient/src/index.html rename to spring-boot-angular/angularclient/src/index.html diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/main.ts b/spring-boot-angular/angularclient/src/main.ts similarity index 100% rename from spring-boot-angular/src/main/java/com/baeldung/angularclient/src/main.ts rename to spring-boot-angular/angularclient/src/main.ts diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/polyfills.ts b/spring-boot-angular/angularclient/src/polyfills.ts similarity index 100% rename from spring-boot-angular/src/main/java/com/baeldung/angularclient/src/polyfills.ts rename to spring-boot-angular/angularclient/src/polyfills.ts diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/styles.css b/spring-boot-angular/angularclient/src/styles.css similarity index 100% rename from spring-boot-angular/src/main/java/com/baeldung/angularclient/src/styles.css rename to spring-boot-angular/angularclient/src/styles.css diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/tsconfig.app.json b/spring-boot-angular/angularclient/src/tsconfig.app.json similarity index 100% rename from spring-boot-angular/src/main/java/com/baeldung/angularclient/src/tsconfig.app.json rename to spring-boot-angular/angularclient/src/tsconfig.app.json diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/tsconfig.spec.json b/spring-boot-angular/angularclient/src/tsconfig.spec.json similarity index 100% rename from spring-boot-angular/src/main/java/com/baeldung/angularclient/src/tsconfig.spec.json rename to spring-boot-angular/angularclient/src/tsconfig.spec.json diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/typings.d.ts b/spring-boot-angular/angularclient/src/typings.d.ts similarity index 100% rename from spring-boot-angular/src/main/java/com/baeldung/angularclient/src/typings.d.ts rename to spring-boot-angular/angularclient/src/typings.d.ts diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/tsconfig.json b/spring-boot-angular/angularclient/tsconfig.json similarity index 100% rename from spring-boot-angular/src/main/java/com/baeldung/angularclient/tsconfig.json rename to spring-boot-angular/angularclient/tsconfig.json diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/tslint.json b/spring-boot-angular/angularclient/tslint.json similarity index 100% rename from spring-boot-angular/src/main/java/com/baeldung/angularclient/tslint.json rename to spring-boot-angular/angularclient/tslint.json diff --git a/spring-boot-angular/src/main/java/com/baeldung/application/controllers/UserController.java b/spring-boot-angular/src/main/java/com/baeldung/application/controllers/UserController.java index c101ed771f..14c90d5b10 100644 --- a/spring-boot-angular/src/main/java/com/baeldung/application/controllers/UserController.java +++ b/spring-boot-angular/src/main/java/com/baeldung/application/controllers/UserController.java @@ -1,6 +1,6 @@ package com.baeldung.application.controllers; -import com.application.entities.User; +import com.baeldung.application.entities.User; import com.baeldung.application.repositories.UserRepository; import java.util.List; import org.springframework.web.bind.annotation.CrossOrigin; diff --git a/spring-boot-angular/src/main/java/com/baeldung/application/repositories/UserRepository.java b/spring-boot-angular/src/main/java/com/baeldung/application/repositories/UserRepository.java index f8ef5a4c0c..5a81cadcbe 100644 --- a/spring-boot-angular/src/main/java/com/baeldung/application/repositories/UserRepository.java +++ b/spring-boot-angular/src/main/java/com/baeldung/application/repositories/UserRepository.java @@ -6,5 +6,4 @@ import org.springframework.stereotype.Repository; import org.springframework.web.bind.annotation.CrossOrigin; @Repository -@CrossOrigin(origins = "http://localhost:4200") public interface UserRepository extends CrudRepository{} diff --git a/spring-boot-angular/src/main/java/com/baeldung/pom.xml b/spring-boot-angular/src/main/java/com/baeldung/pom.xml new file mode 100644 index 0000000000..ac86f932b4 --- /dev/null +++ b/spring-boot-angular/src/main/java/com/baeldung/pom.xml @@ -0,0 +1,50 @@ + + + 4.0.0 + com.baeldung.springbootangular + spring-boot-angular + 1.0 + jar + Spring Boot Angular Application + + + org.springframework.boot + spring-boot-starter-parent + 2.1.3.RELEASE + + + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.boot + spring-boot-starter-web + + + com.h2database + h2 + runtime + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + 1.8 + + \ No newline at end of file diff --git a/spring-boot-bootstrap/README.md b/spring-boot-bootstrap/README.md index 70fcd90118..6a88f25bd7 100644 --- a/spring-boot-bootstrap/README.md +++ b/spring-boot-bootstrap/README.md @@ -1,6 +1,5 @@ ### Relevant Articles: - [Spring Boot Tutorial – Bootstrap a Simple Application](http://www.baeldung.com/spring-boot-start) -- [Spring Boot Dependency Management with a Custom Parent](http://www.baeldung.com/spring-boot-dependency-management-custom-parent) - [Thin JARs with Spring Boot](http://www.baeldung.com/spring-boot-thin-jar) - [Deploying a Spring Boot Application to Cloud Foundry](https://www.baeldung.com/spring-boot-app-deploy-to-cloud-foundry) - [Deploy a Spring Boot Application to Google App Engine](https://www.baeldung.com/spring-boot-google-app-engine) diff --git a/spring-boot-data/README.md b/spring-boot-data/README.md index 21f7303c48..d93b8c3e93 100644 --- a/spring-boot-data/README.md +++ b/spring-boot-data/README.md @@ -1,2 +1,2 @@ ### Relevant Articles: -- [Formatting JSON Dates in Spring ](https://www.baeldung.com/spring-boot-formatting-json-dates) \ No newline at end of file +- [Formatting JSON Dates in Spring Boot](https://www.baeldung.com/spring-boot-formatting-json-dates) diff --git a/spring-boot-data/pom.xml b/spring-boot-data/pom.xml index 9ef4cc69c8..8735a54e7b 100644 --- a/spring-boot-data/pom.xml +++ b/spring-boot-data/pom.xml @@ -119,4 +119,4 @@ 2.2.4 - \ No newline at end of file + diff --git a/spring-boot-exceptions/.gitignore b/spring-boot-exceptions/.gitignore new file mode 100644 index 0000000000..153c9335eb --- /dev/null +++ b/spring-boot-exceptions/.gitignore @@ -0,0 +1,29 @@ +HELP.md +/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/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +/build/ + +### VS Code ### +.vscode/ diff --git a/spring-boot-exceptions/pom.xml b/spring-boot-exceptions/pom.xml new file mode 100644 index 0000000000..105f60e295 --- /dev/null +++ b/spring-boot-exceptions/pom.xml @@ -0,0 +1,37 @@ + + + 4.0.0 + + + com.baeldung + parent-boot-2 + 0.0.1-SNAPSHOT + ../parent-boot-2 + + + com.baeldung + spring-boot-exceptions + 0.0.4-SNAPSHOT + pass-exception-to-client-json-spring-boot + Baeldung article code on how to pass exceptions to client in JSON format using Spring Boot + + + 1.8 + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-test + test + + + + diff --git a/spring-boot-exceptions/src/main/java/com/baeldung/jsonexception/CustomException.java b/spring-boot-exceptions/src/main/java/com/baeldung/jsonexception/CustomException.java new file mode 100644 index 0000000000..f1a1d94f54 --- /dev/null +++ b/spring-boot-exceptions/src/main/java/com/baeldung/jsonexception/CustomException.java @@ -0,0 +1,11 @@ +package com.baeldung.jsonexception; + +public class CustomException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + public CustomException() { + super("Custom exception message."); + } + +} \ No newline at end of file diff --git a/spring-boot-exceptions/src/main/java/com/baeldung/jsonexception/ErrorHandler.java b/spring-boot-exceptions/src/main/java/com/baeldung/jsonexception/ErrorHandler.java new file mode 100644 index 0000000000..a890dfa3a2 --- /dev/null +++ b/spring-boot-exceptions/src/main/java/com/baeldung/jsonexception/ErrorHandler.java @@ -0,0 +1,19 @@ +package com.baeldung.jsonexception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ControllerAdvice +@ResponseBody +public class ErrorHandler { + + @ExceptionHandler(CustomException.class) + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + public CustomException handleCustomException(CustomException ce) { + return ce; + } + +} \ No newline at end of file diff --git a/spring-boot-exceptions/src/main/java/com/baeldung/jsonexception/JsonErrorApplication.java b/spring-boot-exceptions/src/main/java/com/baeldung/jsonexception/JsonErrorApplication.java new file mode 100644 index 0000000000..188584bd7c --- /dev/null +++ b/spring-boot-exceptions/src/main/java/com/baeldung/jsonexception/JsonErrorApplication.java @@ -0,0 +1,13 @@ +package com.baeldung.jsonexception; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class JsonErrorApplication { + + public static void main(String[] args) { + SpringApplication.run(JsonErrorApplication.class, args); + } + +} \ No newline at end of file diff --git a/spring-boot-exceptions/src/main/java/com/baeldung/jsonexception/MainController.java b/spring-boot-exceptions/src/main/java/com/baeldung/jsonexception/MainController.java new file mode 100644 index 0000000000..5d73c239a4 --- /dev/null +++ b/spring-boot-exceptions/src/main/java/com/baeldung/jsonexception/MainController.java @@ -0,0 +1,14 @@ +package com.baeldung.jsonexception; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; + +@Controller +public class MainController { + + @GetMapping("/") + public void index() throws CustomException { + throw new CustomException(); + } + +} \ No newline at end of file diff --git a/spring-boot-exceptions/src/main/resources/application.properties b/spring-boot-exceptions/src/main/resources/application.properties new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/spring-boot-exceptions/src/main/resources/application.properties @@ -0,0 +1 @@ + diff --git a/spring-boot-exceptions/src/main/resources/static/.gitignore b/spring-boot-exceptions/src/main/resources/static/.gitignore new file mode 100644 index 0000000000..5e7d2734cf --- /dev/null +++ b/spring-boot-exceptions/src/main/resources/static/.gitignore @@ -0,0 +1,4 @@ +# Ignore everything in this directory +* +# Except this file +!.gitignore diff --git a/spring-boot-exceptions/src/main/resources/templates/.gitignore b/spring-boot-exceptions/src/main/resources/templates/.gitignore new file mode 100644 index 0000000000..5e7d2734cf --- /dev/null +++ b/spring-boot-exceptions/src/main/resources/templates/.gitignore @@ -0,0 +1,4 @@ +# Ignore everything in this directory +* +# Except this file +!.gitignore diff --git a/spring-boot-exceptions/src/test/java/com/baeldung/jsonexception/MainControllerIntegrationTest.java b/spring-boot-exceptions/src/test/java/com/baeldung/jsonexception/MainControllerIntegrationTest.java new file mode 100644 index 0000000000..77e71b7d21 --- /dev/null +++ b/spring-boot-exceptions/src/test/java/com/baeldung/jsonexception/MainControllerIntegrationTest.java @@ -0,0 +1,19 @@ +package com.baeldung.jsonexception; + +import org.junit.Test; + +import com.baeldung.jsonexception.CustomException; +import com.baeldung.jsonexception.MainController; + +public class MainControllerIntegrationTest { + + @Test(expected = CustomException.class) + public void givenIndex_thenCustomException() throws CustomException { + + MainController mainController = new MainController(); + + mainController.index(); + + } + +} \ No newline at end of file diff --git a/spring-boot-exceptions/src/test/java/com/baeldung/jsonexception/SpringContextIntegrationTest.java b/spring-boot-exceptions/src/test/java/com/baeldung/jsonexception/SpringContextIntegrationTest.java new file mode 100644 index 0000000000..aa91e242ab --- /dev/null +++ b/spring-boot-exceptions/src/test/java/com/baeldung/jsonexception/SpringContextIntegrationTest.java @@ -0,0 +1,16 @@ +package com.baeldung.jsonexception; + +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 SpringContextIntegrationTest { + + @Test + public void contextLoads() { + } + +} diff --git a/spring-boot-flowable/README.md b/spring-boot-flowable/README.md new file mode 100644 index 0000000000..8fb90d953b --- /dev/null +++ b/spring-boot-flowable/README.md @@ -0,0 +1,3 @@ +### Relevant articles + +- [Introduction to Flowable](http://www.baeldung.com/flowable) diff --git a/spring-boot-flowable/pom.xml b/spring-boot-flowable/pom.xml new file mode 100644 index 0000000000..f9531a1e6a --- /dev/null +++ b/spring-boot-flowable/pom.xml @@ -0,0 +1,58 @@ + + + 4.0.0 + spring-boot-flowable + war + spring-boot-flowable + Spring Boot Flowable Module + + parent-boot-2 + com.baeldung + 0.0.1-SNAPSHOT + ../parent-boot-2 + + + + org.springframework.boot + spring-boot-starter-web + + + com.h2database + h2 + runtime + + + org.flowable + flowable-spring-boot-starter-rest + ${flowable.version} + + + org.flowable + flowable-spring-boot-starter-actuator + ${flowable.version} + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.jupiter + junit-jupiter-engine + test + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + 6.4.1 + + \ No newline at end of file diff --git a/spring-boot-flowable/src/main/java/com/baeldung/Application.java b/spring-boot-flowable/src/main/java/com/baeldung/Application.java new file mode 100644 index 0000000000..37dbe7dab8 --- /dev/null +++ b/spring-boot-flowable/src/main/java/com/baeldung/Application.java @@ -0,0 +1,13 @@ +package com.baeldung; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} diff --git a/spring-boot-flowable/src/main/java/com/baeldung/controller/ArticleWorkflowController.java b/spring-boot-flowable/src/main/java/com/baeldung/controller/ArticleWorkflowController.java new file mode 100644 index 0000000000..3087d30af4 --- /dev/null +++ b/spring-boot-flowable/src/main/java/com/baeldung/controller/ArticleWorkflowController.java @@ -0,0 +1,32 @@ +package com.baeldung.controller; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +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.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import com.baeldung.domain.Approval; +import com.baeldung.domain.Article; +import com.baeldung.service.ArticleWorkflowService; + +@RestController +public class ArticleWorkflowController { + @Autowired + private ArticleWorkflowService service; + @PostMapping("/submit") + public void submit(@RequestBody Article article) { + service.startProcess(article); + } + @GetMapping("/tasks") + public List
getTasks(@RequestParam String assignee) { + return service.getTasks(assignee); + } + @PostMapping("/review") + public void review(@RequestBody Approval approval) { + service.submitReview(approval); + } +} \ No newline at end of file diff --git a/spring-boot-flowable/src/main/java/com/baeldung/domain/Approval.java b/spring-boot-flowable/src/main/java/com/baeldung/domain/Approval.java new file mode 100644 index 0000000000..b0c9c99437 --- /dev/null +++ b/spring-boot-flowable/src/main/java/com/baeldung/domain/Approval.java @@ -0,0 +1,24 @@ +package com.baeldung.domain; + +public class Approval { + + private String id; + private boolean status; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public boolean isStatus() { + return status; + } + + public void setStatus(boolean status) { + this.status = status; + } + +} diff --git a/spring-boot-flowable/src/main/java/com/baeldung/domain/Article.java b/spring-boot-flowable/src/main/java/com/baeldung/domain/Article.java new file mode 100644 index 0000000000..efa2eb431e --- /dev/null +++ b/spring-boot-flowable/src/main/java/com/baeldung/domain/Article.java @@ -0,0 +1,52 @@ +package com.baeldung.domain; + +public class Article { + + private String id; + private String author; + private String url; + + public Article() { + } + + public Article(String author, String url) { + this.author = author; + this.url = url; + } + + public Article(String id, String author, String url) { + this.id = id; + this.author = author; + this.url = url; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + @Override + public String toString() { + return ("[" + this.author + " " + this.url + "]"); + } + +} diff --git a/spring-boot-flowable/src/main/java/com/baeldung/service/ArticleWorkflowService.java b/spring-boot-flowable/src/main/java/com/baeldung/service/ArticleWorkflowService.java new file mode 100644 index 0000000000..b1e2a92354 --- /dev/null +++ b/spring-boot-flowable/src/main/java/com/baeldung/service/ArticleWorkflowService.java @@ -0,0 +1,55 @@ +package com.baeldung.service; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.flowable.engine.RuntimeService; +import org.flowable.engine.TaskService; +import org.flowable.task.api.Task; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.baeldung.domain.Approval; +import com.baeldung.domain.Article; + +@Service +public class ArticleWorkflowService { + @Autowired + private RuntimeService runtimeService; + @Autowired + private TaskService taskService; + + @Transactional + public void startProcess(Article article) { + Map variables = new HashMap(); + variables.put("author", article.getAuthor()); + variables.put("url", article.getUrl()); + runtimeService.startProcessInstanceByKey("articleReview", variables); + } + + @Transactional + public List
getTasks(String assignee) { + List tasks = taskService.createTaskQuery() + .taskCandidateGroup(assignee) + .list(); + + List
articles = tasks.stream() + .map(task -> { + Map variables = taskService.getVariables(task.getId()); + return new Article( + task.getId(), (String) variables.get("author"), (String) variables.get("url")); + }) + .collect(Collectors.toList()); + return articles; + } + + @Transactional + public void submitReview(Approval approval) { + Map variables = new HashMap(); + variables.put("approved", approval.isStatus()); + taskService.complete(approval.getId(), variables); + } +} \ No newline at end of file diff --git a/spring-boot-flowable/src/main/java/com/baeldung/service/PublishArticleService.java b/spring-boot-flowable/src/main/java/com/baeldung/service/PublishArticleService.java new file mode 100644 index 0000000000..b43f1dccdb --- /dev/null +++ b/spring-boot-flowable/src/main/java/com/baeldung/service/PublishArticleService.java @@ -0,0 +1,10 @@ +package com.baeldung.service; + +import org.flowable.engine.delegate.DelegateExecution; +import org.flowable.engine.delegate.JavaDelegate; + +public class PublishArticleService implements JavaDelegate { + public void execute(DelegateExecution execution) { + System.out.println("Publishing the approved article."); + } +} diff --git a/spring-boot-flowable/src/main/java/com/baeldung/service/SendMailService.java b/spring-boot-flowable/src/main/java/com/baeldung/service/SendMailService.java new file mode 100644 index 0000000000..f80b16748f --- /dev/null +++ b/spring-boot-flowable/src/main/java/com/baeldung/service/SendMailService.java @@ -0,0 +1,10 @@ +package com.baeldung.service; + +import org.flowable.engine.delegate.DelegateExecution; +import org.flowable.engine.delegate.JavaDelegate; + +public class SendMailService implements JavaDelegate { + public void execute(DelegateExecution execution) { + System.out.println("Sending rejection mail to author."); + } +} diff --git a/spring-boot-flowable/src/main/resources/application.properties b/spring-boot-flowable/src/main/resources/application.properties new file mode 100644 index 0000000000..c3afcaa0b5 --- /dev/null +++ b/spring-boot-flowable/src/main/resources/application.properties @@ -0,0 +1 @@ +management.endpoint.flowable.enabled=true \ No newline at end of file diff --git a/spring-boot-flowable/src/main/resources/processes/article-workflow.bpmn20.xml b/spring-boot-flowable/src/main/resources/processes/article-workflow.bpmn20.xml new file mode 100644 index 0000000000..6bf210dcee --- /dev/null +++ b/spring-boot-flowable/src/main/resources/processes/article-workflow.bpmn20.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/spring-boot-flowable/src/test/java/com/baeldung/processes/ArticleWorkflowUnitTest.java b/spring-boot-flowable/src/test/java/com/baeldung/processes/ArticleWorkflowUnitTest.java new file mode 100644 index 0000000000..ef5453623a --- /dev/null +++ b/spring-boot-flowable/src/test/java/com/baeldung/processes/ArticleWorkflowUnitTest.java @@ -0,0 +1,40 @@ +package com.baeldung.processes; + +import static org.junit.Assert.assertEquals; + +import java.util.HashMap; +import java.util.Map; + +import org.flowable.engine.RuntimeService; +import org.flowable.engine.TaskService; +import org.flowable.engine.test.Deployment; +import org.flowable.spring.impl.test.FlowableSpringExtension; +import org.flowable.task.api.Task; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +@ExtendWith(FlowableSpringExtension.class) +@ExtendWith(SpringExtension.class) +public class ArticleWorkflowUnitTest { + @Autowired + private RuntimeService runtimeService; + @Autowired + private TaskService taskService; + @Test + @Deployment(resources = { "processes/article-workflow.bpmn20.xml" }) + void articleApprovalTest() { + Map variables = new HashMap(); + variables.put("author", "test@baeldung.com"); + variables.put("url", "http://baeldung.com/dummy"); + runtimeService.startProcessInstanceByKey("articleReview", variables); + Task task = taskService.createTaskQuery() + .singleResult(); + assertEquals("Review the submitted tutorial", task.getName()); + variables.put("approved", true); + taskService.complete(task.getId(), variables); + assertEquals(0, runtimeService.createProcessInstanceQuery() + .count()); + } +} \ No newline at end of file diff --git a/spring-boot-mvc-birt/README.md b/spring-boot-mvc-birt/README.md new file mode 100644 index 0000000000..9fe3d94e2a --- /dev/null +++ b/spring-boot-mvc-birt/README.md @@ -0,0 +1,3 @@ +### Relevant Articles + +- [BIRT Reporting with Spring Boot](https://www.baeldung.com/birt-reports-spring-boot) diff --git a/spring-boot-mvc-birt/pom.xml b/spring-boot-mvc-birt/pom.xml new file mode 100644 index 0000000000..8f41e8410a --- /dev/null +++ b/spring-boot-mvc-birt/pom.xml @@ -0,0 +1,83 @@ + + + 4.0.0 + com.baeldung + spring-boot-mvc-birt + spring-boot-mvc-birt + 0.0.1-SNAPSHOT + jar + Module For Spring Boot Integration with BIRT + + org.springframework.boot + spring-boot-starter-parent + 2.1.1.RELEASE + + + + + org.springframework.boot + spring-boot-starter + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-logging + + + ch.qos.logback + logback-classic + + + + + + org.springframework.boot + spring-boot-starter-test + test + + + + com.innoventsolutions.birt.runtime + org.eclipse.birt.runtime_4.8.0-20180626 + 4.8.0 + + + + log4j + log4j + 1.2.17 + + + + org.projectlombok + lombok + 1.18.6 + provided + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + 2.1.1.RELEASE + com.baeldung.birt.engine.ReportEngineApplication + 1.8 + 1.8 + + + diff --git a/spring-boot-mvc-birt/reports/csv_data_report.rptdesign b/spring-boot-mvc-birt/reports/csv_data_report.rptdesign new file mode 100644 index 0000000000..f390c5e69b --- /dev/null +++ b/spring-boot-mvc-birt/reports/csv_data_report.rptdesign @@ -0,0 +1,2032 @@ + + + Eclipse BIRT Designer Version 4.7.0.v201706222054 + new_report + + + queryText + 5 + + + HOME + 4 + + + URI + 4 + + + DELIMTYPE + 4 + + + CHARSET + 4 + + + INCLCOLUMNNAME + 4 + + + INCLTYPELINE + 4 + + + TRAILNULLCOLS + 4 + + + OdaConnProfileName + 4 + + + OdaConnProfileStorePath + 4 + + + in + /templates/blank_report.gif + ltr + 96 + + + reports/data.csv + COMMA + UTF-8 + YES + NO + NO + + + + + nulls lowest + + + Student + dimension + Student + + + Math + measure + Math + + + Geography + measure + Geography + + + History + measure + History + + + + + + + 1 + Student + string + + + 2 + Math + integer + + + 3 + Geography + integer + + + 4 + History + integer + + + + Data Source + + + 1 + Student + Student + string + 12 + + + 2 + Math + Math + integer + 12 + + + 3 + Geography + Geography + integer + 12 + + + 4 + History + History + integer + 12 + + + + + + 2.0 + + + + + + + Studen + 1 + + 12 + -1 + -1 + Unknown + + + Studen + + + + + + + Math + 2 + + 12 + -1 + -1 + Unknown + + + Math + + + + + + + Geography + 3 + + 12 + -1 + -1 + Unknown + + + Geography + + + + + + + History + 4 + + 12 + -1 + -1 + Unknown + + + History + + + + + + + +]]> + + + + + + + + + + + + 7.947916666666667in + + 2.15625in + + + + + 2 + 1 + + + 2.6.1 + Bar Chart + Side-by-side + + + + 0.0 + 0.0 + 0.0 + 0.0 + + + 3.0 + 3.0 + 3.0 + 3.0 + + -1 + -1 + -1 + -1 + + + 1 + + 255 + 0 + 0 + 0 + + false + + true + + + + + 0.0 + 0.0 + 0.0 + 0.0 + + + 3.0 + 3.0 + 3.0 + 3.0 + + -1 + -1 + -1 + -1 + + + 1 + + 255 + 0 + 0 + 0 + + false + + true + 5 + 5 + + + + 0 + + 255 + 0 + 0 + 0 + + false + + + 0.0 + 0.0 + 0.0 + 0.0 + + + + + + 0.0 + 0.0 + 0.0 + 0.0 + + + 3.0 + 3.0 + 3.0 + 3.0 + + -1 + -1 + -1 + -1 + + + 1 + + 255 + 0 + 0 + 0 + + false + + true + + + + 0 + + 255 + 0 + 0 + 0 + + false + + + 2.0 + 2.0 + 2.0 + 2.0 + + + + + + + + + Vertical + Top_Bottom + + + 1 + + 255 + 0 + 0 + 0 + + true + + Right + Series + + <Caption> + <Value></Value> + <Font> + <Alignment/> + </Font> + </Caption> + <Background xsi:type="attribute:ColorDefinition"> + <Transparency>0</Transparency> + <Red>255</Red> + <Green>255</Green> + <Blue>255</Blue> + </Background> + <Outline> + <Style>Solid</Style> + <Thickness>1</Thickness> + <Color> + <Transparency>255</Transparency> + <Red>0</Red> + <Green>0</Green> + <Blue>0</Blue> + </Color> + <Visible>false</Visible> + </Outline> + <Insets> + <Top>0.0</Top> + <Left>2.0</Left> + <Bottom>0.0</Bottom> + <Right>3.0</Right> + </Insets> + <Visible>false</Visible> + + Above + false + + + 0.0 + 0.0 + 572.25 + 286.125 + + + 3.0 + 3.0 + 3.0 + 3.0 + + -1 + -1 + -1 + -1 + + + 1 + + 255 + 0 + 0 + 0 + + false + + true + + Two_Dimensional + Points + 10.0 + + enable.area.alt + false + + + + A, B, C + + + 5,4,12 + 0 + + + 10.0,8.0,24.0 + 1 + + + 15.0,12.0,36.0 + 2 + + + + ToggleSerieVisibility + + + + This chart contains no data. + + + Center + Center + + + + + 64 + 127 + 127 + 127 + + + + 128 + 127 + 127 + 127 + + true + + + 10.0 + 10.0 + 10.0 + 10.0 + + false + + + Text + + <Caption> + <Value>X-Axis Title</Value> + <Font> + <Size>14.0</Size> + <Bold>true</Bold> + <Alignment> + <horizontalAlignment>Center</horizontalAlignment> + <verticalAlignment>Center</verticalAlignment> + </Alignment> + </Font> + </Caption> + <Background xsi:type="attribute:ColorDefinition"> + <Transparency>0</Transparency> + <Red>255</Red> + <Green>255</Green> + <Blue>255</Blue> + </Background> + <Outline> + <Style>Solid</Style> + <Thickness>1</Thickness> + <Color> + <Transparency>255</Transparency> + <Red>0</Red> + <Green>0</Green> + <Blue>0</Blue> + </Color> + </Outline> + <Insets> + <Top>0.0</Top> + <Left>2.0</Left> + <Bottom>0.0</Bottom> + <Right>3.0</Right> + </Insets> + <Visible>false</Visible> + + Below + + Linear + + <Caption> + <Value>Y-Axis Title</Value> + <Font> + <Size>14.0</Size> + <Bold>true</Bold> + <Alignment> + <horizontalAlignment>Center</horizontalAlignment> + <verticalAlignment>Center</verticalAlignment> + </Alignment> + </Font> + </Caption> + <Background xsi:type="attribute:ColorDefinition"> + <Transparency>0</Transparency> + <Red>255</Red> + <Green>255</Green> + <Blue>255</Blue> + </Background> + <Outline> + <Style>Solid</Style> + <Thickness>1</Thickness> + <Color> + <Transparency>255</Transparency> + <Red>0</Red> + <Green>0</Green> + <Blue>0</Blue> + </Color> + </Outline> + <Insets> + <Top>0.0</Top> + <Left>2.0</Left> + <Bottom>0.0</Bottom> + <Right>3.0</Right> + </Insets> + <Visible>false</Visible> + + Left + + + + + Numeric + + + + + 255 + 80 + 166 + 218 + + + 255 + 242 + 88 + 106 + + + 255 + 232 + 172 + 57 + + + 255 + 128 + 255 + 128 + + + 255 + 64 + 128 + 128 + + + 255 + 128 + 128 + 192 + + + 255 + 170 + 85 + 85 + + + 255 + 128 + 128 + 0 + + + 255 + 192 + 192 + 192 + + + 255 + 255 + 255 + 128 + + + 255 + 128 + 192 + 128 + + + 255 + 7 + 146 + 94 + + + 255 + 0 + 128 + 255 + + + 255 + 255 + 128 + 192 + + + 255 + 0 + 255 + 255 + + + 255 + 255 + 128 + 128 + + + 255 + 0 + 128 + 192 + + + 255 + 255 + 0 + 255 + + + 255 + 128 + 64 + 64 + + + 255 + 255 + 128 + 64 + + + 255 + 80 + 240 + 120 + + + 255 + 0 + 64 + 128 + + + 255 + 128 + 0 + 64 + + + 255 + 255 + 0 + 128 + + + 255 + 128 + 128 + 64 + + + 255 + 128 + 128 + 128 + + + 255 + 255 + 128 + 255 + + + 255 + 0 + 64 + 0 + + + 255 + 0 + 0 + 0 + + + 255 + 255 + 255 + 255 + + + 255 + 255 + 128 + 0 + + + + true + + + row["Geography"] + + Text + Sum + + + Geo + + + Orthogonal_Value + + , + + Outside + false + + onmouseover + + Show_Tooltip + + + 200 + + + + Rectangle + + + Text + Sum + + + + + + + Numeric + + + + + 255 + 242 + 88 + 106 + + + 255 + 232 + 172 + 57 + + + 255 + 128 + 255 + 128 + + + 255 + 64 + 128 + 128 + + + 255 + 128 + 128 + 192 + + + 255 + 170 + 85 + 85 + + + 255 + 128 + 128 + 0 + + + 255 + 192 + 192 + 192 + + + 255 + 255 + 255 + 128 + + + 255 + 128 + 192 + 128 + + + 255 + 7 + 146 + 94 + + + 255 + 0 + 128 + 255 + + + 255 + 255 + 128 + 192 + + + 255 + 0 + 255 + 255 + + + 255 + 255 + 128 + 128 + + + 255 + 0 + 128 + 192 + + + 255 + 255 + 0 + 255 + + + 255 + 128 + 64 + 64 + + + 255 + 255 + 128 + 64 + + + 255 + 80 + 240 + 120 + + + 255 + 0 + 64 + 128 + + + 255 + 128 + 0 + 64 + + + 255 + 255 + 0 + 128 + + + 255 + 128 + 128 + 64 + + + 255 + 128 + 128 + 128 + + + 255 + 255 + 128 + 255 + + + 255 + 0 + 64 + 0 + + + 255 + 0 + 0 + 0 + + + 255 + 255 + 255 + 255 + + + 255 + 255 + 128 + 0 + + + 255 + 80 + 166 + 218 + + + + true + + + row["History"] + + false + Text + Sum + + + History + + + Orthogonal_Value + + , + + Outside + false + + onmouseover + + Show_Tooltip + + + 200 + + + + Rectangle + + + Text + Sum + + + + + + + Numeric + + + + + 255 + 232 + 172 + 57 + + + 255 + 128 + 255 + 128 + + + 255 + 64 + 128 + 128 + + + 255 + 128 + 128 + 192 + + + 255 + 170 + 85 + 85 + + + 255 + 128 + 128 + 0 + + + 255 + 192 + 192 + 192 + + + 255 + 255 + 255 + 128 + + + 255 + 128 + 192 + 128 + + + 255 + 7 + 146 + 94 + + + 255 + 0 + 128 + 255 + + + 255 + 255 + 128 + 192 + + + 255 + 0 + 255 + 255 + + + 255 + 255 + 128 + 128 + + + 255 + 0 + 128 + 192 + + + 255 + 255 + 0 + 255 + + + 255 + 128 + 64 + 64 + + + 255 + 255 + 128 + 64 + + + 255 + 80 + 240 + 120 + + + 255 + 0 + 64 + 128 + + + 255 + 128 + 0 + 64 + + + 255 + 255 + 0 + 128 + + + 255 + 128 + 128 + 64 + + + 255 + 128 + 128 + 128 + + + 255 + 255 + 128 + 255 + + + 255 + 0 + 64 + 0 + + + 255 + 0 + 0 + 0 + + + 255 + 255 + 255 + 255 + + + 255 + 255 + 128 + 0 + + + 255 + 80 + 166 + 218 + + + 255 + 242 + 88 + 106 + + + + true + + + row["Math"] + + false + Text + Sum + + + Math + + + Orthogonal_Value + + , + + Outside + false + + onmouseover + + Show_Tooltip + + + 200 + + + + Rectangle + + + Text + Sum + + + Vertical + + + 1 + + 255 + 0 + 0 + 0 + + true + + + Left + + + + 1 + + 255 + 196 + 196 + 196 + + false + + Across + + + 1 + + 255 + 196 + 196 + 196 + + true + + + + + + 1 + + 255 + 225 + 225 + 225 + + false + + Across + + + 1 + + 255 + 225 + 225 + 225 + + false + + + + 5 + + + Min + + 0.0 + + + true + false + + + + + + + + 255 + 80 + 166 + 218 + + + 255 + 242 + 88 + 106 + + + 255 + 232 + 172 + 57 + + + 255 + 128 + 255 + 128 + + + 255 + 64 + 128 + 128 + + + 255 + 128 + 128 + 192 + + + 255 + 170 + 85 + 85 + + + 255 + 128 + 128 + 0 + + + 255 + 192 + 192 + 192 + + + 255 + 255 + 255 + 128 + + + 255 + 128 + 192 + 128 + + + 255 + 7 + 146 + 94 + + + 255 + 0 + 128 + 255 + + + 255 + 255 + 128 + 192 + + + 255 + 0 + 255 + 255 + + + 255 + 255 + 128 + 128 + + + 255 + 0 + 128 + 192 + + + 255 + 255 + 0 + 255 + + + 255 + 128 + 64 + 64 + + + 255 + 255 + 128 + 64 + + + 255 + 80 + 240 + 120 + + + 255 + 0 + 64 + 128 + + + 255 + 128 + 0 + 64 + + + 255 + 255 + 0 + 128 + + + 255 + 128 + 128 + 64 + + + 255 + 128 + 128 + 128 + + + 255 + 255 + 128 + 255 + + + 255 + 0 + 64 + 0 + + + 255 + 0 + 0 + 0 + + + 255 + 255 + 255 + 255 + + + 255 + 255 + 128 + 0 + + + + true + + + row["Student"] + + + + + Orthogonal_Value + + , + + Outside + false + + + true + Text + Sum + + + Horizontal + + + 1 + + 255 + 0 + 0 + 0 + + true + + + Below + + + + 1 + + 255 + 196 + 196 + 196 + + false + + Across + + + 1 + + 255 + 196 + 196 + 196 + + true + + + + + + 1 + + 255 + 225 + 225 + 225 + + false + + Across + + + 1 + + 255 + 225 + 225 + 225 + + false + + + + 5 + + + Min + + 0.0 + + + true + true + false + + Vertical + 50.0 + + + -20.0 + 45.0 + 0.0 + None + + + +]]> + SVG + true + 286.125pt + 572.25pt + Data Set + + + Student + Student + dataSetRow["Student"] + string + + + Math + Math + dataSetRow["Math"] + integer + + + Geography + Geography + dataSetRow["Geography"] + integer + + + History + History + dataSetRow["History"] + integer + + + + + + + + 2 + 1 + + Data Set + + + Student + Student + dataSetRow["Student"] + string + + + Math + Math + dataSetRow["Math"] + integer + + + Geography + Geography + dataSetRow["Geography"] + integer + + + History + History + dataSetRow["History"] + integer + + + + + + +
+ + + + + + + + + + + + + + +
+ + + + + Student + + + + + Math + + + + + Geography + + + + + History + + + + +
+ + + + + + +
+
+
+
+
+ +
diff --git a/spring-boot-mvc-birt/reports/data.csv b/spring-boot-mvc-birt/reports/data.csv new file mode 100644 index 0000000000..d05e58415e --- /dev/null +++ b/spring-boot-mvc-birt/reports/data.csv @@ -0,0 +1,4 @@ +Student, Math, Geography, History +Bill, 10,3,8 +Tom, 5,6,5 +Anne, 7, 4,9 \ No newline at end of file diff --git a/spring-boot-mvc-birt/reports/static_report.rptdesign b/spring-boot-mvc-birt/reports/static_report.rptdesign new file mode 100644 index 0000000000..d96ff76856 --- /dev/null +++ b/spring-boot-mvc-birt/reports/static_report.rptdesign @@ -0,0 +1,27 @@ + + + Sample Report + + + + + + 100% + + + + + + url + "https://www.baeldung.com/wp-content/themes/baeldung/favicon/favicon-96x96.png" + + + + + + + + + diff --git a/spring-boot-mvc-birt/src/main/java/com/baeldung/birt/designer/ReportDesignApplication.java b/spring-boot-mvc-birt/src/main/java/com/baeldung/birt/designer/ReportDesignApplication.java new file mode 100644 index 0000000000..f1e1619a58 --- /dev/null +++ b/spring-boot-mvc-birt/src/main/java/com/baeldung/birt/designer/ReportDesignApplication.java @@ -0,0 +1,93 @@ +package com.baeldung.birt.designer; + +import com.ibm.icu.util.ULocale; +import org.apache.log4j.Logger; +import org.eclipse.birt.core.exception.BirtException; +import org.eclipse.birt.core.framework.Platform; +import org.eclipse.birt.report.model.api.*; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; + +import java.io.File; +import java.io.IOException; + +@SpringBootApplication +public class ReportDesignApplication implements CommandLineRunner { + + private static final Logger log = Logger.getLogger(ReportDesignApplication.class); + + @Value("${reports.relative.path}") + private String REPORTS_FOLDER; + + public static void main(String[] args) { + new SpringApplicationBuilder(ReportDesignApplication.class).web(WebApplicationType.NONE).build().run(args); + } + + @Override public void run(String... args) throws Exception { + buildReport(); + } + + private void buildReport() throws IOException, BirtException { + final DesignConfig config = new DesignConfig(); + + final IDesignEngine engine; + try { + Platform.startup(config); + IDesignEngineFactory factory = (IDesignEngineFactory) Platform + .createFactoryObject(IDesignEngineFactory.EXTENSION_DESIGN_ENGINE_FACTORY); + engine = factory.createDesignEngine(config); + + } catch (Exception ex) { + log.error("Exception during creation of DesignEngine", ex); + throw ex; + } + + SessionHandle session = engine.newSessionHandle(ULocale.ENGLISH); + + ReportDesignHandle design = session.createDesign(); + design.setTitle("Sample Report"); + + // The element factory creates instances of the various BIRT elements. + ElementFactory factory = design.getElementFactory(); + + // Create a simple master page that describes how the report will + // appear when printed. + // + // Note: The report will fail to load in the BIRT designer + // unless you create a master page. + + DesignElementHandle element = factory.newSimpleMasterPage("Page Master"); //$NON-NLS-1$ + design.getMasterPages().add(element); + + // Create a grid + GridHandle grid = factory.newGridItem(null, 2 /* cols */, 1 /* row */); + design.getBody().add(grid); + grid.setWidth("100%"); + + RowHandle row0 = (RowHandle) grid.getRows().get(0); + + // Create an image and add it to the first cell. + ImageHandle image = factory.newImage(null); + CellHandle cell = (CellHandle) row0.getCells().get(0); + cell.getContent().add(image); + image.setURL("\"https://www.baeldung.com/wp-content/themes/baeldung/favicon/favicon-96x96.png\""); + + // Create a label and add it to the second cell. + LabelHandle label = factory.newLabel(null); + cell = (CellHandle) row0.getCells().get(1); + cell.getContent().add(label); + label.setText("Hello, Baeldung world!"); + + // Save the design and close it. + File report = new File(REPORTS_FOLDER); + report.mkdirs(); + + design.saveAs(new File(report, "static_report.rptdesign").getAbsolutePath()); + design.close(); + log.info("Report generated"); + } + +} diff --git a/spring-boot-mvc-birt/src/main/java/com/baeldung/birt/engine/ReportEngineApplication.java b/spring-boot-mvc-birt/src/main/java/com/baeldung/birt/engine/ReportEngineApplication.java new file mode 100644 index 0000000000..6d72017c9d --- /dev/null +++ b/spring-boot-mvc-birt/src/main/java/com/baeldung/birt/engine/ReportEngineApplication.java @@ -0,0 +1,29 @@ +package com.baeldung.birt.engine; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@SpringBootApplication +@EnableWebMvc +public class ReportEngineApplication implements WebMvcConfigurer { + @Value("${reports.relative.path}") + private String reportsPath; + @Value("${images.relative.path}") + private String imagesPath; + + public static void main(final String[] args) { + SpringApplication.run(ReportEngineApplication.class, args); + } + + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) { + registry + .addResourceHandler(reportsPath + imagesPath + "/**") + .addResourceLocations("file:///" + System.getProperty("user.dir") + "/" + reportsPath + imagesPath); + } + +} \ No newline at end of file diff --git a/spring-boot-mvc-birt/src/main/java/com/baeldung/birt/engine/controller/BirtReportController.java b/spring-boot-mvc-birt/src/main/java/com/baeldung/birt/engine/controller/BirtReportController.java new file mode 100644 index 0000000000..e2405d02ec --- /dev/null +++ b/spring-boot-mvc-birt/src/main/java/com/baeldung/birt/engine/controller/BirtReportController.java @@ -0,0 +1,51 @@ +package com.baeldung.birt.engine.controller; + +import com.baeldung.birt.engine.dto.OutputType; +import com.baeldung.birt.engine.dto.Report; +import com.baeldung.birt.engine.service.BirtReportService; +import org.apache.log4j.Logger; +import org.eclipse.birt.report.engine.api.EngineException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +@Controller +public class BirtReportController { + private static final Logger log = Logger.getLogger(BirtReportController.class); + + @Autowired + private BirtReportService reportService; + + @RequestMapping(produces = "application/json", method = RequestMethod.GET, value = "/report") + @ResponseBody + public List listReports() { + return reportService.getReports(); + } + + @RequestMapping(produces = "application/json", method = RequestMethod.GET, value = "/report/reload") + @ResponseBody + public ResponseEntity reloadReports(HttpServletResponse response) { + try { + log.info("Reloading reports"); + reportService.loadReports(); + } catch (EngineException e) { + log.error("There was an error reloading the reports in memory: ", e); + return ResponseEntity.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).build(); + } + return ResponseEntity.ok().build(); + } + + @RequestMapping(method = RequestMethod.GET, value = "/report/{name}") + @ResponseBody + public void generateFullReport(HttpServletResponse response, HttpServletRequest request, + @PathVariable("name") String name, @RequestParam("output") String output) { + log.info("Generating full report: " + name + "; format: " + output); + OutputType format = OutputType.from(output); + reportService.generateMainReport(name, format, response, request); + } +} diff --git a/spring-boot-mvc-birt/src/main/java/com/baeldung/birt/engine/dto/OutputType.java b/spring-boot-mvc-birt/src/main/java/com/baeldung/birt/engine/dto/OutputType.java new file mode 100644 index 0000000000..3180a347ba --- /dev/null +++ b/spring-boot-mvc-birt/src/main/java/com/baeldung/birt/engine/dto/OutputType.java @@ -0,0 +1,21 @@ +package com.baeldung.birt.engine.dto; + +import org.eclipse.birt.report.engine.api.IRenderOption; + +public enum OutputType { + HTML(IRenderOption.OUTPUT_FORMAT_HTML), + PDF(IRenderOption.OUTPUT_FORMAT_PDF), + INVALID("invalid"); + + String val; + OutputType(String val) { + this.val = val; + } + + public static OutputType from(String text) { + for (OutputType output : values()) { + if(output.val.equalsIgnoreCase(text)) return output; + } + return INVALID; + } +} diff --git a/spring-boot-mvc-birt/src/main/java/com/baeldung/birt/engine/dto/Report.java b/spring-boot-mvc-birt/src/main/java/com/baeldung/birt/engine/dto/Report.java new file mode 100644 index 0000000000..a2d2444b80 --- /dev/null +++ b/spring-boot-mvc-birt/src/main/java/com/baeldung/birt/engine/dto/Report.java @@ -0,0 +1,37 @@ +package com.baeldung.birt.engine.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * Report DTO class + */ +@Data +@NoArgsConstructor +public class Report { + private String title; + private String name; + private List parameters; + + public Report(String title, String name) { + this.title = title; + this.name = name; + } + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class Parameter { + private String title; + private String name; + private ParameterType type; + + } + + public enum ParameterType { + INT, STRING + } +} diff --git a/spring-boot-mvc-birt/src/main/java/com/baeldung/birt/engine/service/BirtReportService.java b/spring-boot-mvc-birt/src/main/java/com/baeldung/birt/engine/service/BirtReportService.java new file mode 100644 index 0000000000..540bbbb530 --- /dev/null +++ b/spring-boot-mvc-birt/src/main/java/com/baeldung/birt/engine/service/BirtReportService.java @@ -0,0 +1,168 @@ +package com.baeldung.birt.engine.service; + +import com.baeldung.birt.engine.dto.OutputType; +import com.baeldung.birt.engine.dto.Report; +import org.eclipse.birt.core.exception.BirtException; +import org.eclipse.birt.core.framework.Platform; +import org.eclipse.birt.report.engine.api.*; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.core.io.ResourceLoader; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.File; +import java.util.*; + +@Service +public class BirtReportService implements ApplicationContextAware, DisposableBean { + @Value("${reports.relative.path}") + private String reportsPath; + @Value("${images.relative.path}") + private String imagesPath; + + private HTMLServerImageHandler htmlImageHandler = new HTMLServerImageHandler(); + + @Autowired + private ResourceLoader resourceLoader; + @Autowired + private ServletContext servletContext; + + private IReportEngine birtEngine; + private ApplicationContext context; + private String imageFolder; + + private Map reports = new HashMap<>(); + + @SuppressWarnings("unchecked") + @PostConstruct + protected void initialize() throws BirtException { + EngineConfig config = new EngineConfig(); + config.getAppContext().put("spring", this.context); + Platform.startup(config); + IReportEngineFactory factory = (IReportEngineFactory) Platform + .createFactoryObject(IReportEngineFactory.EXTENSION_REPORT_ENGINE_FACTORY); + birtEngine = factory.createReportEngine(config); + imageFolder = System.getProperty("user.dir") + File.separatorChar + reportsPath + imagesPath; + loadReports(); + } + + @Override + public void setApplicationContext(ApplicationContext context) { + this.context = context; + } + + /** + * Load report files to memory + * + */ + public void loadReports() throws EngineException { + File folder = new File(reportsPath); + for (String file : Objects.requireNonNull(folder.list())) { + if (!file.endsWith(".rptdesign")) { + continue; + } + + reports.put(file.replace(".rptdesign", ""), + birtEngine.openReportDesign(folder.getAbsolutePath() + File.separator + file)); + + } + } + + public List getReports() { + List response = new ArrayList<>(); + for (Map.Entry entry : reports.entrySet()) { + IReportRunnable report = reports.get(entry.getKey()); + IGetParameterDefinitionTask task = birtEngine.createGetParameterDefinitionTask(report); + Report reportItem = new Report(report.getDesignHandle().getProperty("title").toString(), entry.getKey()); + for (Object h : task.getParameterDefns(false)) { + IParameterDefn def = (IParameterDefn) h; + reportItem.getParameters() + .add(new Report.Parameter(def.getPromptText(), def.getName(), getParameterType(def))); + } + response.add(reportItem); + } + return response; + } + + private Report.ParameterType getParameterType(IParameterDefn param) { + if (IParameterDefn.TYPE_INTEGER == param.getDataType()) { + return Report.ParameterType.INT; + } + return Report.ParameterType.STRING; + } + + public void generateMainReport(String reportName, OutputType output, HttpServletResponse response, HttpServletRequest request) { + switch (output) { + case HTML: + generateHTMLReport(reports.get(reportName), response, request); + break; + case PDF: + generatePDFReport(reports.get(reportName), response, request); + break; + default: + throw new IllegalArgumentException("Output type not recognized:" + output); + } + } + + /** + * Generate a report as HTML + */ + @SuppressWarnings("unchecked") + private void generateHTMLReport(IReportRunnable report, HttpServletResponse response, HttpServletRequest request) { + IRunAndRenderTask runAndRenderTask = birtEngine.createRunAndRenderTask(report); + response.setContentType(birtEngine.getMIMEType("html")); + IRenderOption options = new RenderOption(); + HTMLRenderOption htmlOptions = new HTMLRenderOption(options); + htmlOptions.setOutputFormat("html"); + htmlOptions.setBaseImageURL("/" + reportsPath + imagesPath); + htmlOptions.setImageDirectory(imageFolder); + htmlOptions.setImageHandler(htmlImageHandler); + runAndRenderTask.setRenderOption(htmlOptions); + runAndRenderTask.getAppContext().put(EngineConstants.APPCONTEXT_BIRT_VIEWER_HTTPSERVET_REQUEST, request); + + try { + htmlOptions.setOutputStream(response.getOutputStream()); + runAndRenderTask.run(); + } catch (Exception e) { + throw new RuntimeException(e.getMessage(), e); + } finally { + runAndRenderTask.close(); + } + } + + /** + * Generate a report as PDF + */ + @SuppressWarnings("unchecked") + private void generatePDFReport(IReportRunnable report, HttpServletResponse response, HttpServletRequest request) { + IRunAndRenderTask runAndRenderTask = birtEngine.createRunAndRenderTask(report); + response.setContentType(birtEngine.getMIMEType("pdf")); + IRenderOption options = new RenderOption(); + PDFRenderOption pdfRenderOption = new PDFRenderOption(options); + pdfRenderOption.setOutputFormat("pdf"); + runAndRenderTask.setRenderOption(pdfRenderOption); + runAndRenderTask.getAppContext().put(EngineConstants.APPCONTEXT_PDF_RENDER_CONTEXT, request); + + try { + pdfRenderOption.setOutputStream(response.getOutputStream()); + runAndRenderTask.run(); + } catch (Exception e) { + throw new RuntimeException(e.getMessage(), e); + } finally { + runAndRenderTask.close(); + } + } + + @Override + public void destroy() { + birtEngine.destroy(); + Platform.shutdown(); + } +} diff --git a/spring-boot-mvc-birt/src/main/resources/application.properties b/spring-boot-mvc-birt/src/main/resources/application.properties new file mode 100644 index 0000000000..5b015c70b1 --- /dev/null +++ b/spring-boot-mvc-birt/src/main/resources/application.properties @@ -0,0 +1,2 @@ +reports.relative.path=reports/ +images.relative.path=images/ \ No newline at end of file diff --git a/spring-boot-ops-2/.gitignore b/spring-boot-ops-2/.gitignore new file mode 100644 index 0000000000..153c9335eb --- /dev/null +++ b/spring-boot-ops-2/.gitignore @@ -0,0 +1,29 @@ +HELP.md +/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/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +/build/ + +### VS Code ### +.vscode/ diff --git a/spring-boot-ops-2/README.MD b/spring-boot-ops-2/README.MD new file mode 100644 index 0000000000..20b30515fb --- /dev/null +++ b/spring-boot-ops-2/README.MD @@ -0,0 +1,3 @@ +### Relevant Articles + +- [How to Configure Spring Boot Tomcat](https://www.baeldung.com/spring-boot-configure-tomcat) \ No newline at end of file diff --git a/spring-boot-ops-2/pom.xml b/spring-boot-ops-2/pom.xml new file mode 100644 index 0000000000..dc5280df48 --- /dev/null +++ b/spring-boot-ops-2/pom.xml @@ -0,0 +1,41 @@ + + + 4.0.0 + + + parent-boot-2 + com.baeldung + 0.0.1-SNAPSHOT + ../parent-boot-2 + + + com.baeldung + spring-boot-ops-2 + 0.0.1-SNAPSHOT + spring-boot-ops-2 + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/spring-boot-ops-2/src/main/java/com/baeldung/springbootconfiguration/SpringBootConfigurationApplication.java b/spring-boot-ops-2/src/main/java/com/baeldung/springbootconfiguration/SpringBootConfigurationApplication.java new file mode 100644 index 0000000000..96297459a4 --- /dev/null +++ b/spring-boot-ops-2/src/main/java/com/baeldung/springbootconfiguration/SpringBootConfigurationApplication.java @@ -0,0 +1,13 @@ +package com.baeldung.springbootconfiguration; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SpringBootConfigurationApplication { + + public static void main(String[] args) { + SpringApplication.run(SpringBootConfigurationApplication.class, args); + } + +} diff --git a/spring-boot-ops-2/src/main/resources/application-tomcat.properties b/spring-boot-ops-2/src/main/resources/application-tomcat.properties new file mode 100644 index 0000000000..d7c1ba9ac3 --- /dev/null +++ b/spring-boot-ops-2/src/main/resources/application-tomcat.properties @@ -0,0 +1,23 @@ +# server configuration +server.port=80 +server.address=127.0.0.1 + +## Error handling configuration +server.error.whitelabel.enabled=true +server.error.path=/user-error +server.error.include-exception=true +server.error.include-stacktrace=always + +## Server connections configuration +server.tomcat.max-threads=200 +server.connection-timeout=5s +server.max-http-header-size=8KB +server.tomcat.max-swallow-size=2MB +server.tomcat.max-http-post-size=2MB + +## Access logs configuration +server.tomcat.accesslog.enabled=true +server.tomcat.accesslog.directory=logs +server.tomcat.accesslog.file-date-format=yyyy-MM-dd +server.tomcat.accesslog.prefix=access_log +server.tomcat.accesslog.suffix=.log diff --git a/spring-boot-ops-2/src/main/resources/application.properties b/spring-boot-ops-2/src/main/resources/application.properties new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/spring-boot-ops-2/src/main/resources/application.properties @@ -0,0 +1 @@ + diff --git a/spring-boot-ops-2/src/test/java/com/baeldung/springbootconfiguration/SpringContextIntegrationTest.java b/spring-boot-ops-2/src/test/java/com/baeldung/springbootconfiguration/SpringContextIntegrationTest.java new file mode 100644 index 0000000000..24bef73ef9 --- /dev/null +++ b/spring-boot-ops-2/src/test/java/com/baeldung/springbootconfiguration/SpringContextIntegrationTest.java @@ -0,0 +1,15 @@ +package com.baeldung.springbootconfiguration; + +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 SpringContextIntegrationTest { + + @Test + public void contextLoads() { + } +} diff --git a/spring-boot-ops/README.md b/spring-boot-ops/README.md index 553b02ebf0..d5063f14e5 100644 --- a/spring-boot-ops/README.md +++ b/spring-boot-ops/README.md @@ -10,3 +10,5 @@ - [Spring Boot Console Application](http://www.baeldung.com/spring-boot-console-app) - [Comparing Embedded Servlet Containers in Spring Boot](http://www.baeldung.com/spring-boot-servlet-containers) - [Programmatically Restarting a Spring Boot Application](https://www.baeldung.com/java-restart-spring-boot-app) + - [Spring Properties File Outside jar](https://www.baeldung.com/spring-properties-file-outside-jar) + diff --git a/spring-boot-ops/pom.xml b/spring-boot-ops/pom.xml index 625b2ad188..f36434b682 100644 --- a/spring-boot-ops/pom.xml +++ b/spring-boot-ops/pom.xml @@ -95,6 +95,15 @@ ${project.artifactId} + + + src/main/resources + true + + **/conf.properties + + + org.springframework.boot @@ -110,6 +119,29 @@ + + org.apache.maven.plugins + maven-failsafe-plugin + 2.18 + + + + integration-tests + + integration-test + verify + + + + + **/ExternalPropertyFileLoaderIntegrationTest.java + + + + + diff --git a/spring-boot-ops/src/main/java/com/baeldung/environmentpostprocessor/PriceCalculationApplication.java b/spring-boot-ops/src/main/java/com/baeldung/environmentpostprocessor/PriceCalculationApplication.java new file mode 100644 index 0000000000..ed912d8c0a --- /dev/null +++ b/spring-boot-ops/src/main/java/com/baeldung/environmentpostprocessor/PriceCalculationApplication.java @@ -0,0 +1,59 @@ +package com.baeldung.environmentpostprocessor; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +import com.baeldung.environmentpostprocessor.service.PriceCalculationService; + +@SpringBootApplication +public class PriceCalculationApplication implements CommandLineRunner { + + @Autowired + PriceCalculationService priceCalculationService; + + private static final Logger logger = LoggerFactory.getLogger(PriceCalculationApplication.class); + + public static void main(String[] args) { + SpringApplication.run(PriceCalculationApplication.class, args); + } + + @Override + public void run(String... args) throws Exception { + + List params = Arrays.stream(args) + .collect(Collectors.toList()); + if (verifyArguments(params)) { + double singlePrice = Double.valueOf(params.get(0)); + int quantity = Integer.valueOf(params.get(1)); + priceCalculationService.productTotalPrice(singlePrice, quantity); + } else { + logger.warn("Invalid arguments " + params.toString()); + } + + } + + private boolean verifyArguments(List args) { + boolean successful = true; + if (args.size() != 2) { + successful = false; + return successful; + } + try { + double singlePrice = Double.valueOf(args.get(0)); + int quantity = Integer.valueOf(args.get(1)); + } catch (NumberFormatException e) { + successful = false; + } + return successful; + + } + +} diff --git a/spring-boot-ops/src/main/java/com/baeldung/environmentpostprocessor/PriceCalculationEnvironmentPostProcessor.java b/spring-boot-ops/src/main/java/com/baeldung/environmentpostprocessor/PriceCalculationEnvironmentPostProcessor.java new file mode 100644 index 0000000000..ca6d6cc28f --- /dev/null +++ b/spring-boot-ops/src/main/java/com/baeldung/environmentpostprocessor/PriceCalculationEnvironmentPostProcessor.java @@ -0,0 +1,81 @@ +package com.baeldung.environmentpostprocessor; + +import static org.springframework.core.env.StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME; + +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.env.EnvironmentPostProcessor; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.MapPropertySource; +import org.springframework.core.env.PropertySource; + +@Order(Ordered.LOWEST_PRECEDENCE) +public class PriceCalculationEnvironmentPostProcessor implements EnvironmentPostProcessor { + + private static final Logger logger = LoggerFactory.getLogger(PriceCalculationEnvironmentPostProcessor.class); + + private static final String PREFIX = "com.baeldung.environmentpostprocessor."; + private static final String CALCUATION_MODE = "calculation_mode"; + private static final String GROSS_CALCULATION_TAX_RATE = "gross_calculation_tax_rate"; + private static final String CALCUATION_MODE_DEFAULT_VALUE = "NET"; + private static final double GROSS_CALCULATION_TAX_RATE_DEFAULT_VALUE = 0; + + List names = Arrays.asList(CALCUATION_MODE, GROSS_CALCULATION_TAX_RATE); + + private static Map defaults = new LinkedHashMap<>(); + static { + defaults.put(CALCUATION_MODE, CALCUATION_MODE_DEFAULT_VALUE); + defaults.put(GROSS_CALCULATION_TAX_RATE, GROSS_CALCULATION_TAX_RATE_DEFAULT_VALUE); + } + + @Override + public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { + + PropertySource system = environment.getPropertySources() + .get(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME); + + Map prefixed = new LinkedHashMap<>(); + + if (!hasOurPriceProperties(system)) { + // Baeldung-internal code so this doesn't break other examples + logger.warn("System environment variables [calculation_mode,gross_calculation_tax_rate] not detected, fallback to default value [calcuation_mode={},gross_calcuation_tax_rate={}]", CALCUATION_MODE_DEFAULT_VALUE, + GROSS_CALCULATION_TAX_RATE_DEFAULT_VALUE); + prefixed = names.stream() + .collect(Collectors.toMap(this::rename, this::getDefaultValue)); + environment.getPropertySources() + .addAfter(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, new MapPropertySource("prefixer", prefixed)); + return; + } + + prefixed = names.stream() + .collect(Collectors.toMap(this::rename, system::getProperty)); + environment.getPropertySources() + .addAfter(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, new MapPropertySource("prefixer", prefixed)); + + } + + private Object getDefaultValue(String key) { + return defaults.get(key); + } + + private String rename(String key) { + return PREFIX + key.replaceAll("\\_", "."); + } + + private boolean hasOurPriceProperties(PropertySource system) { + if (system.containsProperty(CALCUATION_MODE) && system.containsProperty(GROSS_CALCULATION_TAX_RATE)) { + return true; + } else + return false; + } + +} diff --git a/spring-boot-ops/src/main/java/com/baeldung/environmentpostprocessor/autoconfig/PriceCalculationAutoConfig.java b/spring-boot-ops/src/main/java/com/baeldung/environmentpostprocessor/autoconfig/PriceCalculationAutoConfig.java new file mode 100644 index 0000000000..c884f043a0 --- /dev/null +++ b/spring-boot-ops/src/main/java/com/baeldung/environmentpostprocessor/autoconfig/PriceCalculationAutoConfig.java @@ -0,0 +1,32 @@ +package com.baeldung.environmentpostprocessor.autoconfig; + +import org.springframework.boot.autoconfigure.AutoConfigureOrder; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.Ordered; + +import com.baeldung.environmentpostprocessor.calculator.GrossPriceCalculator; +import com.baeldung.environmentpostprocessor.calculator.NetPriceCalculator; +import com.baeldung.environmentpostprocessor.calculator.PriceCalculator; + +@Configuration +@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) +public class PriceCalculationAutoConfig { + + @Bean + @ConditionalOnProperty(name = "com.baeldung.environmentpostprocessor.calculation.mode", havingValue = "NET") + @ConditionalOnMissingBean + public PriceCalculator getNetPriceCalculator() { + return new NetPriceCalculator(); + } + + @Bean + @ConditionalOnProperty(name = "com.baeldung.environmentpostprocessor.calculation.mode", havingValue = "GROSS") + @ConditionalOnMissingBean + public PriceCalculator getGrossPriceCalculator() { + return new GrossPriceCalculator(); + } + +} diff --git a/spring-boot-ops/src/main/java/com/baeldung/environmentpostprocessor/calculator/GrossPriceCalculator.java b/spring-boot-ops/src/main/java/com/baeldung/environmentpostprocessor/calculator/GrossPriceCalculator.java new file mode 100644 index 0000000000..f8f797bd66 --- /dev/null +++ b/spring-boot-ops/src/main/java/com/baeldung/environmentpostprocessor/calculator/GrossPriceCalculator.java @@ -0,0 +1,23 @@ +package com.baeldung.environmentpostprocessor.calculator; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; + +public class GrossPriceCalculator implements PriceCalculator { + + private static final Logger logger = LoggerFactory.getLogger(GrossPriceCalculator.class); + + @Value("${com.baeldung.environmentpostprocessor.gross.calculation.tax.rate}") + double taxRate; + + @Override + public double calculate(double singlePrice, int quantity) { + logger.info("Gross based price calculation with input parameters [singlePrice = {},quantity= {} ], {} percent tax applied.", singlePrice, quantity, taxRate * 100); + double netPrice = singlePrice * quantity; + double result = Math.round(netPrice * (1 + taxRate)); + logger.info("Calcuation result is {}", result); + return result; + } + +} diff --git a/spring-boot-ops/src/main/java/com/baeldung/environmentpostprocessor/calculator/NetPriceCalculator.java b/spring-boot-ops/src/main/java/com/baeldung/environmentpostprocessor/calculator/NetPriceCalculator.java new file mode 100644 index 0000000000..263dff6247 --- /dev/null +++ b/spring-boot-ops/src/main/java/com/baeldung/environmentpostprocessor/calculator/NetPriceCalculator.java @@ -0,0 +1,17 @@ +package com.baeldung.environmentpostprocessor.calculator; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class NetPriceCalculator implements PriceCalculator { + + private static final Logger logger = LoggerFactory.getLogger(GrossPriceCalculator.class); + + @Override + public double calculate(double singlePrice, int quantity) { + logger.info("Net based price calculation with input parameters [singlePrice = {},quantity= {} ], NO tax applied.", singlePrice, quantity); + double result = Math.round(singlePrice * quantity); + logger.info("Calcuation result is {}", result); + return result; + } +} diff --git a/spring-boot-ops/src/main/java/com/baeldung/environmentpostprocessor/calculator/PriceCalculator.java b/spring-boot-ops/src/main/java/com/baeldung/environmentpostprocessor/calculator/PriceCalculator.java new file mode 100644 index 0000000000..9d7bef93a4 --- /dev/null +++ b/spring-boot-ops/src/main/java/com/baeldung/environmentpostprocessor/calculator/PriceCalculator.java @@ -0,0 +1,5 @@ +package com.baeldung.environmentpostprocessor.calculator; + +public interface PriceCalculator { + public double calculate(double singlePrice, int quantity); +} diff --git a/spring-boot-ops/src/main/java/com/baeldung/environmentpostprocessor/service/PriceCalculationService.java b/spring-boot-ops/src/main/java/com/baeldung/environmentpostprocessor/service/PriceCalculationService.java new file mode 100644 index 0000000000..0e4eb39506 --- /dev/null +++ b/spring-boot-ops/src/main/java/com/baeldung/environmentpostprocessor/service/PriceCalculationService.java @@ -0,0 +1,17 @@ +package com.baeldung.environmentpostprocessor.service; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.baeldung.environmentpostprocessor.calculator.PriceCalculator; + +@Service +public class PriceCalculationService { + + @Autowired + PriceCalculator priceCalculator; + + public double productTotalPrice(double singlePrice, int quantity) { + return priceCalculator.calculate(singlePrice, quantity); + } +} diff --git a/spring-boot-ops/src/main/java/com/baeldung/properties/ConfProperties.java b/spring-boot-ops/src/main/java/com/baeldung/properties/ConfProperties.java new file mode 100644 index 0000000000..0b6041bb06 --- /dev/null +++ b/spring-boot-ops/src/main/java/com/baeldung/properties/ConfProperties.java @@ -0,0 +1,43 @@ +package com.baeldung.properties; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class ConfProperties { + + @Value("${url}") + private String url; + + @Value("${username}") + private String username; + + @Value("${password}") + private String password; + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + 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-ops/src/main/java/com/baeldung/properties/ExternalPropertyConfigurer.java b/spring-boot-ops/src/main/java/com/baeldung/properties/ExternalPropertyConfigurer.java new file mode 100644 index 0000000000..0cdbb452d5 --- /dev/null +++ b/spring-boot-ops/src/main/java/com/baeldung/properties/ExternalPropertyConfigurer.java @@ -0,0 +1,18 @@ +package com.baeldung.properties; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; +import org.springframework.core.io.FileSystemResource; + +@Configuration +public class ExternalPropertyConfigurer { + + @Bean + public PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() { + PropertySourcesPlaceholderConfigurer properties = new PropertySourcesPlaceholderConfigurer(); + properties.setLocation(new FileSystemResource("src/main/resources/external/conf.properties")); + properties.setIgnoreResourceNotFound(false); + return properties; + } +} \ No newline at end of file diff --git a/spring-boot-ops/src/main/java/com/baeldung/properties/ExternalPropertyFileLoader.java b/spring-boot-ops/src/main/java/com/baeldung/properties/ExternalPropertyFileLoader.java new file mode 100644 index 0000000000..dc5e14549b --- /dev/null +++ b/spring-boot-ops/src/main/java/com/baeldung/properties/ExternalPropertyFileLoader.java @@ -0,0 +1,18 @@ +package com.baeldung.properties; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; + +@SpringBootApplication +public class ExternalPropertyFileLoader { + + @Autowired + ConfProperties prop; + + public static void main(String[] args) { + new SpringApplicationBuilder(ExternalPropertyFileLoader.class).build() + .run(args); + } + +} diff --git a/spring-boot-ops/src/main/resources/META-INF/spring.factories b/spring-boot-ops/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000000..c36b67f8d7 --- /dev/null +++ b/spring-boot-ops/src/main/resources/META-INF/spring.factories @@ -0,0 +1,6 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +com.baeldung.environmentpostprocessor.autoconfig.PriceCalculationAutoConfig + +org.springframework.boot.env.EnvironmentPostProcessor=\ +com.baeldung.environmentpostprocessor.PriceCalculationEnvironmentPostProcessor + diff --git a/spring-boot-ops/src/main/resources/external/conf.properties b/spring-boot-ops/src/main/resources/external/conf.properties new file mode 100644 index 0000000000..cfcd23dc76 --- /dev/null +++ b/spring-boot-ops/src/main/resources/external/conf.properties @@ -0,0 +1,4 @@ +url=jdbc:postgresql://localhost:5432/ +username=admin +password=root +spring.main.allow-bean-definition-overriding=true \ No newline at end of file diff --git a/spring-boot-ops/src/test/java/com/baeldung/environmentpostprocessor/PriceCalculationEnvironmentPostProcessorLiveTest.java b/spring-boot-ops/src/test/java/com/baeldung/environmentpostprocessor/PriceCalculationEnvironmentPostProcessorLiveTest.java new file mode 100644 index 0000000000..54af217346 --- /dev/null +++ b/spring-boot-ops/src/test/java/com/baeldung/environmentpostprocessor/PriceCalculationEnvironmentPostProcessorLiveTest.java @@ -0,0 +1,26 @@ +package com.baeldung.environmentpostprocessor; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import com.baeldung.environmentpostprocessor.service.PriceCalculationService; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = PriceCalculationApplication.class) +public class PriceCalculationEnvironmentPostProcessorLiveTest { + + @Autowired + PriceCalculationService pcService; + + @Test + public void whenSetNetEnvironmentVariablebyDefault_thenNoTaxApplied() { + double total = pcService.productTotalPrice(100, 4); + assertEquals(400.0, total, 0); + } + +} diff --git a/spring-boot-ops/src/test/java/com/baeldung/properties/ExternalPropertyFileLoaderIntegrationTest.java b/spring-boot-ops/src/test/java/com/baeldung/properties/ExternalPropertyFileLoaderIntegrationTest.java new file mode 100644 index 0000000000..2001db57d0 --- /dev/null +++ b/spring-boot-ops/src/test/java/com/baeldung/properties/ExternalPropertyFileLoaderIntegrationTest.java @@ -0,0 +1,27 @@ +package com.baeldung.properties; + +import static org.junit.Assert.assertEquals; + +import java.io.IOException; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +@RunWith(SpringJUnit4ClassRunner.class) +@SpringBootTest(classes = ExternalPropertyFileLoader.class) +public class ExternalPropertyFileLoaderIntegrationTest { + + @Autowired + ConfProperties props; + + @Test + public void whenExternalisedPropertiesLoaded_thenReadValues() throws IOException { + assertEquals("jdbc:postgresql://localhost:5432/", props.getUrl()); + assertEquals("admin", props.getUsername()); + assertEquals("root", props.getPassword()); + } + +} diff --git a/spring-boot-rest/README.md b/spring-boot-rest/README.md index 8fbc9527b8..b28192cf62 100644 --- a/spring-boot-rest/README.md +++ b/spring-boot-rest/README.md @@ -1,12 +1,18 @@ 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) -4. [Build a REST API with Spring and Java Config](http://www.baeldung.com/building-a-restful-web-service-with-spring-and-java-based-configuration) -5. [HATEOAS for a Spring REST Service](http://www.baeldung.com/rest-api-discoverability-with-spring) -6. [REST API Discoverability and HATEOAS](http://www.baeldung.com/restful-web-service-discoverability) -7. [Versioning a REST API](http://www.baeldung.com/rest-versioning) -8. [Http Message Converters with the Spring Framework](http://www.baeldung.com/spring-httpmessageconverter-rest) -9. [ETags for REST with Spring](http://www.baeldung.com/etags-for-rest-with-spring) -10. [Testing REST with multiple MIME types](http://www.baeldung.com/testing-rest-api-with-multiple-media-types) +2. [Build a REST API with Spring and Java Config](http://www.baeldung.com/building-a-restful-web-service-with-spring-and-java-based-configuration) +3. [Http Message Converters with the Spring Framework](http://www.baeldung.com/spring-httpmessageconverter-rest) +4. [Spring’s RequestBody and ResponseBody Annotations](https://www.baeldung.com/spring-request-response-body) +5. [Entity To DTO Conversion for a Spring REST API](https://www.baeldung.com/entity-to-and-from-dto-for-a-java-spring-application) +6. [Error Handling for REST with Spring](http://www.baeldung.com/exception-handling-for-rest-with-spring) +7. [REST API Discoverability and HATEOAS](http://www.baeldung.com/restful-web-service-discoverability) +8. [An Intro to Spring HATEOAS](http://www.baeldung.com/spring-hateoas-tutorial) +9. [REST Pagination in Spring](http://www.baeldung.com/rest-api-pagination-in-spring) +10. [Test a REST API with Java](http://www.baeldung.com/integration-testing-a-rest-api) + +- [HATEOAS for a Spring REST Service](http://www.baeldung.com/rest-api-discoverability-with-spring) +- [Versioning a REST API](http://www.baeldung.com/rest-versioning) +- [ETags for REST with Spring](http://www.baeldung.com/etags-for-rest-with-spring) +- [Testing REST with multiple MIME types](http://www.baeldung.com/testing-rest-api-with-multiple-media-types) +- [Testing Web APIs with Postman Collections](https://www.baeldung.com/postman-testing-collections) diff --git a/spring-boot-rest/pom.xml b/spring-boot-rest/pom.xml index decaccd148..598b589ea0 100644 --- a/spring-boot-rest/pom.xml +++ b/spring-boot-rest/pom.xml @@ -44,6 +44,12 @@ org.springframework.boot spring-boot-starter-data-jpa + + + + org.springframework.boot + spring-boot-starter-hateoas + @@ -63,6 +69,11 @@ htmlunit test + + org.modelmapper + modelmapper + ${modelmapper.version} + @@ -78,5 +89,6 @@ com.baeldung.SpringBootRestApplication 27.0.1-jre 1.4.11.1 + 2.3.3 diff --git a/spring-boot-rest/src/main/java/com/baeldung/SpringBootRestApplication.java b/spring-boot-rest/src/main/java/com/baeldung/SpringBootRestApplication.java index 62aae7619d..1c0d0d19e8 100644 --- a/spring-boot-rest/src/main/java/com/baeldung/SpringBootRestApplication.java +++ b/spring-boot-rest/src/main/java/com/baeldung/SpringBootRestApplication.java @@ -1,7 +1,9 @@ package com.baeldung; +import org.modelmapper.ModelMapper; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; @SpringBootApplication public class SpringBootRestApplication { @@ -9,5 +11,10 @@ public class SpringBootRestApplication { public static void main(String[] args) { SpringApplication.run(SpringBootRestApplication.class, args); } + + @Bean + public ModelMapper modelMapper() { + return new ModelMapper(); + } } diff --git a/spring-boot/src/main/java/com/baeldung/modelmapper/controller/PostRestController.java b/spring-boot-rest/src/main/java/com/baeldung/modelmapper/controller/PostRestController.java similarity index 99% rename from spring-boot/src/main/java/com/baeldung/modelmapper/controller/PostRestController.java rename to spring-boot-rest/src/main/java/com/baeldung/modelmapper/controller/PostRestController.java index c0cbca5220..68c17975d4 100644 --- a/spring-boot/src/main/java/com/baeldung/modelmapper/controller/PostRestController.java +++ b/spring-boot-rest/src/main/java/com/baeldung/modelmapper/controller/PostRestController.java @@ -21,6 +21,7 @@ import com.baeldung.modelmapper.service.IPostService; import com.baeldung.modelmapper.service.IUserService; @Controller +@RequestMapping("/posts") public class PostRestController { @Autowired diff --git a/spring-boot/src/main/java/com/baeldung/modelmapper/dto/PostDto.java b/spring-boot-rest/src/main/java/com/baeldung/modelmapper/dto/PostDto.java similarity index 100% rename from spring-boot/src/main/java/com/baeldung/modelmapper/dto/PostDto.java rename to spring-boot-rest/src/main/java/com/baeldung/modelmapper/dto/PostDto.java diff --git a/spring-boot/src/main/java/com/baeldung/modelmapper/dto/UserDto.java b/spring-boot-rest/src/main/java/com/baeldung/modelmapper/dto/UserDto.java similarity index 100% rename from spring-boot/src/main/java/com/baeldung/modelmapper/dto/UserDto.java rename to spring-boot-rest/src/main/java/com/baeldung/modelmapper/dto/UserDto.java diff --git a/spring-boot/src/main/java/com/baeldung/modelmapper/model/Post.java b/spring-boot-rest/src/main/java/com/baeldung/modelmapper/model/Post.java similarity index 100% rename from spring-boot/src/main/java/com/baeldung/modelmapper/model/Post.java rename to spring-boot-rest/src/main/java/com/baeldung/modelmapper/model/Post.java diff --git a/spring-boot/src/main/java/com/baeldung/modelmapper/model/Preference.java b/spring-boot-rest/src/main/java/com/baeldung/modelmapper/model/Preference.java similarity index 100% rename from spring-boot/src/main/java/com/baeldung/modelmapper/model/Preference.java rename to spring-boot-rest/src/main/java/com/baeldung/modelmapper/model/Preference.java diff --git a/spring-boot/src/main/java/com/baeldung/modelmapper/model/User.java b/spring-boot-rest/src/main/java/com/baeldung/modelmapper/model/User.java similarity index 100% rename from spring-boot/src/main/java/com/baeldung/modelmapper/model/User.java rename to spring-boot-rest/src/main/java/com/baeldung/modelmapper/model/User.java diff --git a/spring-boot/src/main/java/com/baeldung/modelmapper/repository/PostRepository.java b/spring-boot-rest/src/main/java/com/baeldung/modelmapper/repository/PostRepository.java similarity index 100% rename from spring-boot/src/main/java/com/baeldung/modelmapper/repository/PostRepository.java rename to spring-boot-rest/src/main/java/com/baeldung/modelmapper/repository/PostRepository.java diff --git a/spring-boot/src/main/java/com/baeldung/modelmapper/service/IPostService.java b/spring-boot-rest/src/main/java/com/baeldung/modelmapper/service/IPostService.java similarity index 100% rename from spring-boot/src/main/java/com/baeldung/modelmapper/service/IPostService.java rename to spring-boot-rest/src/main/java/com/baeldung/modelmapper/service/IPostService.java diff --git a/spring-boot/src/main/java/com/baeldung/modelmapper/service/IUserService.java b/spring-boot-rest/src/main/java/com/baeldung/modelmapper/service/IUserService.java similarity index 100% rename from spring-boot/src/main/java/com/baeldung/modelmapper/service/IUserService.java rename to spring-boot-rest/src/main/java/com/baeldung/modelmapper/service/IUserService.java diff --git a/spring-boot/src/main/java/com/baeldung/modelmapper/service/PostService.java b/spring-boot-rest/src/main/java/com/baeldung/modelmapper/service/PostService.java similarity index 100% rename from spring-boot/src/main/java/com/baeldung/modelmapper/service/PostService.java rename to spring-boot-rest/src/main/java/com/baeldung/modelmapper/service/PostService.java diff --git a/spring-boot/src/main/java/com/baeldung/modelmapper/service/UserService.java b/spring-boot-rest/src/main/java/com/baeldung/modelmapper/service/UserService.java similarity index 100% rename from spring-boot/src/main/java/com/baeldung/modelmapper/service/UserService.java rename to spring-boot-rest/src/main/java/com/baeldung/modelmapper/service/UserService.java 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 index 1cc732ab08..fbbba23013 100644 --- a/spring-boot-rest/src/main/java/com/baeldung/persistence/IOperations.java +++ b/spring-boot-rest/src/main/java/com/baeldung/persistence/IOperations.java @@ -9,7 +9,7 @@ public interface IOperations { // read - one - T findOne(final long id); + T findById(final long id); // read - all diff --git a/spring-security-rest/src/main/java/org/baeldung/persistence/model/Customer.java b/spring-boot-rest/src/main/java/com/baeldung/persistence/model/Customer.java similarity index 97% rename from spring-security-rest/src/main/java/org/baeldung/persistence/model/Customer.java rename to spring-boot-rest/src/main/java/com/baeldung/persistence/model/Customer.java index b302ec057a..10da2e10f0 100644 --- a/spring-security-rest/src/main/java/org/baeldung/persistence/model/Customer.java +++ b/spring-boot-rest/src/main/java/com/baeldung/persistence/model/Customer.java @@ -1,4 +1,4 @@ -package org.baeldung.persistence.model; +package com.baeldung.persistence.model; import java.util.Map; diff --git a/spring-security-rest/src/main/java/org/baeldung/persistence/model/Order.java b/spring-boot-rest/src/main/java/com/baeldung/persistence/model/Order.java similarity index 96% rename from spring-security-rest/src/main/java/org/baeldung/persistence/model/Order.java rename to spring-boot-rest/src/main/java/com/baeldung/persistence/model/Order.java index ca551423e8..7aea9bce5c 100644 --- a/spring-security-rest/src/main/java/org/baeldung/persistence/model/Order.java +++ b/spring-boot-rest/src/main/java/com/baeldung/persistence/model/Order.java @@ -1,4 +1,4 @@ -package org.baeldung.persistence.model; +package com.baeldung.persistence.model; import org.springframework.hateoas.ResourceSupport; 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 index 5900c443b8..f589eaecf5 100644 --- 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 @@ -18,9 +18,8 @@ public abstract class AbstractService implements IOperat @Override @Transactional(readOnly = true) - public T findOne(final long id) { - return getDao().findById(id) - .get(); + public T findById(final long id) { + return getDao().findById(id).orElse(null); } // read - all diff --git a/spring-security-rest/src/main/java/org/baeldung/web/service/CustomerService.java b/spring-boot-rest/src/main/java/com/baeldung/services/CustomerService.java similarity index 64% rename from spring-security-rest/src/main/java/org/baeldung/web/service/CustomerService.java rename to spring-boot-rest/src/main/java/com/baeldung/services/CustomerService.java index da016af2d5..a5e95e693b 100644 --- a/spring-security-rest/src/main/java/org/baeldung/web/service/CustomerService.java +++ b/spring-boot-rest/src/main/java/com/baeldung/services/CustomerService.java @@ -1,8 +1,8 @@ -package org.baeldung.web.service; +package com.baeldung.services; import java.util.List; -import org.baeldung.persistence.model.Customer; +import com.baeldung.persistence.model.Customer; public interface CustomerService { diff --git a/spring-security-rest/src/main/java/org/baeldung/web/service/CustomerServiceImpl.java b/spring-boot-rest/src/main/java/com/baeldung/services/CustomerServiceImpl.java similarity index 92% rename from spring-security-rest/src/main/java/org/baeldung/web/service/CustomerServiceImpl.java rename to spring-boot-rest/src/main/java/com/baeldung/services/CustomerServiceImpl.java index e179de2554..58030483ec 100644 --- a/spring-security-rest/src/main/java/org/baeldung/web/service/CustomerServiceImpl.java +++ b/spring-boot-rest/src/main/java/com/baeldung/services/CustomerServiceImpl.java @@ -1,12 +1,13 @@ -package org.baeldung.web.service; +package com.baeldung.services; import java.util.ArrayList; import java.util.HashMap; import java.util.List; -import org.baeldung.persistence.model.Customer; import org.springframework.stereotype.Service; +import com.baeldung.persistence.model.Customer; + @Service public class CustomerServiceImpl implements CustomerService { diff --git a/spring-rest/src/main/java/com/baeldung/services/ExampleService.java b/spring-boot-rest/src/main/java/com/baeldung/services/ExampleService.java similarity index 100% rename from spring-rest/src/main/java/com/baeldung/services/ExampleService.java rename to spring-boot-rest/src/main/java/com/baeldung/services/ExampleService.java diff --git a/spring-security-rest/src/main/java/org/baeldung/web/service/OrderService.java b/spring-boot-rest/src/main/java/com/baeldung/services/OrderService.java similarity index 70% rename from spring-security-rest/src/main/java/org/baeldung/web/service/OrderService.java rename to spring-boot-rest/src/main/java/com/baeldung/services/OrderService.java index 9a23488c50..775701e042 100644 --- a/spring-security-rest/src/main/java/org/baeldung/web/service/OrderService.java +++ b/spring-boot-rest/src/main/java/com/baeldung/services/OrderService.java @@ -1,8 +1,8 @@ -package org.baeldung.web.service; +package com.baeldung.services; import java.util.List; -import org.baeldung.persistence.model.Order; +import com.baeldung.persistence.model.Order; public interface OrderService { diff --git a/spring-security-rest/src/main/java/org/baeldung/web/service/OrderServiceImpl.java b/spring-boot-rest/src/main/java/com/baeldung/services/OrderServiceImpl.java similarity index 93% rename from spring-security-rest/src/main/java/org/baeldung/web/service/OrderServiceImpl.java rename to spring-boot-rest/src/main/java/com/baeldung/services/OrderServiceImpl.java index 0a6d4708a1..fffdf88969 100644 --- a/spring-security-rest/src/main/java/org/baeldung/web/service/OrderServiceImpl.java +++ b/spring-boot-rest/src/main/java/com/baeldung/services/OrderServiceImpl.java @@ -1,14 +1,15 @@ -package org.baeldung.web.service; +package com.baeldung.services; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import org.baeldung.persistence.model.Customer; -import org.baeldung.persistence.model.Order; import org.springframework.stereotype.Service; +import com.baeldung.persistence.model.Customer; +import com.baeldung.persistence.model.Order; + @Service public class OrderServiceImpl implements OrderService { 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 5179c66978..2e967751ad 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 @@ -24,8 +24,8 @@ import com.google.common.base.Preconditions; @Configuration @EnableTransactionManagement @PropertySource({ "classpath:persistence-${envTarget:h2}.properties" }) -@ComponentScan({ "com.baeldung.persistence" }) -@EnableJpaRepositories(basePackages = "com.baeldung.persistence.dao") +@ComponentScan(basePackages = { "com.baeldung.persistence", "com.baeldung.modelmapper" }) +@EnableJpaRepositories(basePackages = {"com.baeldung.persistence.dao", "com.baeldung.modelmapper.repository"}) public class PersistenceConfig { @Autowired @@ -39,7 +39,7 @@ public class PersistenceConfig { public LocalContainerEntityManagerFactoryBean entityManagerFactory() { final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); em.setDataSource(dataSource()); - em.setPackagesToScan(new String[] { "com.baeldung.persistence.model" }); + em.setPackagesToScan(new String[] { "com.baeldung.persistence.model", "com.baeldung.modelmapper.model" }); final HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); // vendorAdapter.set 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 4b876a8338..ab16b61e1d 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 @@ -55,7 +55,7 @@ public class WebConfig implements WebMvcConfigurer { @Bean public FilterRegistrationBean shallowEtagHeaderFilter() { FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean<>( new ShallowEtagHeaderFilter()); - filterRegistrationBean.addUrlPatterns("/auth/foos/*"); + filterRegistrationBean.addUrlPatterns("/foos/*"); filterRegistrationBean.setName("etagFilter"); return filterRegistrationBean; } diff --git a/spring-boot-rest/src/main/java/com/baeldung/transfer/LoginForm.java b/spring-boot-rest/src/main/java/com/baeldung/transfer/LoginForm.java new file mode 100644 index 0000000000..caafcdb500 --- /dev/null +++ b/spring-boot-rest/src/main/java/com/baeldung/transfer/LoginForm.java @@ -0,0 +1,31 @@ +package com.baeldung.transfer; + +public class LoginForm { + private String username; + private String password; + + public LoginForm() { + } + + public LoginForm(String username, String password) { + super(); + this.username = username; + this.password = password; + } + + 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; + } +} \ No newline at end of file diff --git a/spring-rest/src/main/java/com/baeldung/transfer/ResponseTransfer.java b/spring-boot-rest/src/main/java/com/baeldung/transfer/ResponseTransfer.java similarity index 100% rename from spring-rest/src/main/java/com/baeldung/transfer/ResponseTransfer.java rename to spring-boot-rest/src/main/java/com/baeldung/transfer/ResponseTransfer.java diff --git a/spring-security-rest/src/main/java/org/baeldung/web/controller/CustomerController.java b/spring-boot-rest/src/main/java/com/baeldung/web/controller/CustomerController.java similarity index 64% rename from spring-security-rest/src/main/java/org/baeldung/web/controller/CustomerController.java rename to spring-boot-rest/src/main/java/com/baeldung/web/controller/CustomerController.java index e1db105d18..91aa9f2144 100644 --- a/spring-security-rest/src/main/java/org/baeldung/web/controller/CustomerController.java +++ b/spring-boot-rest/src/main/java/com/baeldung/web/controller/CustomerController.java @@ -1,24 +1,25 @@ -package org.baeldung.web.controller; +package com.baeldung.web.controller; import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo; import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn; import java.util.List; -import org.baeldung.persistence.model.Customer; -import org.baeldung.persistence.model.Order; -import org.baeldung.web.service.CustomerService; -import org.baeldung.web.service.OrderService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.hateoas.Link; import org.springframework.hateoas.Resources; import org.springframework.hateoas.config.EnableHypermediaSupport; import org.springframework.hateoas.config.EnableHypermediaSupport.HypermediaType; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; +import com.baeldung.persistence.model.Customer; +import com.baeldung.persistence.model.Order; +import com.baeldung.services.CustomerService; +import com.baeldung.services.OrderService; + @RestController @RequestMapping(value = "/customers") @EnableHypermediaSupport(type = HypermediaType.HAL) @@ -29,45 +30,49 @@ public class CustomerController { @Autowired private OrderService orderService; - @RequestMapping(value = "/{customerId}", method = RequestMethod.GET) + @GetMapping("/{customerId}") public Customer getCustomerById(@PathVariable final String customerId) { return customerService.getCustomerDetail(customerId); } - @RequestMapping(value = "/{customerId}/{orderId}", method = RequestMethod.GET) + @GetMapping("/{customerId}/{orderId}") public Order getOrderById(@PathVariable final String customerId, @PathVariable final String orderId) { return orderService.getOrderByIdForCustomer(customerId, orderId); } - @RequestMapping(value = "/{customerId}/orders", method = RequestMethod.GET , produces = {"application/hal+json"}) + @GetMapping(value = "/{customerId}/orders", produces = { "application/hal+json" }) public Resources getOrdersForCustomer(@PathVariable final String customerId) { final List orders = orderService.getAllOrdersForCustomer(customerId); for (final Order order : orders) { - final Link selfLink = linkTo(methodOn(CustomerController.class).getOrderById(customerId, order.getOrderId())).withSelfRel(); + final Link selfLink = linkTo( + methodOn(CustomerController.class).getOrderById(customerId, order.getOrderId())).withSelfRel(); order.add(selfLink); } - - Link link =linkTo(methodOn(CustomerController.class).getOrdersForCustomer(customerId)).withSelfRel(); - Resources result = new Resources<>(orders,link); + + Link link = linkTo(methodOn(CustomerController.class).getOrdersForCustomer(customerId)).withSelfRel(); + Resources result = new Resources<>(orders, link); return result; } - @RequestMapping(method = RequestMethod.GET, produces = {"application/hal+json"}) + @GetMapping(produces = { "application/hal+json" }) public Resources getAllCustomers() { final List allCustomers = customerService.allCustomers(); - + for (final Customer customer : allCustomers) { String customerId = customer.getCustomerId(); - Link selfLink = linkTo(CustomerController.class).slash(customerId).withSelfRel(); + Link selfLink = linkTo(CustomerController.class).slash(customerId) + .withSelfRel(); customer.add(selfLink); - if (orderService.getAllOrdersForCustomer(customerId).size() > 0) { - final Link ordersLink = linkTo(methodOn(CustomerController.class).getOrdersForCustomer(customerId)).withRel("allOrders"); + if (orderService.getAllOrdersForCustomer(customerId) + .size() > 0) { + final Link ordersLink = linkTo(methodOn(CustomerController.class).getOrdersForCustomer(customerId)) + .withRel("allOrders"); customer.add(ordersLink); } } - - Link link =linkTo(CustomerController.class).withSelfRel(); - Resources result = new Resources<>(allCustomers,link); + + Link link = linkTo(CustomerController.class).withSelfRel(); + Resources result = new Resources<>(allCustomers, link); return result; } diff --git a/spring-rest/src/main/java/com/baeldung/controllers/ExamplePostController.java b/spring-boot-rest/src/main/java/com/baeldung/web/controller/ExamplePostController.java similarity index 97% rename from spring-rest/src/main/java/com/baeldung/controllers/ExamplePostController.java rename to spring-boot-rest/src/main/java/com/baeldung/web/controller/ExamplePostController.java index 93f96756b4..1519d95d4d 100644 --- a/spring-rest/src/main/java/com/baeldung/controllers/ExamplePostController.java +++ b/spring-boot-rest/src/main/java/com/baeldung/web/controller/ExamplePostController.java @@ -1,4 +1,4 @@ -package com.baeldung.controllers; +package com.baeldung.web.controller; import com.baeldung.services.ExampleService; import com.baeldung.transfer.ResponseTransfer; 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 index 255fcaabb7..8174480078 100644 --- 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 @@ -20,6 +20,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.server.ResponseStatusException; import org.springframework.web.util.UriComponentsBuilder; import com.baeldung.persistence.model.Foo; @@ -32,7 +33,7 @@ import com.baeldung.web.util.RestPreconditions; import com.google.common.base.Preconditions; @RestController -@RequestMapping(value = "/auth/foos") +@RequestMapping(value = "/foos") public class FooController { @Autowired @@ -51,22 +52,29 @@ public class FooController { @GetMapping(value = "/{id}/custom-etag") public ResponseEntity findByIdWithCustomEtag(@PathVariable("id") final Long id, final HttpServletResponse response) { - final Foo resourceById = RestPreconditions.checkFound(service.findOne(id)); + final Foo foo = RestPreconditions.checkFound(service.findById(id)); eventPublisher.publishEvent(new SingleResourceRetrievedEvent(this, response)); return ResponseEntity.ok() - .eTag(Long.toString(resourceById.getVersion())) - .body(resourceById); + .eTag(Long.toString(foo.getVersion())) + .body(foo); } // read - one @GetMapping(value = "/{id}") public Foo findById(@PathVariable("id") final Long id, final HttpServletResponse response) { - final Foo resourceById = RestPreconditions.checkFound(service.findOne(id)); + try { + final Foo resourceById = RestPreconditions.checkFound(service.findById(id)); + + eventPublisher.publishEvent(new SingleResourceRetrievedEvent(this, response)); + return resourceById; + } + catch (MyResourceNotFoundException exc) { + throw new ResponseStatusException( + HttpStatus.NOT_FOUND, "Foo Not Found", exc); + } - eventPublisher.publishEvent(new SingleResourceRetrievedEvent(this, response)); - return resourceById; } // read - all @@ -120,7 +128,7 @@ public class FooController { @ResponseStatus(HttpStatus.OK) public void update(@PathVariable("id") final Long id, @RequestBody final Foo resource) { Preconditions.checkNotNull(resource); - RestPreconditions.checkFound(service.findOne(resource.getId())); + RestPreconditions.checkFound(service.findById(resource.getId())); service.update(resource); } 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 index 436e41e8eb..d618e9f0bf 100644 --- 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 @@ -7,34 +7,28 @@ 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.GetMapping; 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) + @GetMapping("/") @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); + final URI fooUri = new UriTemplate("{rootUri}{resource}").expand(rootUri, "foos"); + final String linkToFoos = LinkUtil.createLinkHeader(fooUri.toASCIIString(), "collection"); + response.addHeader("Link", linkToFoos); } } diff --git a/spring-boot-rest/src/main/java/com/baeldung/web/controller/students/Student.java b/spring-boot-rest/src/main/java/com/baeldung/web/controller/students/Student.java new file mode 100644 index 0000000000..3b6a5c0298 --- /dev/null +++ b/spring-boot-rest/src/main/java/com/baeldung/web/controller/students/Student.java @@ -0,0 +1,53 @@ +package com.baeldung.web.controller.students; + +public class Student { + + private long id; + private String firstName; + private String lastName; + + public Student() {} + + public Student(String firstName, String lastName) { + super(); + this.firstName = firstName; + this.lastName = lastName; + } + + public Student(long id, String firstName, String lastName) { + super(); + this.id = id; + this.firstName = firstName; + this.lastName = lastName; + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + @Override + public String toString() { + return "Student [id=" + id + ", firstName=" + firstName + ", lastName=" + lastName + "]"; + } + +} diff --git a/spring-boot-rest/src/main/java/com/baeldung/web/controller/students/StudentController.java b/spring-boot-rest/src/main/java/com/baeldung/web/controller/students/StudentController.java new file mode 100644 index 0000000000..f937e0c757 --- /dev/null +++ b/spring-boot-rest/src/main/java/com/baeldung/web/controller/students/StudentController.java @@ -0,0 +1,73 @@ +package com.baeldung.web.controller.students; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +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.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.servlet.support.ServletUriComponentsBuilder; +import com.baeldung.web.controller.students.StudentService; + +@RestController +@RequestMapping("/students") +public class StudentController { + + @Autowired + private StudentService service; + + @GetMapping("/") + public List read() { + return service.readAll(); + } + + @GetMapping("/{id}") + public ResponseEntity read(@PathVariable("id") Long id) { + Student foundStudent = service.read(id); + if (foundStudent == null) { + return ResponseEntity.notFound().build(); + } else { + return ResponseEntity.ok(foundStudent); + } + } + + @PostMapping("/") + public ResponseEntity create(@RequestBody Student student) throws URISyntaxException { + Student createdStudent = service.create(student); + + URI uri = ServletUriComponentsBuilder.fromCurrentRequest() + .path("/{id}") + .buildAndExpand(createdStudent.getId()) + .toUri(); + + return ResponseEntity.created(uri) + .body(createdStudent); + + } + + @PutMapping("/{id}") + public ResponseEntity update(@RequestBody Student student, @PathVariable Long id) { + Student updatedStudent = service.update(id, student); + if (updatedStudent == null) { + return ResponseEntity.notFound().build(); + } else { + return ResponseEntity.ok(updatedStudent); + } + } + + @DeleteMapping("/{id}") + public ResponseEntity deleteStudent(@PathVariable Long id) { + service.delete(id); + + return ResponseEntity.noContent().build(); + } + +} diff --git a/spring-boot-rest/src/main/java/com/baeldung/web/controller/students/StudentService.java b/spring-boot-rest/src/main/java/com/baeldung/web/controller/students/StudentService.java new file mode 100644 index 0000000000..d923f4f14f --- /dev/null +++ b/spring-boot-rest/src/main/java/com/baeldung/web/controller/students/StudentService.java @@ -0,0 +1,51 @@ +package com.baeldung.web.controller.students; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Function; +import java.util.stream.Collectors; + +import org.springframework.stereotype.Service; + +@Service +public class StudentService { + + // DB repository mock + private Map repository = Arrays.asList( + new Student[]{ + new Student(1, "Alan","Turing"), + new Student(2, "Sebastian","Bach"), + new Student(3, "Pablo","Picasso"), + }).stream() + .collect(Collectors.toConcurrentMap(s -> s.getId(), Function.identity())); + + // DB id sequence mock + private AtomicLong sequence = new AtomicLong(3); + + public List readAll() { + return repository.values().stream().collect(Collectors.toList()); + } + + public Student read(Long id) { + return repository.get(id); + } + + public Student create(Student student) { + long key = sequence.incrementAndGet(); + student.setId(key); + repository.put(key, student); + return student; + } + + public Student update(Long id, Student student) { + student.setId(id); + Student oldStudent = repository.replace(id, student); + return oldStudent == null ? null : student; + } + + public void delete(Long id) { + repository.remove(id); + } +} 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 31555ef353..afcd364cce 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 @@ -115,7 +115,7 @@ class PaginatedResultsRetrievedDiscoverabilityListener implements ApplicationLis protected void plural(final UriComponentsBuilder uriBuilder, final Class clazz) { final String resourceName = clazz.getSimpleName() .toLowerCase() + "s"; - uriBuilder.path("/auth/" + resourceName); + uriBuilder.path("/" + resourceName); } } diff --git a/spring-boot-rest/src/main/resources/application.properties b/spring-boot-rest/src/main/resources/application.properties index a0179f1e4b..176deb4f49 100644 --- a/spring-boot-rest/src/main/resources/application.properties +++ b/spring-boot-rest/src/main/resources/application.properties @@ -1,6 +1,5 @@ -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 +#server.error.include-stacktrace=always diff --git a/spring-boot-rest/src/test/java/com/baeldung/Consts.java b/spring-boot-rest/src/test/java/com/baeldung/Consts.java index e33efd589e..4850a1b36a 100644 --- a/spring-boot-rest/src/test/java/com/baeldung/Consts.java +++ b/spring-boot-rest/src/test/java/com/baeldung/Consts.java @@ -1,5 +1,5 @@ package com.baeldung; public interface Consts { - int APPLICATION_PORT = 8082; + int APPLICATION_PORT = 8080; } diff --git a/spring-boot-rest/src/test/java/com/baeldung/SpringContextIntegrationTest.java b/spring-boot-rest/src/test/java/com/baeldung/SpringContextIntegrationTest.java index 25fbc4cc02..3db1ecb462 100644 --- a/spring-boot-rest/src/test/java/com/baeldung/SpringContextIntegrationTest.java +++ b/spring-boot-rest/src/test/java/com/baeldung/SpringContextIntegrationTest.java @@ -6,7 +6,7 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) -@SpringBootTest +@SpringBootTest(classes = {SpringBootRestApplication.class}) public class SpringContextIntegrationTest { @Test 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 index d26632bc38..18f612d398 100644 --- 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 @@ -59,7 +59,7 @@ public abstract class AbstractLiveTest { // protected String getURL() { - return "http://localhost:" + APPLICATION_PORT + "/spring-boot-rest/auth/foos"; + return "http://localhost:" + APPLICATION_PORT + "/spring-boot-rest/foos"; } } diff --git a/spring-rest/src/test/java/com/baeldung/controllers/ExamplePostControllerRequestIntegrationTest.java b/spring-boot-rest/src/test/java/com/baeldung/controllers/ExamplePostControllerRequestIntegrationTest.java similarity index 92% rename from spring-rest/src/test/java/com/baeldung/controllers/ExamplePostControllerRequestIntegrationTest.java rename to spring-boot-rest/src/test/java/com/baeldung/controllers/ExamplePostControllerRequestIntegrationTest.java index 94b8bf40e7..fc533072c8 100644 --- a/spring-rest/src/test/java/com/baeldung/controllers/ExamplePostControllerRequestIntegrationTest.java +++ b/spring-boot-rest/src/test/java/com/baeldung/controllers/ExamplePostControllerRequestIntegrationTest.java @@ -1,8 +1,10 @@ package com.baeldung.controllers; -import com.baeldung.sampleapp.config.MainApplication; -import com.baeldung.services.ExampleService; -import com.baeldung.transfer.LoginForm; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -14,13 +16,13 @@ import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import static org.mockito.Mockito.when; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import com.baeldung.SpringBootRestApplication; +import com.baeldung.services.ExampleService; +import com.baeldung.transfer.LoginForm; +import com.baeldung.web.controller.ExamplePostController; @RunWith(SpringRunner.class) -@SpringBootTest(classes = MainApplication.class) +@SpringBootTest(classes = SpringBootRestApplication.class) public class ExamplePostControllerRequestIntegrationTest { MockMvc mockMvc; diff --git a/spring-rest/src/test/java/com/baeldung/controllers/ExamplePostControllerResponseIntegrationTest.java b/spring-boot-rest/src/test/java/com/baeldung/controllers/ExamplePostControllerResponseIntegrationTest.java similarity index 92% rename from spring-rest/src/test/java/com/baeldung/controllers/ExamplePostControllerResponseIntegrationTest.java rename to spring-boot-rest/src/test/java/com/baeldung/controllers/ExamplePostControllerResponseIntegrationTest.java index 5743ad450b..cbe21b1d90 100644 --- a/spring-rest/src/test/java/com/baeldung/controllers/ExamplePostControllerResponseIntegrationTest.java +++ b/spring-boot-rest/src/test/java/com/baeldung/controllers/ExamplePostControllerResponseIntegrationTest.java @@ -1,8 +1,11 @@ package com.baeldung.controllers; -import com.baeldung.sampleapp.config.MainApplication; -import com.baeldung.services.ExampleService; -import com.baeldung.transfer.LoginForm; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -11,18 +14,16 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; - import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import static org.mockito.Mockito.when; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import com.baeldung.SpringBootRestApplication; +import com.baeldung.services.ExampleService; +import com.baeldung.transfer.LoginForm; +import com.baeldung.web.controller.ExamplePostController; @RunWith(SpringRunner.class) -@SpringBootTest(classes = MainApplication.class) +@SpringBootTest(classes = SpringBootRestApplication.class) public class ExamplePostControllerResponseIntegrationTest { MockMvc mockMvc; diff --git a/spring-boot/src/test/java/com/baeldung/modelmapper/PostDtoUnitTest.java b/spring-boot-rest/src/test/java/com/baeldung/modelmapper/PostDtoUnitTest.java similarity index 100% rename from spring-boot/src/test/java/com/baeldung/modelmapper/PostDtoUnitTest.java rename to spring-boot-rest/src/test/java/com/baeldung/modelmapper/PostDtoUnitTest.java diff --git a/spring-boot-rest/src/test/java/com/baeldung/rest/GitHubUser.java b/spring-boot-rest/src/test/java/com/baeldung/rest/GitHubUser.java new file mode 100644 index 0000000000..da5085ab12 --- /dev/null +++ b/spring-boot-rest/src/test/java/com/baeldung/rest/GitHubUser.java @@ -0,0 +1,21 @@ +package com.baeldung.rest; + +public class GitHubUser { + + private String login; + + public GitHubUser() { + super(); + } + + // API + + public String getLogin() { + return login; + } + + public void setLogin(final String login) { + this.login = login; + } + +} diff --git a/testing-modules/rest-testing/src/test/java/org/baeldung/rest/GithubBasicLiveTest.java b/spring-boot-rest/src/test/java/com/baeldung/rest/GithubBasicLiveTest.java similarity index 98% rename from testing-modules/rest-testing/src/test/java/org/baeldung/rest/GithubBasicLiveTest.java rename to spring-boot-rest/src/test/java/com/baeldung/rest/GithubBasicLiveTest.java index acac82c8f4..3082b34421 100644 --- a/testing-modules/rest-testing/src/test/java/org/baeldung/rest/GithubBasicLiveTest.java +++ b/spring-boot-rest/src/test/java/com/baeldung/rest/GithubBasicLiveTest.java @@ -1,4 +1,4 @@ -package org.baeldung.rest; +package com.baeldung.rest; import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic; import static org.hamcrest.Matchers.equalTo; diff --git a/spring-boot-rest/src/test/java/com/baeldung/rest/RetrieveUtil.java b/spring-boot-rest/src/test/java/com/baeldung/rest/RetrieveUtil.java new file mode 100644 index 0000000000..0ec36bc3ae --- /dev/null +++ b/spring-boot-rest/src/test/java/com/baeldung/rest/RetrieveUtil.java @@ -0,0 +1,21 @@ +package com.baeldung.rest; + +import java.io.IOException; + +import org.apache.http.HttpResponse; +import org.apache.http.util.EntityUtils; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; + +public class RetrieveUtil { + + // API + + public static T retrieveResourceFromResponse(final HttpResponse response, final Class clazz) throws IOException { + final String jsonFromResponse = EntityUtils.toString(response.getEntity()); + final ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + return mapper.readValue(jsonFromResponse, clazz); + } + +} diff --git a/spring-boot-rest/src/test/java/com/baeldung/springhateoas/CustomerControllerIntegrationTest.java b/spring-boot-rest/src/test/java/com/baeldung/springhateoas/CustomerControllerIntegrationTest.java new file mode 100644 index 0000000000..b08da6d2cd --- /dev/null +++ b/spring-boot-rest/src/test/java/com/baeldung/springhateoas/CustomerControllerIntegrationTest.java @@ -0,0 +1,98 @@ +package com.baeldung.springhateoas; + +import static org.hamcrest.Matchers.is; +import static org.mockito.BDDMockito.given; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.util.Collections; +import java.util.List; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.hateoas.MediaTypes; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; + +import com.baeldung.persistence.model.Customer; +import com.baeldung.persistence.model.Order; +import com.baeldung.services.CustomerService; +import com.baeldung.services.OrderService; +import com.baeldung.web.controller.CustomerController; + +@RunWith(SpringRunner.class) +@WebMvcTest(CustomerController.class) +public class CustomerControllerIntegrationTest { + + @Autowired + private MockMvc mvc; + + @MockBean + private CustomerService customerService; + + @MockBean + private OrderService orderService; + + private static final String DEFAULT_CUSTOMER_ID = "customer1"; + private static final String DEFAULT_ORDER_ID = "order1"; + + @Test + public void givenExistingCustomer_whenCustomerRequested_thenResourceRetrieved() throws Exception { + given(this.customerService.getCustomerDetail(DEFAULT_CUSTOMER_ID)) + .willReturn(new Customer(DEFAULT_CUSTOMER_ID, "customerJohn", "companyOne")); + + this.mvc.perform(get("/customers/" + DEFAULT_CUSTOMER_ID)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$._links").doesNotExist()) + .andExpect(jsonPath("$.customerId", is(DEFAULT_CUSTOMER_ID))); + } + + @Test + public void givenExistingOrder_whenOrderRequested_thenResourceRetrieved() throws Exception { + given(this.orderService.getOrderByIdForCustomer(DEFAULT_CUSTOMER_ID, DEFAULT_ORDER_ID)) + .willReturn(new Order(DEFAULT_ORDER_ID, 1., 1)); + + this.mvc.perform(get("/customers/" + DEFAULT_CUSTOMER_ID + "/" + DEFAULT_ORDER_ID)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$._links").doesNotExist()) + .andExpect(jsonPath("$.orderId", is(DEFAULT_ORDER_ID))); + } + + @Test + public void givenExistingCustomerWithOrders_whenOrdersRequested_thenHalResourceRetrieved() throws Exception { + Order order1 = new Order(DEFAULT_ORDER_ID, 1., 1); + List orders = Collections.singletonList(order1); + given(this.orderService.getAllOrdersForCustomer(DEFAULT_CUSTOMER_ID)).willReturn(orders); + + this.mvc.perform(get("/customers/" + DEFAULT_CUSTOMER_ID + "/orders").accept(MediaTypes.HAL_JSON_VALUE)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$._embedded.orderList[0]._links.self.href", + is("http://localhost/customers/customer1/order1"))) + .andExpect(jsonPath("$._links.self.href", is("http://localhost/customers/customer1/orders"))); + } + + @Test + public void givenExistingCustomer_whenAllCustomersRequested_thenHalResourceRetrieved() throws Exception { + // customers + Customer retrievedCustomer = new Customer(DEFAULT_CUSTOMER_ID, "customerJohn", "companyOne"); + List customers = Collections.singletonList(retrievedCustomer); + given(this.customerService.allCustomers()).willReturn(customers); + // orders + Order order1 = new Order(DEFAULT_ORDER_ID, 1., 1); + List orders = Collections.singletonList(order1); + given(this.orderService.getAllOrdersForCustomer(DEFAULT_CUSTOMER_ID)).willReturn(orders); + + this.mvc.perform(get("/customers/").accept(MediaTypes.HAL_JSON_VALUE)) + .andExpect(status().isOk()) + .andExpect( + jsonPath("$._embedded.customerList[0]._links.self.href", is("http://localhost/customers/customer1"))) + .andExpect(jsonPath("$._embedded.customerList[0]._links.allOrders.href", + is("http://localhost/customers/customer1/orders"))) + .andExpect(jsonPath("$._links.self.href", is("http://localhost/customers"))); + } + +} diff --git a/spring-boot-rest/src/test/java/com/baeldung/web/FooControllerAppIntegrationTest.java b/spring-boot-rest/src/test/java/com/baeldung/web/FooControllerAppIntegrationTest.java index bd5b5eb58e..3300b91fde 100644 --- a/spring-boot-rest/src/test/java/com/baeldung/web/FooControllerAppIntegrationTest.java +++ b/spring-boot-rest/src/test/java/com/baeldung/web/FooControllerAppIntegrationTest.java @@ -27,7 +27,7 @@ public class FooControllerAppIntegrationTest { @Test public void whenFindPaginatedRequest_thenEmptyResponse() throws Exception { - this.mockMvc.perform(get("/auth/foos").param("page", "0") + this.mockMvc.perform(get("/foos").param("page", "0") .param("size", "2")) .andExpect(status().isOk()) .andExpect(content().json("[]")); diff --git a/spring-boot-rest/src/test/java/com/baeldung/web/FooControllerCustomEtagIntegrationTest.java b/spring-boot-rest/src/test/java/com/baeldung/web/FooControllerCustomEtagIntegrationTest.java index dc48c21b30..9e7b60ed8c 100644 --- a/spring-boot-rest/src/test/java/com/baeldung/web/FooControllerCustomEtagIntegrationTest.java +++ b/spring-boot-rest/src/test/java/com/baeldung/web/FooControllerCustomEtagIntegrationTest.java @@ -29,7 +29,7 @@ public class FooControllerCustomEtagIntegrationTest { @Autowired private MockMvc mvc; - private String FOOS_ENDPOINT = "/auth/foos/"; + private String FOOS_ENDPOINT = "/foos/"; private String CUSTOM_ETAG_ENDPOINT_SUFFIX = "/custom-etag"; private static String serializeFoo(Foo foo) throws Exception { diff --git a/spring-boot-rest/src/test/java/com/baeldung/web/FooControllerWebLayerIntegrationTest.java b/spring-boot-rest/src/test/java/com/baeldung/web/FooControllerWebLayerIntegrationTest.java index 7e41cf6393..bd98523b0a 100644 --- a/spring-boot-rest/src/test/java/com/baeldung/web/FooControllerWebLayerIntegrationTest.java +++ b/spring-boot-rest/src/test/java/com/baeldung/web/FooControllerWebLayerIntegrationTest.java @@ -51,7 +51,7 @@ public class FooControllerWebLayerIntegrationTest { doNothing().when(publisher) .publishEvent(any(PaginatedResultsRetrievedEvent.class)); - this.mockMvc.perform(get("/auth/foos").param("page", "0") + this.mockMvc.perform(get("/foos").param("page", "0") .param("size", "2")) .andExpect(status().isOk()) .andExpect(jsonPath("$",Matchers.hasSize(1))); diff --git a/spring-boot-rest/src/test/java/com/baeldung/web/FooPageableLiveTest.java b/spring-boot-rest/src/test/java/com/baeldung/web/FooPageableLiveTest.java index 359a62a4d8..6a365f3bd5 100644 --- a/spring-boot-rest/src/test/java/com/baeldung/web/FooPageableLiveTest.java +++ b/spring-boot-rest/src/test/java/com/baeldung/web/FooPageableLiveTest.java @@ -74,7 +74,7 @@ public class FooPageableLiveTest extends AbstractBasicLiveTest { } protected String getPageableURL() { - return "http://localhost:" + APPLICATION_PORT + "/spring-boot-rest/auth/foos/pageable"; + return "http://localhost:" + APPLICATION_PORT + "/spring-boot-rest/foos/pageable"; } } diff --git a/spring-boot-rest/src/test/java/com/baeldung/web/StudentControllerIntegrationTest.java b/spring-boot-rest/src/test/java/com/baeldung/web/StudentControllerIntegrationTest.java new file mode 100644 index 0000000000..54ac69ebeb --- /dev/null +++ b/spring-boot-rest/src/test/java/com/baeldung/web/StudentControllerIntegrationTest.java @@ -0,0 +1,76 @@ +package com.baeldung.web; + +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 org.springframework.web.server.MediaTypeNotSupportedStatusException; + +import com.baeldung.web.controller.students.Student; +import com.fasterxml.jackson.databind.ObjectMapper; + +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +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.post; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; + +@RunWith(SpringRunner.class) +@SpringBootTest +@AutoConfigureMockMvc +public class StudentControllerIntegrationTest { + + private static final String STUDENTS_PATH = "/students/"; + + @Autowired + private MockMvc mockMvc; + + @Test + public void whenReadAll_thenStatusIsOk() throws Exception { + this.mockMvc.perform(get(STUDENTS_PATH)) + .andExpect(status().isOk()); + } + + @Test + public void whenReadOne_thenStatusIsOk() throws Exception { + this.mockMvc.perform(get(STUDENTS_PATH + 1)) + .andExpect(status().isOk()); + } + + @Test + public void whenCreate_thenStatusIsCreated() throws Exception { + Student student = new Student(10, "Albert", "Einstein"); + this.mockMvc.perform(post(STUDENTS_PATH).content(asJsonString(student)) + .contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(status().isCreated()); + } + + @Test + public void whenUpdate_thenStatusIsOk() throws Exception { + Student student = new Student(1, "Nikola", "Tesla"); + this.mockMvc.perform(put(STUDENTS_PATH + 1) + .content(asJsonString(student)) + .contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(status().isOk()); + } + + @Test + public void whenDelete_thenStatusIsNoContent() throws Exception { + this.mockMvc.perform(delete(STUDENTS_PATH + 3)) + .andExpect(status().isNoContent()); + } + + private String asJsonString(final Object obj) { + try { + return new ObjectMapper().writeValueAsString(obj); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + +} diff --git a/spring-boot-rest/src/test/resources/foo_API_test.postman_collection.json b/spring-boot-rest/src/test/resources/foo_API_test.postman_collection.json index 5a6230bd22..dc4acafab3 100644 --- a/spring-boot-rest/src/test/resources/foo_API_test.postman_collection.json +++ b/spring-boot-rest/src/test/resources/foo_API_test.postman_collection.json @@ -42,15 +42,14 @@ "raw": "{\n \"name\": \"Transformers\"\n}" }, "url": { - "raw": "http://localhost:8082/spring-boot-rest/auth/foos", + "raw": "http://localhost:8080/spring-boot-rest/foos", "protocol": "http", "host": [ "localhost" ], - "port": "8082", + "port": "8080", "path": [ "spring-boot-rest", - "auth", "foos" ] } @@ -85,15 +84,14 @@ "raw": "" }, "url": { - "raw": "http://localhost:8082/spring-boot-rest/auth/foos/{{id}}", + "raw": "http://localhost:8080/spring-boot-rest/foos/{{id}}", "protocol": "http", "host": [ "localhost" ], - "port": "8082", + "port": "8080", "path": [ "spring-boot-rest", - "auth", "foos", "{{id}}" ] @@ -123,15 +121,14 @@ "raw": "" }, "url": { - "raw": "http://localhost:8082/spring-boot-rest/auth/foos/{{id}}", + "raw": "http://localhost:8080/spring-boot-rest/foos/{{id}}", "protocol": "http", "host": [ "localhost" ], - "port": "8082", + "port": "8080", "path": [ "spring-boot-rest", - "auth", "foos", "{{id}}" ] @@ -164,15 +161,14 @@ "raw": "" }, "url": { - "raw": "http://localhost:8082/spring-boot-rest/auth/foos/{{id}}", + "raw": "http://localhost:8080/spring-boot-rest/foos/{{id}}", "protocol": "http", "host": [ "localhost" ], - "port": "8082", + "port": "8080", "path": [ "spring-boot-rest", - "auth", "foos", "{{id}}" ] diff --git a/spring-boot-security/pom.xml b/spring-boot-security/pom.xml index aaa0fbf4c7..79a77775de 100644 --- a/spring-boot-security/pom.xml +++ b/spring-boot-security/pom.xml @@ -8,10 +8,10 @@ jar - parent-boot-1 + parent-boot-2 com.baeldung 0.0.1-SNAPSHOT - ../parent-boot-1 + ../parent-boot-2 @@ -22,6 +22,12 @@ org.springframework.security.oauth spring-security-oauth2 + 2.3.3.RELEASE + + + org.springframework.security.oauth.boot + spring-security-oauth2-autoconfigure + 2.1.2.RELEASE org.springframework.boot @@ -55,6 +61,12 @@ spring-security-test test + + org.springframework.boot + spring-boot-autoconfigure + 2.1.1.RELEASE + + diff --git a/spring-boot-security/src/main/java/com/baeldung/integrationtesting/WebSecurityConfigurer.java b/spring-boot-security/src/main/java/com/baeldung/integrationtesting/WebSecurityConfigurer.java index 32a48ce612..1437440668 100644 --- a/spring-boot-security/src/main/java/com/baeldung/integrationtesting/WebSecurityConfigurer.java +++ b/spring-boot-security/src/main/java/com/baeldung/integrationtesting/WebSecurityConfigurer.java @@ -1,18 +1,24 @@ package com.baeldung.integrationtesting; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; @Configuration public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter { @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { + + BCryptPasswordEncoder encoder = passwordEncoder(); + auth.inMemoryAuthentication() + .passwordEncoder(encoder) .withUser("spring") - .password("secret") + .password(encoder.encode("secret")) .roles("USER"); } @@ -27,5 +33,8 @@ public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter { .httpBasic(); } - + @Bean + public BCryptPasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } } diff --git a/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/basic_auth/SpringBootSecurityApplication.java b/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/basic_auth/SpringBootSecurityApplication.java index 2ecad4ae35..7007c15596 100644 --- a/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/basic_auth/SpringBootSecurityApplication.java +++ b/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/basic_auth/SpringBootSecurityApplication.java @@ -2,14 +2,13 @@ package com.baeldung.springbootsecurity.basic_auth; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration; +import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; @SpringBootApplication(exclude = { SecurityAutoConfiguration.class // ,ManagementWebSecurityAutoConfiguration.class }, scanBasePackages = "com.baeldung.springbootsecurity.basic_auth") public class SpringBootSecurityApplication { - public static void main(String[] args) { SpringApplication.run(SpringBootSecurityApplication.class, args); } diff --git a/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/basic_auth/config/BasicAuthConfiguration.java b/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/basic_auth/config/BasicAuthConfiguration.java index 993c573fb0..592ef5354d 100644 --- a/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/basic_auth/config/BasicAuthConfiguration.java +++ b/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/basic_auth/config/BasicAuthConfiguration.java @@ -5,6 +5,8 @@ import org.springframework.security.config.annotation.authentication.builders.Au 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.springframework.security.crypto.factory.PasswordEncoderFactories; +import org.springframework.security.crypto.password.PasswordEncoder; @Configuration @EnableWebSecurity @@ -12,14 +14,15 @@ public class BasicAuthConfiguration extends WebSecurityConfigurerAdapter { @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { - auth + PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder(); + auth .inMemoryAuthentication() .withUser("user") - .password("password") + .password(encoder.encode("password")) .roles("USER") .and() .withUser("admin") - .password("admin") + .password(encoder.encode("admin")) .roles("USER", "ADMIN"); } diff --git a/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/oauth2server/config/AuthenticationMananagerConfig.java b/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/oauth2server/config/AuthenticationMananagerConfig.java new file mode 100644 index 0000000000..2b4135f36d --- /dev/null +++ b/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/oauth2server/config/AuthenticationMananagerConfig.java @@ -0,0 +1,18 @@ +package com.baeldung.springbootsecurity.oauth2server.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; + +@Configuration +@Profile("authz") +public class AuthenticationMananagerConfig extends WebSecurityConfigurerAdapter { + + @Bean + @Override + public AuthenticationManager authenticationManagerBean() throws Exception { + return super.authenticationManagerBean(); + } +} \ No newline at end of file diff --git a/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/oauth2server/config/AuthorizationServerConfig.java b/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/oauth2server/config/AuthorizationServerConfig.java index b403feb5c1..6e21987a89 100644 --- a/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/oauth2server/config/AuthorizationServerConfig.java +++ b/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/oauth2server/config/AuthorizationServerConfig.java @@ -1,9 +1,11 @@ package com.baeldung.springbootsecurity.oauth2server.config; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer; import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter; import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer; @@ -25,15 +27,20 @@ public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdap clients .inMemory() .withClient("baeldung") - .secret("baeldung") + .secret(passwordEncoder().encode("baeldung")) .authorizedGrantTypes("client_credentials", "password", "authorization_code") .scopes("openid", "read") .autoApprove(true) .and() .withClient("baeldung-admin") - .secret("baeldung") + .secret(passwordEncoder().encode("baeldung")) .authorizedGrantTypes("authorization_code", "client_credentials", "refresh_token") .scopes("read", "write") .autoApprove(true); } + + @Bean + public BCryptPasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } } diff --git a/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/oauth2server/config/WebSecurityConfiguration.java b/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/oauth2server/config/WebSecurityConfiguration.java new file mode 100644 index 0000000000..3a8c073870 --- /dev/null +++ b/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/oauth2server/config/WebSecurityConfiguration.java @@ -0,0 +1,17 @@ +package com.baeldung.springbootsecurity.oauth2server.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; + +@Configuration +@Profile("!authz") +public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { + + @Bean + public AuthenticationManager customAuthenticationManager() throws Exception { + return authenticationManager(); + } +} diff --git a/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/oauth2sso/SpringBootOAuth2SsoApplication.java b/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/oauth2sso/SpringBootOAuth2SsoApplication.java index b1cd580f08..342c246e66 100644 --- a/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/oauth2sso/SpringBootOAuth2SsoApplication.java +++ b/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/oauth2sso/SpringBootOAuth2SsoApplication.java @@ -1,6 +1,7 @@ package com.baeldung.springbootsecurity.oauth2sso; import org.springframework.boot.autoconfigure.SpringBootApplication; + import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso; import org.springframework.boot.builder.SpringApplicationBuilder; diff --git a/spring-boot-security/src/main/java/com/baeldung/springsecuritytaglibs/config/SpringBootSecurityTagLibsConfig.java b/spring-boot-security/src/main/java/com/baeldung/springsecuritytaglibs/config/SpringBootSecurityTagLibsConfig.java index 665dd0bce9..75bc613bd1 100644 --- a/spring-boot-security/src/main/java/com/baeldung/springsecuritytaglibs/config/SpringBootSecurityTagLibsConfig.java +++ b/spring-boot-security/src/main/java/com/baeldung/springsecuritytaglibs/config/SpringBootSecurityTagLibsConfig.java @@ -1,10 +1,12 @@ package com.baeldung.springsecuritytaglibs.config; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 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.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; @Configuration @EnableWebSecurity @@ -12,9 +14,11 @@ public class SpringBootSecurityTagLibsConfig extends WebSecurityConfigurerAdapte @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { + BCryptPasswordEncoder encoder = passwordEncoder(); auth.inMemoryAuthentication() + .passwordEncoder(encoder) .withUser("testUser") - .password("password") + .password(encoder.encode("password")) .roles("ADMIN"); } @@ -28,4 +32,9 @@ public class SpringBootSecurityTagLibsConfig extends WebSecurityConfigurerAdapte .anyRequest().permitAll().and().httpBasic(); // @formatter:on } + + @Bean + public BCryptPasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } } \ No newline at end of file diff --git a/spring-boot-security/src/main/resources/application-authz.properties b/spring-boot-security/src/main/resources/application-authz.properties index d29b0cdd3c..0c53999bb3 100644 --- a/spring-boot-security/src/main/resources/application-authz.properties +++ b/spring-boot-security/src/main/resources/application-authz.properties @@ -1,3 +1,3 @@ -security.user.password=password +spring.security.user.password=password security.oauth2.client.client-id=client security.oauth2.client.client-secret=secret diff --git a/spring-boot-security/src/main/resources/application-taglibs.properties b/spring-boot-security/src/main/resources/application-taglibs.properties index 218868405f..3e482ed92a 100644 --- a/spring-boot-security/src/main/resources/application-taglibs.properties +++ b/spring-boot-security/src/main/resources/application-taglibs.properties @@ -1,3 +1,3 @@ #jsp config -spring.mvc.view.prefix: /WEB-INF/views/ -spring.mvc.view.suffix: .jsp +spring.mvc.view.prefix= /WEB-INF/views/ +spring.mvc.view.suffix= .jsp diff --git a/spring-boot-security/src/test/java/com/baeldung/springbootsecurity/basic_auth/BasicAuthConfigurationIntegrationTest.java b/spring-boot-security/src/test/java/com/baeldung/springbootsecurity/basic_auth/BasicAuthConfigurationIntegrationTest.java index 32c3fbdef4..c091aa6d75 100644 --- a/spring-boot-security/src/test/java/com/baeldung/springbootsecurity/basic_auth/BasicAuthConfigurationIntegrationTest.java +++ b/spring-boot-security/src/test/java/com/baeldung/springbootsecurity/basic_auth/BasicAuthConfigurationIntegrationTest.java @@ -1,10 +1,10 @@ package com.baeldung.springbootsecurity.basic_auth; -import com.baeldung.springbootsecurity.basic_auth.SpringBootSecurityApplication; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.springframework.boot.context.embedded.LocalServerPort; +import org.springframework.boot.web.server.LocalServerPort; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.http.HttpStatus; @@ -16,9 +16,9 @@ import java.net.MalformedURLException; import java.net.URL; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; - @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = RANDOM_PORT, classes = SpringBootSecurityApplication.class) public class BasicAuthConfigurationIntegrationTest { @@ -50,8 +50,6 @@ public class BasicAuthConfigurationIntegrationTest { ResponseEntity response = restTemplate.getForEntity(base.toString(), String.class); assertEquals(HttpStatus.UNAUTHORIZED, response.getStatusCode()); - assertTrue(response - .getBody() - .contains("Unauthorized")); + assertNull(response.getBody()); } } diff --git a/spring-boot-security/src/test/java/com/baeldung/springsecuritytaglibs/HomeControllerIntegrationTest.java b/spring-boot-security/src/test/java/com/baeldung/springsecuritytaglibs/HomeControllerUnitTest.java similarity index 98% rename from spring-boot-security/src/test/java/com/baeldung/springsecuritytaglibs/HomeControllerIntegrationTest.java rename to spring-boot-security/src/test/java/com/baeldung/springsecuritytaglibs/HomeControllerUnitTest.java index 654e7925b9..0585c06a59 100644 --- a/spring-boot-security/src/test/java/com/baeldung/springsecuritytaglibs/HomeControllerIntegrationTest.java +++ b/spring-boot-security/src/test/java/com/baeldung/springsecuritytaglibs/HomeControllerUnitTest.java @@ -13,7 +13,7 @@ import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, classes = SpringBootSecurityTagLibsApplication.class) -public class HomeControllerIntegrationTest { +public class HomeControllerUnitTest { @Autowired private TestRestTemplate restTemplate; diff --git a/spring-boot-testing/pom.xml b/spring-boot-testing/pom.xml index caf48276b6..84107070bd 100644 --- a/spring-boot-testing/pom.xml +++ b/spring-boot-testing/pom.xml @@ -101,7 +101,7 @@ org.codehaus.gmavenplus gmavenplus-plugin - 1.6 + ${gmavenplus-plugin.version} @@ -119,6 +119,7 @@ com.baeldung.boot.Application 2.2.4 1.2-groovy-2.4 + 1.6 diff --git a/spring-boot-testing/src/main/java/com/baeldung/component/OtherComponent.java b/spring-boot-testing/src/main/java/com/baeldung/component/OtherComponent.java new file mode 100644 index 0000000000..97f001a9e5 --- /dev/null +++ b/spring-boot-testing/src/main/java/com/baeldung/component/OtherComponent.java @@ -0,0 +1,19 @@ +package com.baeldung.component; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +@Component +public class OtherComponent { + + private static final Logger LOG = LoggerFactory.getLogger(OtherComponent.class); + + public void processData() { + LOG.trace("This is a TRACE log from another package"); + LOG.debug("This is a DEBUG log from another package"); + LOG.info("This is an INFO log from another package"); + LOG.error("This is an ERROR log from another package"); + } + +} diff --git a/spring-boot-testing/src/main/java/com/baeldung/testloglevel/TestLogLevelApplication.java b/spring-boot-testing/src/main/java/com/baeldung/testloglevel/TestLogLevelApplication.java new file mode 100644 index 0000000000..ed8218c6a3 --- /dev/null +++ b/spring-boot-testing/src/main/java/com/baeldung/testloglevel/TestLogLevelApplication.java @@ -0,0 +1,15 @@ +package com.baeldung.testloglevel; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +import com.baeldung.boot.Application; + +@SpringBootApplication(scanBasePackages = {"com.baeldung.testloglevel", "com.baeldung.component"}) +public class TestLogLevelApplication { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} diff --git a/spring-boot-testing/src/main/java/com/baeldung/testloglevel/TestLogLevelController.java b/spring-boot-testing/src/main/java/com/baeldung/testloglevel/TestLogLevelController.java new file mode 100644 index 0000000000..22078562b4 --- /dev/null +++ b/spring-boot-testing/src/main/java/com/baeldung/testloglevel/TestLogLevelController.java @@ -0,0 +1,31 @@ +package com.baeldung.testloglevel; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.baeldung.component.OtherComponent; + +@RestController +public class TestLogLevelController { + + private static final Logger LOG = LoggerFactory.getLogger(TestLogLevelController.class); + + @Autowired + private OtherComponent otherComponent; + + @GetMapping("/testLogLevel") + public String testLogLevel() { + LOG.trace("This is a TRACE log"); + LOG.debug("This is a DEBUG log"); + LOG.info("This is an INFO log"); + LOG.error("This is an ERROR log"); + + otherComponent.processData(); + + return "Added some log output to console..."; + } + +} diff --git a/spring-boot-testing/src/test/java/com/baeldung/testloglevel/LogbackMultiProfileTestLogLevelIntegrationTest.java b/spring-boot-testing/src/test/java/com/baeldung/testloglevel/LogbackMultiProfileTestLogLevelIntegrationTest.java new file mode 100644 index 0000000000..7a1eb4adbe --- /dev/null +++ b/spring-boot-testing/src/test/java/com/baeldung/testloglevel/LogbackMultiProfileTestLogLevelIntegrationTest.java @@ -0,0 +1,70 @@ +package com.baeldung.testloglevel; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.boot.test.rule.OutputCapture; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, classes = TestLogLevelApplication.class) +@EnableAutoConfiguration(exclude = SecurityAutoConfiguration.class) +@ActiveProfiles("logback-test2") +public class LogbackMultiProfileTestLogLevelIntegrationTest { + + @Autowired + private TestRestTemplate restTemplate; + + @Rule + public OutputCapture outputCapture = new OutputCapture(); + + private String baseUrl = "/testLogLevel"; + + @Test + public void givenErrorRootLevelAndTraceLevelForOurPackage_whenCall_thenPrintTraceLogsForOurPackage() { + ResponseEntity response = restTemplate.getForEntity(baseUrl, String.class); + + assertThat(response.getStatusCode().value()).isEqualTo(200); + assertThatOutputContainsLogForOurPackage("TRACE"); + } + + @Test + public void givenErrorRootLevelAndTraceLevelForOurPackage_whenCall_thenNoTraceLogsForOtherPackages() { + ResponseEntity response = restTemplate.getForEntity(baseUrl, String.class); + + assertThat(response.getStatusCode().value()).isEqualTo(200); + assertThatOutputDoesntContainLogForOtherPackages("TRACE"); + } + + @Test + public void givenErrorRootLevelAndTraceLevelForOurPackage_whenCall_thenPrintErrorLogs() { + ResponseEntity response = restTemplate.getForEntity(baseUrl, String.class); + + assertThat(response.getStatusCode().value()).isEqualTo(200); + assertThatOutputContainsLogForOurPackage("ERROR"); + assertThatOutputContainsLogForOtherPackages("ERROR"); + } + + private void assertThatOutputContainsLogForOurPackage(String level) { + assertThat(outputCapture.toString()).containsPattern("TestLogLevelController.*" + level + ".*"); + } + + private void assertThatOutputDoesntContainLogForOtherPackages(String level) { + assertThat(outputCapture.toString().replaceAll("(?m)^.*TestLogLevelController.*$", "")).doesNotContain(level); + } + + private void assertThatOutputContainsLogForOtherPackages(String level) { + assertThat(outputCapture.toString().replaceAll("(?m)^.*TestLogLevelController.*$", "")).contains(level); + } + +} diff --git a/spring-boot-testing/src/test/java/com/baeldung/testloglevel/LogbackTestLogLevelIntegrationTest.java b/spring-boot-testing/src/test/java/com/baeldung/testloglevel/LogbackTestLogLevelIntegrationTest.java new file mode 100644 index 0000000000..af3bafdc2e --- /dev/null +++ b/spring-boot-testing/src/test/java/com/baeldung/testloglevel/LogbackTestLogLevelIntegrationTest.java @@ -0,0 +1,70 @@ +package com.baeldung.testloglevel; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.boot.test.rule.OutputCapture; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, classes = TestLogLevelApplication.class) +@EnableAutoConfiguration(exclude = SecurityAutoConfiguration.class) +@ActiveProfiles("logback-test") +public class LogbackTestLogLevelIntegrationTest { + + @Autowired + private TestRestTemplate restTemplate; + + @Rule + public OutputCapture outputCapture = new OutputCapture(); + + private String baseUrl = "/testLogLevel"; + + @Test + public void givenErrorRootLevelAndDebugLevelForOurPackage_whenCall_thenPrintDebugLogsForOurPackage() { + ResponseEntity response = restTemplate.getForEntity(baseUrl, String.class); + + assertThat(response.getStatusCode().value()).isEqualTo(200); + assertThatOutputContainsLogForOurPackage("DEBUG"); + } + + @Test + public void givenErrorRootLevelAndDebugLevelForOurPackage_whenCall_thenNoDebugLogsForOtherPackages() { + ResponseEntity response = restTemplate.getForEntity(baseUrl, String.class); + + assertThat(response.getStatusCode().value()).isEqualTo(200); + assertThatOutputDoesntContainLogForOtherPackages("DEBUG"); + } + + @Test + public void givenErrorRootLevelAndDebugLevelForOurPackage_whenCall_thenPrintErrorLogs() { + ResponseEntity response = restTemplate.getForEntity(baseUrl, String.class); + + assertThat(response.getStatusCode().value()).isEqualTo(200); + assertThatOutputContainsLogForOurPackage("ERROR"); + assertThatOutputContainsLogForOtherPackages("ERROR"); + } + + private void assertThatOutputContainsLogForOurPackage(String level) { + assertThat(outputCapture.toString()).containsPattern("TestLogLevelController.*" + level + ".*"); + } + + private void assertThatOutputDoesntContainLogForOtherPackages(String level) { + assertThat(outputCapture.toString().replaceAll("(?m)^.*TestLogLevelController.*$", "")).doesNotContain(level); + } + + private void assertThatOutputContainsLogForOtherPackages(String level) { + assertThat(outputCapture.toString().replaceAll("(?m)^.*TestLogLevelController.*$", "")).contains(level); + } + +} diff --git a/spring-boot-testing/src/test/java/com/baeldung/testloglevel/TestLogLevelWithProfileIntegrationTest.java b/spring-boot-testing/src/test/java/com/baeldung/testloglevel/TestLogLevelWithProfileIntegrationTest.java new file mode 100644 index 0000000000..5609ce6c01 --- /dev/null +++ b/spring-boot-testing/src/test/java/com/baeldung/testloglevel/TestLogLevelWithProfileIntegrationTest.java @@ -0,0 +1,70 @@ +package com.baeldung.testloglevel; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.boot.test.rule.OutputCapture; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, classes = TestLogLevelApplication.class) +@EnableAutoConfiguration(exclude = SecurityAutoConfiguration.class) +@ActiveProfiles("logging-test") +public class TestLogLevelWithProfileIntegrationTest { + + @Autowired + private TestRestTemplate restTemplate; + + @Rule + public OutputCapture outputCapture = new OutputCapture(); + + private String baseUrl = "/testLogLevel"; + + @Test + public void givenInfoRootLevelAndDebugLevelForOurPackage_whenCall_thenPrintDebugLogsForOurPackage() { + ResponseEntity response = restTemplate.getForEntity(baseUrl, String.class); + + assertThat(response.getStatusCode().value()).isEqualTo(200); + assertThatOutputContainsLogForOurPackage("DEBUG"); + } + + @Test + public void givenInfoRootLevelAndDebugLevelForOurPackage_whenCall_thenNoDebugLogsForOtherPackages() { + ResponseEntity response = restTemplate.getForEntity(baseUrl, String.class); + + assertThat(response.getStatusCode().value()).isEqualTo(200); + assertThatOutputDoesntContainLogForOtherPackages("DEBUG"); + } + + @Test + public void givenInfoRootLevelAndDebugLevelForOurPackage_whenCall_thenPrintInfoLogs() { + ResponseEntity response = restTemplate.getForEntity(baseUrl, String.class); + + assertThat(response.getStatusCode().value()).isEqualTo(200); + assertThatOutputContainsLogForOurPackage("INFO"); + assertThatOutputContainsLogForOtherPackages("INFO"); + } + + private void assertThatOutputContainsLogForOurPackage(String level) { + assertThat(outputCapture.toString()).containsPattern("TestLogLevelController.*" + level + ".*"); + } + + private void assertThatOutputDoesntContainLogForOtherPackages(String level) { + assertThat(outputCapture.toString().replaceAll("(?m)^.*TestLogLevelController.*$", "")).doesNotContain(level); + } + + private void assertThatOutputContainsLogForOtherPackages(String level) { + assertThat(outputCapture.toString().replaceAll("(?m)^.*TestLogLevelController.*$", "")).contains(level); + } + +} diff --git a/spring-boot-testing/src/test/resources/application-logback-test.properties b/spring-boot-testing/src/test/resources/application-logback-test.properties new file mode 100644 index 0000000000..587302fa01 --- /dev/null +++ b/spring-boot-testing/src/test/resources/application-logback-test.properties @@ -0,0 +1 @@ +logging.config=classpath:logback-test.xml diff --git a/spring-boot-testing/src/test/resources/application-logback-test2.properties b/spring-boot-testing/src/test/resources/application-logback-test2.properties new file mode 100644 index 0000000000..aeed46e3ca --- /dev/null +++ b/spring-boot-testing/src/test/resources/application-logback-test2.properties @@ -0,0 +1 @@ +logging.config=classpath:logback-multiprofile.xml \ No newline at end of file diff --git a/spring-boot-testing/src/test/resources/application-logging-test.properties b/spring-boot-testing/src/test/resources/application-logging-test.properties new file mode 100644 index 0000000000..b5adb4cc11 --- /dev/null +++ b/spring-boot-testing/src/test/resources/application-logging-test.properties @@ -0,0 +1,2 @@ +logging.level.com.baeldung.testloglevel=DEBUG +logging.level.root=INFO \ No newline at end of file diff --git a/spring-boot-testing/src/test/resources/logback-multiprofile.xml b/spring-boot-testing/src/test/resources/logback-multiprofile.xml new file mode 100644 index 0000000000..be790234f2 --- /dev/null +++ b/spring-boot-testing/src/test/resources/logback-multiprofile.xml @@ -0,0 +1,18 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + + + + diff --git a/spring-boot-testing/src/test/resources/logback-test.xml b/spring-boot-testing/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..0528aa88f3 --- /dev/null +++ b/spring-boot-testing/src/test/resources/logback-test.xml @@ -0,0 +1,13 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + diff --git a/spring-boot/README.MD b/spring-boot/README.MD index 28123687fd..c0392d38de 100644 --- a/spring-boot/README.MD +++ b/spring-boot/README.MD @@ -6,12 +6,12 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring - [A Guide to Spring in Eclipse STS](http://www.baeldung.com/eclipse-sts-spring) - [The @ServletComponentScan Annotation in Spring Boot](http://www.baeldung.com/spring-servletcomponentscan) - [Intro to Building an Application with Spring Boot](http://www.baeldung.com/intro-to-spring-boot) -- [How to Register a Servlet in a Java Web Application](http://www.baeldung.com/register-servlet) +- [How to Register a Servlet in Java](http://www.baeldung.com/register-servlet) - [Guide to Spring WebUtils and ServletRequestUtils](http://www.baeldung.com/spring-webutils-servletrequestutils) - [Using Custom Banners in Spring Boot](http://www.baeldung.com/spring-boot-custom-banners) - [Guide to Internationalization in Spring Boot](http://www.baeldung.com/spring-boot-internationalization) - [Create a Custom FailureAnalyzer with Spring Boot](http://www.baeldung.com/spring-boot-failure-analyzer) -- [Dynamic DTO Validation Config Retrieved from DB](http://www.baeldung.com/spring-dynamic-dto-validation) +- [Dynamic DTO Validation Config Retrieved from the Database](http://www.baeldung.com/spring-dynamic-dto-validation) - [Custom Information in Spring Boot Info Endpoint](http://www.baeldung.com/spring-boot-info-actuator-custom) - [Using @JsonComponent in Spring Boot](http://www.baeldung.com/spring-boot-jsoncomponent) - [Testing in Spring Boot](http://www.baeldung.com/spring-boot-testing) @@ -21,14 +21,13 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring - [Getting Started with GraphQL and Spring Boot](http://www.baeldung.com/spring-graphql) - [Guide to Spring Type Conversions](http://www.baeldung.com/spring-type-conversions) - [An Introduction to Kong](http://www.baeldung.com/kong) -- [Spring Boot Customize Whitelabel Error Page](http://www.baeldung.com/spring-boot-custom-error-page) +- [Spring Boot: Customize Whitelabel Error Page](http://www.baeldung.com/spring-boot-custom-error-page) - [Spring Boot: Configuring a Main Class](http://www.baeldung.com/spring-boot-main-class) - [A Quick Intro to the SpringBootServletInitializer](http://www.baeldung.com/spring-boot-servlet-initializer) - [How to Define a Spring Boot Filter?](http://www.baeldung.com/spring-boot-add-filter) - [Spring Boot Exit Codes](http://www.baeldung.com/spring-boot-exit-codes) - [Guide to the Favicon in Spring Boot](http://www.baeldung.com/spring-boot-favicon) - [Spring Shutdown Callbacks](http://www.baeldung.com/spring-shutdown-callbacks) -- [Spring Boot Integration Testing with Embedded MongoDB](http://www.baeldung.com/spring-boot-embedded-mongodb) - [Container Configuration in Spring Boot 2](http://www.baeldung.com/embeddedservletcontainercustomizer-configurableembeddedservletcontainer-spring-boot) - [Introduction to Chaos Monkey](https://www.baeldung.com/spring-boot-chaos-monkey) - [Spring Component Scanning](https://www.baeldung.com/spring-component-scanning) @@ -36,3 +35,4 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring - [Display Auto-Configuration Report in Spring Boot](https://www.baeldung.com/spring-boot-auto-configuration-report) - [Injecting Git Information Into Spring](https://www.baeldung.com/spring-git-information) - [Validation in Spring Boot](https://www.baeldung.com/spring-boot-bean-validation) +- [Guide to Creating and Running a Jar File in Java](https://www.baeldung.com/java-create-jar) diff --git a/spring-boot/pom.xml b/spring-boot/pom.xml index 2e463e0189..401e0289e8 100644 --- a/spring-boot/pom.xml +++ b/spring-boot/pom.xml @@ -15,16 +15,7 @@ - - - org.springframework.boot - spring-boot-starter-data-mongodb - - - de.flapdoodle.embed - de.flapdoodle.embed.mongo - test - + org.junit.jupiter @@ -162,12 +153,6 @@ javax.validation validation-api - - - org.modelmapper - modelmapper - ${modelmapper.version} - @@ -265,7 +250,6 @@ 5.2.4 18.0 2.2.4 - 2.3.2 diff --git a/spring-boot/src/main/java/com/baeldung/modelmapper/PostApplication.java b/spring-boot/src/main/java/com/baeldung/modelmapper/PostApplication.java deleted file mode 100644 index 7684c43648..0000000000 --- a/spring-boot/src/main/java/com/baeldung/modelmapper/PostApplication.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.baeldung.modelmapper; - -import org.modelmapper.ModelMapper; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.annotation.Bean; - -@SpringBootApplication -public class PostApplication { - - public static void main(String[] args) { - SpringApplication.run(PostApplication.class, args); - } - - @Bean - public ModelMapper modelMapper() { - return new ModelMapper(); - } - -} 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 3698d8ef30..1a3c985fe4 100644 --- a/spring-boot/src/main/java/org/baeldung/properties/ConfigProperties.java +++ b/spring-boot/src/main/java/org/baeldung/properties/ConfigProperties.java @@ -9,6 +9,7 @@ import javax.validation.constraints.NotBlank; import javax.validation.constraints.Pattern; import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import org.springframework.validation.annotation.Validated; @@ -80,4 +81,10 @@ public class ConfigProperties { public void setCredentials(Credentials credentials) { this.credentials = credentials; } + + @Bean + @ConfigurationProperties(prefix = "item") + public Item item(){ + return new Item(); + } } diff --git a/spring-boot/src/main/java/org/baeldung/properties/Item.java b/spring-boot/src/main/java/org/baeldung/properties/Item.java new file mode 100644 index 0000000000..0314654ada --- /dev/null +++ b/spring-boot/src/main/java/org/baeldung/properties/Item.java @@ -0,0 +1,31 @@ +package org.baeldung.properties; + +public class Item { + + private String name; + private int size; + + public Item() { + } + + public Item(String name, int size) { + this.name = name; + this.size = size; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getSize() { + return size; + } + + public void setSize(int size) { + this.size = size; + } +} diff --git a/spring-boot/src/main/resources/META-INF/spring.factories b/spring-boot/src/main/resources/META-INF/spring.factories index e3d3aa4c8e..336477df96 100644 --- a/spring-boot/src/main/resources/META-INF/spring.factories +++ b/spring-boot/src/main/resources/META-INF/spring.factories @@ -1 +1,2 @@ -org.springframework.boot.diagnostics.FailureAnalyzer=com.baeldung.failureanalyzer.MyBeanNotOfRequiredTypeFailureAnalyzer \ No newline at end of file +org.springframework.boot.diagnostics.FailureAnalyzer=com.baeldung.failureanalyzer.MyBeanNotOfRequiredTypeFailureAnalyzer + diff --git a/spring-boot/src/main/resources/configprops.properties b/spring-boot/src/main/resources/configprops.properties index 2dad11f9cc..424b3632f9 100644 --- a/spring-boot/src/main/resources/configprops.properties +++ b/spring-boot/src/main/resources/configprops.properties @@ -17,4 +17,8 @@ mail.credentials.username=john mail.credentials.password=password mail.credentials.authMethod=SHA1 +#Bean method properties +item.name=Item name +item.size=42 + diff --git a/spring-boot/src/test/java/com/baeldung/validation/tests/UserControllerIntegrationTest.java b/spring-boot/src/test/java/com/baeldung/validation/application/UserControllerIntegrationTest.java similarity index 96% rename from spring-boot/src/test/java/com/baeldung/validation/tests/UserControllerIntegrationTest.java rename to spring-boot/src/test/java/com/baeldung/validation/application/UserControllerIntegrationTest.java index 265c4ec22c..77a230ee6c 100644 --- a/spring-boot/src/test/java/com/baeldung/validation/tests/UserControllerIntegrationTest.java +++ b/spring-boot/src/test/java/com/baeldung/validation/application/UserControllerIntegrationTest.java @@ -1,4 +1,4 @@ -package com.baeldung.validation.tests; +package com.baeldung.validation.application; import com.baeldung.validation.application.controllers.UserController; import com.baeldung.validation.application.repositories.UserRepository; 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 4ba6bf29d8..f864fd4f8c 100644 --- a/spring-boot/src/test/java/org/baeldung/properties/ConfigPropertiesIntegrationTest.java +++ b/spring-boot/src/test/java/org/baeldung/properties/ConfigPropertiesIntegrationTest.java @@ -53,4 +53,11 @@ public class ConfigPropertiesIntegrationTest { Assert.assertEquals("Incorrectly bound object property, username", "john", credentials.getUsername()); Assert.assertEquals("Incorrectly bound object property, password", "password", credentials.getPassword()); } + + @Test + public void whenBeanMethodAnnotatedThenPropertiesCorrectlyBound(){ + Item item = properties.item(); + Assert.assertEquals("Incorrectly bound object property, item.name","Test item name", item.getName()); + Assert.assertEquals("Incorrectly bound object property, item.size", 21, item.getSize()); + } } diff --git a/spring-boot/src/test/resources/configprops-test.properties b/spring-boot/src/test/resources/configprops-test.properties index 697771ae6e..ea11f2159e 100644 --- a/spring-boot/src/test/resources/configprops-test.properties +++ b/spring-boot/src/test/resources/configprops-test.properties @@ -17,3 +17,6 @@ mail.credentials.username=john mail.credentials.password=password mail.credentials.authMethod=SHA1 +#Bean method properties +item.name=Test item name +item.size=21 diff --git a/spring-cloud-data-flow/apache-spark-job/pom.xml b/spring-cloud-data-flow/apache-spark-job/pom.xml new file mode 100644 index 0000000000..671e8ed71a --- /dev/null +++ b/spring-cloud-data-flow/apache-spark-job/pom.xml @@ -0,0 +1,43 @@ + + + 4.0.0 + apache-spark-job + + + spring-cloud-data-flow + com.baeldung + 0.0.1-SNAPSHOT + + + + + org.springframework.cloud + spring-cloud-task-core + ${spring-cloud-task-core.version} + + + org.apache.spark + spark-core_${scala.version} + ${spark.version} + + + log4j + log4j + + + org.slf4j + slf4j-log4j12 + + + + + + + 1.6.2 + 2.10 + 2.0.0.RELEASE + + + \ No newline at end of file diff --git a/spring-cloud-data-flow/apache-spark-job/src/main/java/com/baeldung/spring/cloud/PiApproximation.java b/spring-cloud-data-flow/apache-spark-job/src/main/java/com/baeldung/spring/cloud/PiApproximation.java new file mode 100644 index 0000000000..dfead21728 --- /dev/null +++ b/spring-cloud-data-flow/apache-spark-job/src/main/java/com/baeldung/spring/cloud/PiApproximation.java @@ -0,0 +1,39 @@ +package com.baeldung.spring.cloud; + +import org.apache.spark.SparkConf; +import org.apache.spark.api.java.JavaRDD; +import org.apache.spark.api.java.JavaSparkContext; +import org.apache.spark.api.java.function.Function; +import org.apache.spark.api.java.function.Function2; +import org.apache.spark.rdd.RDD; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +public class PiApproximation { + public static void main(String[] args) { + SparkConf conf = new SparkConf().setAppName("BaeldungPIApproximation"); + JavaSparkContext context = new JavaSparkContext(conf); + int slices = args.length >= 1 ? Integer.valueOf(args[0]) : 2; + int n = (100000L * slices) > Integer.MAX_VALUE ? Integer.MAX_VALUE : 100000 * slices; + + List xs = IntStream.rangeClosed(0, n) + .mapToObj(element -> Integer.valueOf(element)) + .collect(Collectors.toList()); + + JavaRDD dataSet = context.parallelize(xs, slices); + + JavaRDD pointsInsideTheCircle = dataSet.map(integer -> { + double x = Math.random() * 2 - 1; + double y = Math.random() * 2 - 1; + return (x*x + y*y ) < 1 ? 1: 0; + }); + + int count = pointsInsideTheCircle.reduce((integer, integer2) -> integer + integer2); + + System.out.println("The pi was estimated as:" + count / n); + + context.stop(); + } +} diff --git a/spring-cloud-data-flow/pom.xml b/spring-cloud-data-flow/pom.xml index daf8ebd2c8..36a780c28d 100644 --- a/spring-cloud-data-flow/pom.xml +++ b/spring-cloud-data-flow/pom.xml @@ -20,6 +20,7 @@ log-sink batch-job etl + apache-spark-job diff --git a/spring-cloud/README.md b/spring-cloud/README.md index fede3cc12d..5139cdca20 100644 --- a/spring-cloud/README.md +++ b/spring-cloud/README.md @@ -17,4 +17,5 @@ - [Dockerizing a Spring Boot Application](http://www.baeldung.com/dockerizing-spring-boot-application) - [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) +- [Introduction to Spring Cloud OpenFeign](https://www.baeldung.com/spring-cloud-openfeign) diff --git a/spring-cloud/spring-cloud-archaius/additional-sources-simple/src/main/java/com/baeldung/spring/cloud/archaius/additionalsources/config/ApplicationPropertiesConfigurations.java b/spring-cloud/spring-cloud-archaius/additional-sources-simple/src/main/java/com/baeldung/spring/cloud/archaius/additionalsources/config/ApplicationPropertiesConfigurations.java index f2d8ca2638..04d49d967f 100644 --- a/spring-cloud/spring-cloud-archaius/additional-sources-simple/src/main/java/com/baeldung/spring/cloud/archaius/additionalsources/config/ApplicationPropertiesConfigurations.java +++ b/spring-cloud/spring-cloud-archaius/additional-sources-simple/src/main/java/com/baeldung/spring/cloud/archaius/additionalsources/config/ApplicationPropertiesConfigurations.java @@ -1,8 +1,12 @@ package com.baeldung.spring.cloud.archaius.additionalsources.config; +import java.io.IOException; +import java.net.URL; + import org.apache.commons.configuration.AbstractConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.ClassPathResource; import com.netflix.config.DynamicConfiguration; import com.netflix.config.FixedDelayPollingScheduler; @@ -13,8 +17,9 @@ import com.netflix.config.sources.URLConfigurationSource; public class ApplicationPropertiesConfigurations { @Bean - public AbstractConfiguration addApplicationPropertiesSource() { - PolledConfigurationSource source = new URLConfigurationSource("classpath:other-config.properties"); + public AbstractConfiguration addApplicationPropertiesSource() throws IOException { + URL configPropertyURL = (new ClassPathResource("other-config.properties")).getURL(); + PolledConfigurationSource source = new URLConfigurationSource(configPropertyURL); return new DynamicConfiguration(source, new FixedDelayPollingScheduler()); } diff --git a/spring-cloud/spring-cloud-archaius/additional-sources-simple/src/test/java/org/baeldung/SpringContextIntegrationTest.java b/spring-cloud/spring-cloud-archaius/additional-sources-simple/src/test/java/com/baeldung/spring/cloud/archaius/additionalsources/SpringContextIntegrationTest.java similarity index 77% rename from spring-cloud/spring-cloud-archaius/additional-sources-simple/src/test/java/org/baeldung/SpringContextIntegrationTest.java rename to spring-cloud/spring-cloud-archaius/additional-sources-simple/src/test/java/com/baeldung/spring/cloud/archaius/additionalsources/SpringContextIntegrationTest.java index e5ebbce1aa..4811ebaa13 100644 --- a/spring-cloud/spring-cloud-archaius/additional-sources-simple/src/test/java/org/baeldung/SpringContextIntegrationTest.java +++ b/spring-cloud/spring-cloud-archaius/additional-sources-simple/src/test/java/com/baeldung/spring/cloud/archaius/additionalsources/SpringContextIntegrationTest.java @@ -1,12 +1,10 @@ -package org.baeldung; +package com.baeldung.spring.cloud.archaius.additionalsources; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; -import com.baeldung.spring.cloud.archaius.additionalsources.AdditionalSourcesSimpleApplication; - @RunWith(SpringRunner.class) @SpringBootTest(classes = AdditionalSourcesSimpleApplication.class) public class SpringContextIntegrationTest { diff --git a/spring-cloud/spring-cloud-archaius/basic-config/src/test/java/com/baeldung/spring/cloud/archaius/basic/ArchaiusBasicConfigurationIntegrationTest.java b/spring-cloud/spring-cloud-archaius/basic-config/src/test/java/com/baeldung/spring/cloud/archaius/basic/ArchaiusBasicConfigurationIntegrationTest.java index 2948606c0b..d49a8dfa7e 100644 --- a/spring-cloud/spring-cloud-archaius/basic-config/src/test/java/com/baeldung/spring/cloud/archaius/basic/ArchaiusBasicConfigurationIntegrationTest.java +++ b/spring-cloud/spring-cloud-archaius/basic-config/src/test/java/com/baeldung/spring/cloud/archaius/basic/ArchaiusBasicConfigurationIntegrationTest.java @@ -5,21 +5,18 @@ import static org.assertj.core.api.Assertions.assertThat; import java.util.Collections; import org.junit.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.junit.platform.runner.JUnitPlatform; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.util.TestPropertyValues; import org.springframework.cloud.context.environment.EnvironmentChangeEvent; import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.context.junit4.SpringRunner; import com.netflix.config.DynamicPropertyFactory; import com.netflix.config.DynamicStringProperty; -@RunWith(JUnitPlatform.class) -@ExtendWith(SpringExtension.class) +@RunWith(SpringRunner.class) @SpringBootTest public class ArchaiusBasicConfigurationIntegrationTest { diff --git a/spring-cloud/spring-cloud-archaius/dynamodb-config/src/test/java/com/baeldung/spring/cloud/archaius/dynamosources/SpringContextLiveTest.java b/spring-cloud/spring-cloud-archaius/dynamodb-config/src/test/java/com/baeldung/spring/cloud/archaius/dynamosources/SpringContextLiveTest.java new file mode 100644 index 0000000000..a1a6c46c60 --- /dev/null +++ b/spring-cloud/spring-cloud-archaius/dynamodb-config/src/test/java/com/baeldung/spring/cloud/archaius/dynamosources/SpringContextLiveTest.java @@ -0,0 +1,20 @@ +package com.baeldung.spring.cloud.archaius.dynamosources; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +/** + * To run this Live Test we need to: + * * start a dynamodb instance locally on port 8000(e.g. with the following command `docker run -p 8000:8000 --name bael-dynamodb amazon/dynamodb-local`) + * + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = DynamoSourcesApplication.class) +public class SpringContextLiveTest { + + @Test + public void whenSpringContextIsBootstrapped_thenNoExceptions() { + } +} \ No newline at end of file diff --git a/spring-cloud/spring-cloud-archaius/extra-configs/pom.xml b/spring-cloud/spring-cloud-archaius/extra-configs/pom.xml index c3c830f197..f7e5807f43 100644 --- a/spring-cloud/spring-cloud-archaius/extra-configs/pom.xml +++ b/spring-cloud/spring-cloud-archaius/extra-configs/pom.xml @@ -37,6 +37,7 @@ + 2.0.1.RELEASE diff --git a/spring-cloud/spring-cloud-archaius/jdbc-config/src/test/java/com/baeldung/spring/cloud/archaius/jdbconfig/SpringContextIntegrationTest.java b/spring-cloud/spring-cloud-archaius/jdbc-config/src/test/java/com/baeldung/spring/cloud/archaius/jdbconfig/SpringContextIntegrationTest.java new file mode 100644 index 0000000000..b3cd01e684 --- /dev/null +++ b/spring-cloud/spring-cloud-archaius/jdbc-config/src/test/java/com/baeldung/spring/cloud/archaius/jdbconfig/SpringContextIntegrationTest.java @@ -0,0 +1,15 @@ +package com.baeldung.spring.cloud.archaius.jdbconfig; + +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(classes = JdbcSourcesApplication.class) +public class SpringContextIntegrationTest { + + @Test + public void whenSpringContextIsBootstrapped_thenNoExceptions() { + } +} \ No newline at end of file diff --git a/spring-cloud/spring-cloud-archaius/zookeeper-config/src/test/java/com/baeldung/spring/cloud/archaius/zookeeperconfig/SpringContextLiveTest.java b/spring-cloud/spring-cloud-archaius/zookeeper-config/src/test/java/com/baeldung/spring/cloud/archaius/zookeeperconfig/SpringContextLiveTest.java new file mode 100644 index 0000000000..a827b8e27d --- /dev/null +++ b/spring-cloud/spring-cloud-archaius/zookeeper-config/src/test/java/com/baeldung/spring/cloud/archaius/zookeeperconfig/SpringContextLiveTest.java @@ -0,0 +1,20 @@ +package com.baeldung.spring.cloud.archaius.zookeeperconfig; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +/** + * This Live tTest requires: + * * A Zookeeper instance running locally on port 2181 (e.g. using `docker run --name bael-zookeeper -p 2181:2181 --restart always zookeeper`) + * + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = ZookeeperConfigApplication.class) +public class SpringContextLiveTest { + + @Test + public void whenSpringContextIsBootstrapped_thenNoExceptions() { + } +} \ No newline at end of file diff --git a/spring-cloud/spring-cloud-aws/README.md b/spring-cloud/spring-cloud-aws/README.md index 36d0c7080e..3b7b4dbcd7 100644 --- a/spring-cloud/spring-cloud-aws/README.md +++ b/spring-cloud/spring-cloud-aws/README.md @@ -8,7 +8,7 @@ #### Running the Integration Tests -To run the Integration Tests, we need to have an AWS account and have API keys generated for programmatic access. Edit +To run the Live Tests, we need to have an AWS account and have API keys generated for programmatic access. Edit the `application.properties` file to add the following properties: ``` diff --git a/spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/SpringContextLiveTest.java b/spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/SpringContextLiveTest.java new file mode 100644 index 0000000000..90ad9c518c --- /dev/null +++ b/spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/SpringContextLiveTest.java @@ -0,0 +1,22 @@ +package com.baeldung.spring.cloud.aws; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +/** + * + * To run this Live Test, we need to have an AWS account and have API keys generated for programmatic access. + * + * Check the README file in this module for more information. + * + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = SpringCloudAwsApplication.class) +public class SpringContextLiveTest { + + @Test + public void whenSpringContextIsBootstrapped_thenNoExceptions() { + } +} diff --git a/spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/ec2/EC2MetadataIntegrationTest.java b/spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/ec2/EC2MetadataLiveTest.java similarity index 86% rename from spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/ec2/EC2MetadataIntegrationTest.java rename to spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/ec2/EC2MetadataLiveTest.java index 1e75134194..853777ed25 100644 --- a/spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/ec2/EC2MetadataIntegrationTest.java +++ b/spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/ec2/EC2MetadataLiveTest.java @@ -16,12 +16,19 @@ import org.springframework.test.context.junit4.SpringRunner; import com.amazonaws.regions.Regions; import com.amazonaws.services.ec2.AmazonEC2; +/** + * + * To run this Live Test, we need to have an AWS account and have API keys generated for programmatic access. + * + * Check the README file in this module for more information. + * + */ @SpringBootTest @RunWith(SpringRunner.class) @TestPropertySource("classpath:application-test.properties") -public class EC2MetadataIntegrationTest { +public class EC2MetadataLiveTest { - private static final Logger logger = LoggerFactory.getLogger(EC2MetadataIntegrationTest.class); + private static final Logger logger = LoggerFactory.getLogger(EC2MetadataLiveTest.class); private boolean serverEc2; diff --git a/spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/rds/SpringCloudRDSIntegrationTest.java b/spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/rds/SpringCloudRDSLiveTest.java similarity index 85% rename from spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/rds/SpringCloudRDSIntegrationTest.java rename to spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/rds/SpringCloudRDSLiveTest.java index 9e163d6dc4..e7004c6b9f 100644 --- a/spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/rds/SpringCloudRDSIntegrationTest.java +++ b/spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/rds/SpringCloudRDSLiveTest.java @@ -14,9 +14,16 @@ import java.sql.Statement; import static org.assertj.core.api.Assertions.assertThat; +/** + * + * To run this Live Test, we need to have an AWS account and have API keys generated for programmatic access. + * + * Check the README file in this module for more information. + * + */ @SpringBootTest @RunWith(SpringRunner.class) -public class SpringCloudRDSIntegrationTest { +public class SpringCloudRDSLiveTest { @Autowired DataSource dataSource; diff --git a/spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/s3/SpringCloudS3IntegrationTest.java b/spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/s3/SpringCloudS3LiveTest.java similarity index 94% rename from spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/s3/SpringCloudS3IntegrationTest.java rename to spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/s3/SpringCloudS3LiveTest.java index a866287dec..dff3a06fe0 100644 --- a/spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/s3/SpringCloudS3IntegrationTest.java +++ b/spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/s3/SpringCloudS3LiveTest.java @@ -23,10 +23,17 @@ import java.util.UUID; import static org.assertj.core.api.Assertions.assertThat; +/** + * + * To run this Live Test, we need to have an AWS account and have API keys generated for programmatic access. + * + * Check the README file in this module for more information. + * + */ @SpringBootTest @RunWith(SpringRunner.class) @TestPropertySource("classpath:application-test.properties") -public class SpringCloudS3IntegrationTest { +public class SpringCloudS3LiveTest { @Autowired private SpringCloudS3 springCloudS3; diff --git a/spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/sns/SpringCloudSNSIntegrationTest.java b/spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/sns/SpringCloudSNSLiveTest.java similarity index 88% rename from spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/sns/SpringCloudSNSIntegrationTest.java rename to spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/sns/SpringCloudSNSLiveTest.java index e1f23d5c76..b773520089 100644 --- a/spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/sns/SpringCloudSNSIntegrationTest.java +++ b/spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/sns/SpringCloudSNSLiveTest.java @@ -16,10 +16,17 @@ import com.amazonaws.services.sns.model.CreateTopicResult; import com.baeldung.spring.cloud.aws.SpringCloudAwsTestUtil; import com.baeldung.spring.cloud.aws.sqs.Greeting; +/** + * + * To run this Live Test, we need to have an AWS account and have API keys generated for programmatic access. + * + * Check the README file in this module for more information. + * + */ @SpringBootTest @RunWith(SpringRunner.class) @TestPropertySource("classpath:application-test.properties") -public class SpringCloudSNSIntegrationTest { +public class SpringCloudSNSLiveTest { @Autowired private SNSMessageSender snsMessageSender; diff --git a/spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/sqs/SpringCloudSQSIntegrationTest.java b/spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/sqs/SpringCloudSQSLiveTest.java similarity index 95% rename from spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/sqs/SpringCloudSQSIntegrationTest.java rename to spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/sqs/SpringCloudSQSLiveTest.java index 76d2fd7c0d..24917e52f1 100644 --- a/spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/sqs/SpringCloudSQSIntegrationTest.java +++ b/spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/sqs/SpringCloudSQSLiveTest.java @@ -26,12 +26,19 @@ import java.util.concurrent.CountDownLatch; import static org.assertj.core.api.Assertions.assertThat; +/** + * + * To run this Live Test, we need to have an AWS account and have API keys generated for programmatic access. + * + * Check the README file in this module for more information. + * + */ @SpringBootTest @RunWith(SpringRunner.class) @TestPropertySource("classpath:application-test.properties") -public class SpringCloudSQSIntegrationTest { +public class SpringCloudSQSLiveTest { - private static final Logger logger = LoggerFactory.getLogger(SpringCloudSQSIntegrationTest.class); + private static final Logger logger = LoggerFactory.getLogger(SpringCloudSQSLiveTest.class); @Autowired @Lazy diff --git a/spring-cloud/spring-cloud-bootstrap/README.MD b/spring-cloud/spring-cloud-bootstrap/README.MD index 5185200469..7a3a94c8e3 100644 --- a/spring-cloud/spring-cloud-bootstrap/README.MD +++ b/spring-cloud/spring-cloud-bootstrap/README.MD @@ -6,7 +6,7 @@ - [Spring Cloud – Adding Angular 4](http://www.baeldung.com/spring-cloud-angular) - To run the project: - - copy the appliction-config folder to c:\Users\{username}\ on Windows or /Users/{username}/ on *nix. Then open a git bash terminal in application-config and run: + - copy the appliction-config folder to c:\Users\{username}\ on Windows or /home/{username}/ on *nix. Then open a git bash terminal in application-config and run: - git init - git add . - git commit -m "First commit" diff --git a/spring-cloud/spring-cloud-bootstrap/discovery/pom.xml b/spring-cloud/spring-cloud-bootstrap/discovery/pom.xml index 735d3745d7..09bea4864a 100644 --- a/spring-cloud/spring-cloud-bootstrap/discovery/pom.xml +++ b/spring-cloud/spring-cloud-bootstrap/discovery/pom.xml @@ -50,6 +50,6 @@ - Brixton.SR7 + Edgware.SR5 \ No newline at end of file diff --git a/spring-cloud/spring-cloud-bootstrap/discovery/src/test/java/org/baeldung/SpringContextIntegrationTest.java b/spring-cloud/spring-cloud-bootstrap/discovery/src/test/java/org/baeldung/SpringContextLiveTest.java similarity index 70% rename from spring-cloud/spring-cloud-bootstrap/discovery/src/test/java/org/baeldung/SpringContextIntegrationTest.java rename to spring-cloud/spring-cloud-bootstrap/discovery/src/test/java/org/baeldung/SpringContextLiveTest.java index 1e2db33395..e4e2e95e04 100644 --- a/spring-cloud/spring-cloud-bootstrap/discovery/src/test/java/org/baeldung/SpringContextIntegrationTest.java +++ b/spring-cloud/spring-cloud-bootstrap/discovery/src/test/java/org/baeldung/SpringContextLiveTest.java @@ -7,9 +7,15 @@ import org.springframework.test.context.junit4.SpringRunner; import com.baeldung.spring.cloud.bootstrap.discovery.DiscoveryApplication; +/** + * + * This Live Test requires: + * * A Redis instance running in port 6379 (e.g. using `docker run --name some-redis -p 6379:6379 -d redis`) + * + */ @RunWith(SpringRunner.class) @SpringBootTest(classes = DiscoveryApplication.class) -public class SpringContextIntegrationTest { +public class SpringContextLiveTest { @Test public void whenSpringContextIsBootstrapped_thenNoExceptions() { diff --git a/spring-cloud/spring-cloud-bootstrap/gateway/pom.xml b/spring-cloud/spring-cloud-bootstrap/gateway/pom.xml index 2efa926e3a..4f9c60a26a 100644 --- a/spring-cloud/spring-cloud-bootstrap/gateway/pom.xml +++ b/spring-cloud/spring-cloud-bootstrap/gateway/pom.xml @@ -98,6 +98,6 @@ - Brixton.SR7 + Dalston.RELEASE \ No newline at end of file diff --git a/spring-cloud/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/GatewayApplication.java b/spring-cloud/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/GatewayApplication.java index 10ed66bfd4..79785a3f20 100644 --- a/spring-cloud/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/GatewayApplication.java +++ b/spring-cloud/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/GatewayApplication.java @@ -71,7 +71,7 @@ public class GatewayApplication { InstanceInfo instance = eurekaClient.getNextServerFromEureka("zipkin", false); if (!(baseUrl != null && instance.getHomePageUrl().equals(baseUrl))) { baseUrl = instance.getHomePageUrl(); - delegate = new HttpZipkinSpanReporter(baseUrl, zipkinProperties.getFlushInterval(), zipkinProperties.getCompression().isEnabled(), spanMetricReporter); + delegate = new HttpZipkinSpanReporter(new RestTemplate(), baseUrl, zipkinProperties.getFlushInterval(), spanMetricReporter); if (!span.name.matches(skipPattern)) delegate.report(span); } if (!span.name.matches(skipPattern)) delegate.report(span); diff --git a/spring-cloud/spring-cloud-bootstrap/gateway/src/test/java/org/baeldung/SpringContextIntegrationTest.java b/spring-cloud/spring-cloud-bootstrap/gateway/src/test/java/org/baeldung/SpringContextLiveTest.java similarity index 70% rename from spring-cloud/spring-cloud-bootstrap/gateway/src/test/java/org/baeldung/SpringContextIntegrationTest.java rename to spring-cloud/spring-cloud-bootstrap/gateway/src/test/java/org/baeldung/SpringContextLiveTest.java index ef3bb5ef95..e0342cf82c 100644 --- a/spring-cloud/spring-cloud-bootstrap/gateway/src/test/java/org/baeldung/SpringContextIntegrationTest.java +++ b/spring-cloud/spring-cloud-bootstrap/gateway/src/test/java/org/baeldung/SpringContextLiveTest.java @@ -7,9 +7,15 @@ import org.springframework.test.context.junit4.SpringRunner; import com.baeldung.spring.cloud.bootstrap.gateway.GatewayApplication; +/** + * + * This Live Test requires: + * * A Redis instance running in port 6379 (e.g. using `docker run --name some-redis -p 6379:6379 -d redis`) + * + */ @RunWith(SpringRunner.class) @SpringBootTest(classes = GatewayApplication.class) -public class SpringContextIntegrationTest { +public class SpringContextLiveTest { @Test public void whenSpringContextIsBootstrapped_thenNoExceptions() { diff --git a/spring-cloud/spring-cloud-bootstrap/gateway/src/test/resources/bootstrap.properties b/spring-cloud/spring-cloud-bootstrap/gateway/src/test/resources/bootstrap.properties new file mode 100644 index 0000000000..c76df21ff1 --- /dev/null +++ b/spring-cloud/spring-cloud-bootstrap/gateway/src/test/resources/bootstrap.properties @@ -0,0 +1,2 @@ +# This property would be provided by the config service in a real-case scenario +spring.sleuth.web.skipPattern=(^cleanup.|.+favicon.) \ No newline at end of file diff --git a/spring-cloud/spring-cloud-bootstrap/svc-book/pom.xml b/spring-cloud/spring-cloud-bootstrap/svc-book/pom.xml index eb855a91e3..a88b77dda0 100644 --- a/spring-cloud/spring-cloud-bootstrap/svc-book/pom.xml +++ b/spring-cloud/spring-cloud-bootstrap/svc-book/pom.xml @@ -72,7 +72,7 @@ - Brixton.SR7 + Dalston.RELEASE \ No newline at end of file diff --git a/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/BookServiceApplication.java b/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/BookServiceApplication.java index 3d55a59dbc..91fd23e32d 100644 --- a/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/BookServiceApplication.java +++ b/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/BookServiceApplication.java @@ -12,6 +12,8 @@ import org.springframework.cloud.sleuth.zipkin.HttpZipkinSpanReporter; import org.springframework.cloud.sleuth.zipkin.ZipkinProperties; import org.springframework.cloud.sleuth.zipkin.ZipkinSpanReporter; import org.springframework.context.annotation.Bean; +import org.springframework.web.client.RestTemplate; + import zipkin.Span; @SpringBootApplication @@ -42,7 +44,7 @@ public class BookServiceApplication { InstanceInfo instance = eurekaClient.getNextServerFromEureka("zipkin", false); if (!(baseUrl != null && instance.getHomePageUrl().equals(baseUrl))) { baseUrl = instance.getHomePageUrl(); - delegate = new HttpZipkinSpanReporter(baseUrl, zipkinProperties.getFlushInterval(), zipkinProperties.getCompression().isEnabled(), spanMetricReporter); + delegate = new HttpZipkinSpanReporter(new RestTemplate(), baseUrl, zipkinProperties.getFlushInterval(), spanMetricReporter); if (!span.name.matches(skipPattern)) delegate.report(span); } } diff --git a/spring-cloud/spring-cloud-bootstrap/svc-book/src/test/java/org/baeldung/SpringContextIntegrationTest.java b/spring-cloud/spring-cloud-bootstrap/svc-book/src/test/java/org/baeldung/SpringContextLiveTest.java similarity index 70% rename from spring-cloud/spring-cloud-bootstrap/svc-book/src/test/java/org/baeldung/SpringContextIntegrationTest.java rename to spring-cloud/spring-cloud-bootstrap/svc-book/src/test/java/org/baeldung/SpringContextLiveTest.java index 0ffc2410e3..2e437aa3f7 100644 --- a/spring-cloud/spring-cloud-bootstrap/svc-book/src/test/java/org/baeldung/SpringContextIntegrationTest.java +++ b/spring-cloud/spring-cloud-bootstrap/svc-book/src/test/java/org/baeldung/SpringContextLiveTest.java @@ -7,9 +7,15 @@ import org.springframework.test.context.junit4.SpringRunner; import com.baeldung.spring.cloud.bootstrap.svcbook.BookServiceApplication; +/** + * + * This Live Test requires: + * * A Redis instance running in port 6379 (e.g. using `docker run --name some-redis -p 6379:6379 -d redis`) + * + */ @RunWith(SpringRunner.class) @SpringBootTest(classes = BookServiceApplication.class) -public class SpringContextIntegrationTest { +public class SpringContextLiveTest { @Test public void whenSpringContextIsBootstrapped_thenNoExceptions() { diff --git a/spring-cloud/spring-cloud-bootstrap/svc-book/src/test/resources/bootstrap.properties b/spring-cloud/spring-cloud-bootstrap/svc-book/src/test/resources/bootstrap.properties new file mode 100644 index 0000000000..c76df21ff1 --- /dev/null +++ b/spring-cloud/spring-cloud-bootstrap/svc-book/src/test/resources/bootstrap.properties @@ -0,0 +1,2 @@ +# This property would be provided by the config service in a real-case scenario +spring.sleuth.web.skipPattern=(^cleanup.|.+favicon.) \ No newline at end of file diff --git a/spring-cloud/spring-cloud-bootstrap/svc-rating/pom.xml b/spring-cloud/spring-cloud-bootstrap/svc-rating/pom.xml index 7c1e93bad1..f0b19922d8 100644 --- a/spring-cloud/spring-cloud-bootstrap/svc-rating/pom.xml +++ b/spring-cloud/spring-cloud-bootstrap/svc-rating/pom.xml @@ -81,7 +81,7 @@ - Brixton.SR7 + Dalston.RELEASE \ No newline at end of file diff --git a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/RatingServiceApplication.java b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/RatingServiceApplication.java index 31ca69c139..8dacbaa79d 100644 --- a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/RatingServiceApplication.java +++ b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/RatingServiceApplication.java @@ -16,6 +16,7 @@ import org.springframework.context.annotation.Primary; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.transaction.annotation.EnableTransactionManagement; +import org.springframework.web.client.RestTemplate; import com.netflix.appinfo.InstanceInfo; import com.netflix.discovery.EurekaClient; @@ -52,7 +53,7 @@ public class RatingServiceApplication { InstanceInfo instance = eurekaClient.getNextServerFromEureka("zipkin", false); if (!(baseUrl != null && instance.getHomePageUrl().equals(baseUrl))) { baseUrl = instance.getHomePageUrl(); - delegate = new HttpZipkinSpanReporter(baseUrl, zipkinProperties.getFlushInterval(), zipkinProperties.getCompression().isEnabled(), spanMetricReporter); + delegate = new HttpZipkinSpanReporter(new RestTemplate(), baseUrl, zipkinProperties.getFlushInterval(), spanMetricReporter); if (!span.name.matches(skipPattern)) delegate.report(span); } if (!span.name.matches(skipPattern)) delegate.report(span); diff --git a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/test/java/org/baeldung/SpringContextIntegrationTest.java b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/test/java/org/baeldung/SpringContextLiveTest.java similarity index 70% rename from spring-cloud/spring-cloud-bootstrap/svc-rating/src/test/java/org/baeldung/SpringContextIntegrationTest.java rename to spring-cloud/spring-cloud-bootstrap/svc-rating/src/test/java/org/baeldung/SpringContextLiveTest.java index 3589666f17..e2921f0308 100644 --- a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/test/java/org/baeldung/SpringContextIntegrationTest.java +++ b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/test/java/org/baeldung/SpringContextLiveTest.java @@ -7,9 +7,16 @@ import org.springframework.test.context.junit4.SpringRunner; import com.baeldung.spring.cloud.bootstrap.svcrating.RatingServiceApplication; + +/** + * + * This Live Test requires: + * * A Redis instance running in port 6379 (e.g. using `docker run --name some-redis -p 6379:6379 -d redis`) + * + */ @RunWith(SpringRunner.class) @SpringBootTest(classes = RatingServiceApplication.class) -public class SpringContextIntegrationTest { +public class SpringContextLiveTest { @Test public void whenSpringContextIsBootstrapped_thenNoExceptions() { diff --git a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/test/resources/bootstrap.properties b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/test/resources/bootstrap.properties new file mode 100644 index 0000000000..c76df21ff1 --- /dev/null +++ b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/test/resources/bootstrap.properties @@ -0,0 +1,2 @@ +# This property would be provided by the config service in a real-case scenario +spring.sleuth.web.skipPattern=(^cleanup.|.+favicon.) \ No newline at end of file diff --git a/spring-cloud/spring-cloud-config/client/src/test/java/org/baeldung/SpringContextIntegrationTest.java b/spring-cloud/spring-cloud-config/client/src/test/java/com/baeldung/spring/cloud/config/client/SpringContextLiveTest.java similarity index 69% rename from spring-cloud/spring-cloud-config/client/src/test/java/org/baeldung/SpringContextIntegrationTest.java rename to spring-cloud/spring-cloud-config/client/src/test/java/com/baeldung/spring/cloud/config/client/SpringContextLiveTest.java index d727772cf9..3fb43b169d 100644 --- a/spring-cloud/spring-cloud-config/client/src/test/java/org/baeldung/SpringContextIntegrationTest.java +++ b/spring-cloud/spring-cloud-config/client/src/test/java/com/baeldung/spring/cloud/config/client/SpringContextLiveTest.java @@ -1,4 +1,4 @@ -package org.baeldung; +package com.baeldung.spring.cloud.config.client; import org.junit.Test; import org.junit.runner.RunWith; @@ -6,12 +6,15 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; -import com.baeldung.spring.cloud.config.client.ConfigClient; - +/** + * + * The app needs the server running on port 8888. Can be started with docker + * + */ @RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest(classes = ConfigClient.class) @WebAppConfiguration -public class SpringContextIntegrationTest { +public class SpringContextLiveTest { @Test public void contextLoads() { } diff --git a/spring-cloud/spring-cloud-config/server/src/test/java/com/baeldung/spring/cloud/config/server/ConfigServerListIntegrationTest.java b/spring-cloud/spring-cloud-config/server/src/test/java/com/baeldung/spring/cloud/config/server/SpringContextIntegrationTest.java similarity index 79% rename from spring-cloud/spring-cloud-config/server/src/test/java/com/baeldung/spring/cloud/config/server/ConfigServerListIntegrationTest.java rename to spring-cloud/spring-cloud-config/server/src/test/java/com/baeldung/spring/cloud/config/server/SpringContextIntegrationTest.java index c521a0d2ef..b2c6ef85ea 100644 --- a/spring-cloud/spring-cloud-config/server/src/test/java/com/baeldung/spring/cloud/config/server/ConfigServerListIntegrationTest.java +++ b/spring-cloud/spring-cloud-config/server/src/test/java/com/baeldung/spring/cloud/config/server/SpringContextIntegrationTest.java @@ -1,6 +1,5 @@ package com.baeldung.spring.cloud.config.server; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; @@ -10,9 +9,8 @@ import org.springframework.test.context.web.WebAppConfiguration; @RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest(classes = ConfigServer.class) @WebAppConfiguration -@Ignore -public class ConfigServerListIntegrationTest { +public class SpringContextIntegrationTest { @Test - public void contextLoads() { + public void whenSpringContextIsBootstrapped_thenNoExceptions() { } } diff --git a/spring-cloud/spring-cloud-config/server/src/test/resources/application.properties b/spring-cloud/spring-cloud-config/server/src/test/resources/application.properties new file mode 100644 index 0000000000..67cc81ff67 --- /dev/null +++ b/spring-cloud/spring-cloud-config/server/src/test/resources/application.properties @@ -0,0 +1,2 @@ +### This should be provided by the docker config +spring.cloud.config.server.git.uri=classpath:. diff --git a/spring-cloud/spring-cloud-connectors-heroku/src/main/resources/application.properties b/spring-cloud/spring-cloud-connectors-heroku/src/main/resources/application.properties index d2f1c89dc5..571f325824 100644 --- a/spring-cloud/spring-cloud-connectors-heroku/src/main/resources/application.properties +++ b/spring-cloud/spring-cloud-connectors-heroku/src/main/resources/application.properties @@ -4,5 +4,6 @@ spring.datasource.maxIdle=5 spring.datasource.minIdle=2 spring.datasource.initialSize=5 spring.datasource.removeAbandoned=true +spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect spring.jpa.hibernate.ddl-auto=update \ No newline at end of file diff --git a/spring-cloud/spring-cloud-connectors-heroku/src/test/java/org/baeldung/SpringContextIntegrationTest.java b/spring-cloud/spring-cloud-connectors-heroku/src/test/java/com/baeldung/spring/cloud/connectors/heroku/SpringContextIntegrationTest.java similarity index 90% rename from spring-cloud/spring-cloud-connectors-heroku/src/test/java/org/baeldung/SpringContextIntegrationTest.java rename to spring-cloud/spring-cloud-connectors-heroku/src/test/java/com/baeldung/spring/cloud/connectors/heroku/SpringContextIntegrationTest.java index a705f18bc6..dca4c25c71 100644 --- a/spring-cloud/spring-cloud-connectors-heroku/src/test/java/org/baeldung/SpringContextIntegrationTest.java +++ b/spring-cloud/spring-cloud-connectors-heroku/src/test/java/com/baeldung/spring/cloud/connectors/heroku/SpringContextIntegrationTest.java @@ -1,4 +1,4 @@ -package org.baeldung; +package com.baeldung.spring.cloud.connectors.heroku; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/spring-cloud/spring-cloud-connectors-heroku/src/test/resources/application.properties b/spring-cloud/spring-cloud-connectors-heroku/src/test/resources/application.properties new file mode 100644 index 0000000000..7b139ae07d --- /dev/null +++ b/spring-cloud/spring-cloud-connectors-heroku/src/test/resources/application.properties @@ -0,0 +1,2 @@ +spring.jpa.hibernate.ddl-auto=create +spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect \ No newline at end of file diff --git a/spring-cloud/spring-cloud-consul/pom.xml b/spring-cloud/spring-cloud-consul/pom.xml index 1ca3d703b5..456a7ec302 100644 --- a/spring-cloud/spring-cloud-consul/pom.xml +++ b/spring-cloud/spring-cloud-consul/pom.xml @@ -29,13 +29,14 @@ org.springframework.boot spring-boot-starter-test - 1.5.10.RELEASE + ${spring-boot-starter-test.version} test 1.3.0.RELEASE + 1.5.10.RELEASE diff --git a/spring-cloud/spring-cloud-consul/src/test/java/org/baeldung/SpringContextIntegrationTest.java b/spring-cloud/spring-cloud-consul/src/test/java/com/baeldung/spring/cloud/consul/SpringContextLiveTest.java similarity index 74% rename from spring-cloud/spring-cloud-consul/src/test/java/org/baeldung/SpringContextIntegrationTest.java rename to spring-cloud/spring-cloud-consul/src/test/java/com/baeldung/spring/cloud/consul/SpringContextLiveTest.java index 6290ccc03e..7c87add43e 100644 --- a/spring-cloud/spring-cloud-consul/src/test/java/org/baeldung/SpringContextIntegrationTest.java +++ b/spring-cloud/spring-cloud-consul/src/test/java/com/baeldung/spring/cloud/consul/SpringContextLiveTest.java @@ -1,4 +1,4 @@ -package org.baeldung; +package com.baeldung.spring.cloud.consul; import org.junit.Test; import org.junit.runner.RunWith; @@ -9,10 +9,18 @@ import com.baeldung.spring.cloud.consul.discovery.DiscoveryClientApplication; import com.baeldung.spring.cloud.consul.health.ServiceDiscoveryApplication; import com.baeldung.spring.cloud.consul.properties.DistributedPropertiesApplication; + +/** + * + * This Live test requires: + * * a Consul instance running on port 8500 + * * Consul configured with particular properties (e.g. 'my.prop') + * + */ @RunWith(SpringRunner.class) @SpringBootTest(classes = { DiscoveryClientApplication.class, ServiceDiscoveryApplication.class, DistributedPropertiesApplication.class }) -public class SpringContextIntegrationTest { +public class SpringContextLiveTest { @Test public void whenSpringContextIsBootstrapped_thenNoExceptions() { diff --git a/spring-cloud/spring-cloud-contract/spring-cloud-contract-consumer/pom.xml b/spring-cloud/spring-cloud-contract/spring-cloud-contract-consumer/pom.xml index 7d00a9f463..8ecda40d0a 100644 --- a/spring-cloud/spring-cloud-contract/spring-cloud-contract-consumer/pom.xml +++ b/spring-cloud/spring-cloud-contract/spring-cloud-contract-consumer/pom.xml @@ -20,24 +20,24 @@ org.springframework.cloud spring-cloud-contract-wiremock - 1.2.2.RELEASE + ${spring-cloud.version} test org.springframework.cloud spring-cloud-contract-stub-runner - 1.2.2.RELEASE + ${spring-cloud.version} test org.springframework.boot spring-boot-starter-web - 1.5.9.RELEASE + ${spring-boot.version} org.springframework.boot spring-boot-starter-data-rest - 1.5.9.RELEASE + ${spring-boot.version} com.baeldung.spring.cloud @@ -51,5 +51,7 @@ UTF-8 UTF-8 1.8 + 1.2.2.RELEASE + 1.5.9.RELEASE diff --git a/spring-cloud/spring-cloud-contract/spring-cloud-contract-producer/pom.xml b/spring-cloud/spring-cloud-contract/spring-cloud-contract-producer/pom.xml index a6bd4e1be4..47759a818a 100644 --- a/spring-cloud/spring-cloud-contract/spring-cloud-contract-producer/pom.xml +++ b/spring-cloud/spring-cloud-contract/spring-cloud-contract-producer/pom.xml @@ -25,12 +25,12 @@ org.springframework.boot spring-boot-starter-web - 1.5.9.RELEASE + ${spring-boot.version} org.springframework.boot spring-boot-starter-data-rest - 1.5.9.RELEASE + ${spring-boot.version} @@ -66,6 +66,7 @@ UTF-8 1.8 Edgware.SR1 + 1.5.9.RELEASE diff --git a/spring-cloud/spring-cloud-eureka/pom.xml b/spring-cloud/spring-cloud-eureka/pom.xml index b59b415ee2..924981765c 100644 --- a/spring-cloud/spring-cloud-eureka/pom.xml +++ b/spring-cloud/spring-cloud-eureka/pom.xml @@ -21,6 +21,15 @@ 1.0.0-SNAPSHOT .. + + + + org.springframework.boot + spring-boot-starter-test + ${spring-boot.version} + test + + 2.0.1.RELEASE diff --git a/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-client/pom.xml b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-client/pom.xml index c2d64ce237..85fa6606d2 100644 --- a/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-client/pom.xml +++ b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-client/pom.xml @@ -26,12 +26,6 @@ spring-boot-starter-web ${spring-boot.version} - - org.springframework.boot - spring-boot-starter-test - ${spring-boot.version} - test - diff --git a/spring-cloud/spring-cloud-rest/spring-cloud-rest-books-api/src/test/java/org/baeldung/SpringContextIntegrationTest.java b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-client/src/test/java/com/baeldung/spring/cloud/eureka/client/SpringContextIntegrationTest.java similarity index 81% rename from spring-cloud/spring-cloud-rest/spring-cloud-rest-books-api/src/test/java/org/baeldung/SpringContextIntegrationTest.java rename to spring-cloud/spring-cloud-eureka/spring-cloud-eureka-client/src/test/java/com/baeldung/spring/cloud/eureka/client/SpringContextIntegrationTest.java index 24e758ff82..8e379fd5a0 100644 --- a/spring-cloud/spring-cloud-rest/spring-cloud-rest-books-api/src/test/java/org/baeldung/SpringContextIntegrationTest.java +++ b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-client/src/test/java/com/baeldung/spring/cloud/eureka/client/SpringContextIntegrationTest.java @@ -1,4 +1,4 @@ -package org.baeldung; +package com.baeldung.spring.cloud.eureka.client; import org.junit.Test; import org.junit.runner.RunWith; @@ -6,10 +6,11 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) -@SpringBootTest(classes = BooksApiApplication.class) +@SpringBootTest public class SpringContextIntegrationTest { - + @Test public void whenSpringContextIsBootstrapped_thenNoExceptions() { } + } diff --git a/spring-cloud/spring-cloud-rest/spring-cloud-rest-reviews-api/src/test/java/org/baeldung/SpringContextIntegrationTest.java b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client/src/test/java/com/baeldung/spring/cloud/feign/client/SpringContextIntegrationTest.java similarity index 80% rename from spring-cloud/spring-cloud-rest/spring-cloud-rest-reviews-api/src/test/java/org/baeldung/SpringContextIntegrationTest.java rename to spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client/src/test/java/com/baeldung/spring/cloud/feign/client/SpringContextIntegrationTest.java index 07d7db0505..ff742735b3 100644 --- a/spring-cloud/spring-cloud-rest/spring-cloud-rest-reviews-api/src/test/java/org/baeldung/SpringContextIntegrationTest.java +++ b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client/src/test/java/com/baeldung/spring/cloud/feign/client/SpringContextIntegrationTest.java @@ -1,4 +1,4 @@ -package org.baeldung; +package com.baeldung.spring.cloud.feign.client; import org.junit.Test; import org.junit.runner.RunWith; @@ -6,10 +6,11 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) -@SpringBootTest(classes = BookReviewsApiApplication.class) +@SpringBootTest public class SpringContextIntegrationTest { @Test public void whenSpringContextIsBootstrapped_thenNoExceptions() { } + } diff --git a/spring-cloud/spring-cloud-rest/spring-cloud-rest-discovery-server/src/test/java/org/baeldung/SpringContextIntegrationTest.java b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-server/src/test/java/com/baeldung/spring/cloud/eureka/server/SpringContextIntegrationTest.java similarity index 79% rename from spring-cloud/spring-cloud-rest/spring-cloud-rest-discovery-server/src/test/java/org/baeldung/SpringContextIntegrationTest.java rename to spring-cloud/spring-cloud-eureka/spring-cloud-eureka-server/src/test/java/com/baeldung/spring/cloud/eureka/server/SpringContextIntegrationTest.java index e22359a016..f03913b474 100644 --- a/spring-cloud/spring-cloud-rest/spring-cloud-rest-discovery-server/src/test/java/org/baeldung/SpringContextIntegrationTest.java +++ b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-server/src/test/java/com/baeldung/spring/cloud/eureka/server/SpringContextIntegrationTest.java @@ -1,4 +1,4 @@ -package org.baeldung; +package com.baeldung.spring.cloud.eureka.server; import org.junit.Test; import org.junit.runner.RunWith; @@ -6,10 +6,11 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) -@SpringBootTest(classes = SpringCloudRestServerApplication.class) +@SpringBootTest public class SpringContextIntegrationTest { @Test public void whenSpringContextIsBootstrapped_thenNoExceptions() { } + } diff --git a/spring-cloud/spring-cloud-functions/src/test/java/com/baeldung/spring/cloudfunction/aws/SpringContextIntegrationTest.java b/spring-cloud/spring-cloud-functions/src/test/java/com/baeldung/spring/cloudfunction/aws/SpringContextIntegrationTest.java new file mode 100644 index 0000000000..beee84246d --- /dev/null +++ b/spring-cloud/spring-cloud-functions/src/test/java/com/baeldung/spring/cloudfunction/aws/SpringContextIntegrationTest.java @@ -0,0 +1,15 @@ +package com.baeldung.spring.cloudfunction.aws; + +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(classes = CloudFunctionAwsApplication.class) +public class SpringContextIntegrationTest { + + @Test + public void whenSpringContextIsBootstrapped_thenNoExceptions() { + } +} \ No newline at end of file diff --git a/spring-cloud/spring-cloud-config/server/src/test/java/org/baeldung/SpringContextIntegrationTest.java b/spring-cloud/spring-cloud-hystrix/feign-rest-consumer/src/test/java/com/baeldung/spring/cloud/hystrix/rest/consumer/SpringContextIntegrationTest.java similarity index 55% rename from spring-cloud/spring-cloud-config/server/src/test/java/org/baeldung/SpringContextIntegrationTest.java rename to spring-cloud/spring-cloud-hystrix/feign-rest-consumer/src/test/java/com/baeldung/spring/cloud/hystrix/rest/consumer/SpringContextIntegrationTest.java index cd30392d4f..47ee5dcd49 100644 --- a/spring-cloud/spring-cloud-config/server/src/test/java/org/baeldung/SpringContextIntegrationTest.java +++ b/spring-cloud/spring-cloud-hystrix/feign-rest-consumer/src/test/java/com/baeldung/spring/cloud/hystrix/rest/consumer/SpringContextIntegrationTest.java @@ -1,18 +1,18 @@ -package org.baeldung; +package com.baeldung.spring.cloud.hystrix.rest.consumer; import org.junit.Test; import org.junit.runner.RunWith; -import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; -import com.baeldung.spring.cloud.config.server.ConfigServer; - @RunWith(SpringJUnit4ClassRunner.class) -@SpringBootTest(classes = ConfigServer.class) +@ContextConfiguration(classes = RestConsumerFeignApplication.class) @WebAppConfiguration public class SpringContextIntegrationTest { + @Test - public void contextLoads() { + public void whenSpringContextIsBootstrapped_thenNoExceptions() { } + } diff --git a/spring-cloud/spring-cloud-hystrix/rest-consumer/pom.xml b/spring-cloud/spring-cloud-hystrix/rest-consumer/pom.xml index ec2f6d1e55..43ccfcc26d 100644 --- a/spring-cloud/spring-cloud-hystrix/rest-consumer/pom.xml +++ b/spring-cloud/spring-cloud-hystrix/rest-consumer/pom.xml @@ -40,6 +40,13 @@ spring-boot-starter-actuator ${spring-boot-starter-web.version} + + + org.springframework.boot + spring-boot-starter-test + test + ${spring-boot-starter-web.version} + @@ -53,5 +60,10 @@ + + + + 1.10.19 + diff --git a/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/test/java/org/baeldung/SpringContextIntegrationTest.java b/spring-cloud/spring-cloud-hystrix/rest-consumer/src/test/java/com/baeldung/spring/cloud/hystrix/rest/consumer/SpringContextIntegrationTest.java similarity index 63% rename from spring-cloud/spring-cloud-task/springcloudtaskbatch/src/test/java/org/baeldung/SpringContextIntegrationTest.java rename to spring-cloud/spring-cloud-hystrix/rest-consumer/src/test/java/com/baeldung/spring/cloud/hystrix/rest/consumer/SpringContextIntegrationTest.java index 4b5aff2db8..3af30acc51 100644 --- a/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/test/java/org/baeldung/SpringContextIntegrationTest.java +++ b/spring-cloud/spring-cloud-hystrix/rest-consumer/src/test/java/com/baeldung/spring/cloud/hystrix/rest/consumer/SpringContextIntegrationTest.java @@ -1,17 +1,18 @@ -package org.baeldung; +package com.baeldung.spring.cloud.hystrix.rest.consumer; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; - -import com.baeldung.task.JobConfiguration; +import org.springframework.test.context.web.WebAppConfiguration; @RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(classes = JobConfiguration.class) +@ContextConfiguration(classes = RestConsumerApplication.class) +@WebAppConfiguration public class SpringContextIntegrationTest { @Test public void whenSpringContextIsBootstrapped_thenNoExceptions() { } + } diff --git a/spring-cloud/spring-cloud-hystrix/rest-producer/pom.xml b/spring-cloud/spring-cloud-hystrix/rest-producer/pom.xml index 0f84fb7e23..07437634f5 100644 --- a/spring-cloud/spring-cloud-hystrix/rest-producer/pom.xml +++ b/spring-cloud/spring-cloud-hystrix/rest-producer/pom.xml @@ -20,6 +20,18 @@ spring-boot-starter-web ${spring-boot-starter-web.version} + + + org.springframework.boot + spring-boot-starter-test + ${spring-boot-starter-web.version} + test + + + + + 1.10.19 + diff --git a/spring-cloud/spring-cloud-bootstrap/discovery/java/org/baeldung/SpringContextIntegrationTest.java b/spring-cloud/spring-cloud-hystrix/rest-producer/src/test/java/com/baeldung/spring/cloud/hystrix/rest/producer/SpringContextIntegrationTest.java similarity index 70% rename from spring-cloud/spring-cloud-bootstrap/discovery/java/org/baeldung/SpringContextIntegrationTest.java rename to spring-cloud/spring-cloud-hystrix/rest-producer/src/test/java/com/baeldung/spring/cloud/hystrix/rest/producer/SpringContextIntegrationTest.java index 6016788eab..de696dc2b1 100644 --- a/spring-cloud/spring-cloud-bootstrap/discovery/java/org/baeldung/SpringContextIntegrationTest.java +++ b/spring-cloud/spring-cloud-hystrix/rest-producer/src/test/java/com/baeldung/spring/cloud/hystrix/rest/producer/SpringContextIntegrationTest.java @@ -1,17 +1,16 @@ -package org.baeldung; +package com.baeldung.spring.cloud.hystrix.rest.producer; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; -import com.baeldung.spring.cloud.bootstrap.config.ConfigApplication; - @RunWith(SpringRunner.class) -@SpringBootTest(classes = ConfigApplication.class) +@SpringBootTest public class SpringContextIntegrationTest { @Test public void whenSpringContextIsBootstrapped_thenNoExceptions() { } + } diff --git a/spring-cloud/spring-cloud-kubernetes/client-service/.gitignore b/spring-cloud/spring-cloud-kubernetes/client-service/.gitignore new file mode 100644 index 0000000000..2af7cefb0a --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes/client-service/.gitignore @@ -0,0 +1,24 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans + +### 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-cloud/spring-cloud-kubernetes/client-service/Dockerfile b/spring-cloud/spring-cloud-kubernetes/client-service/Dockerfile new file mode 100644 index 0000000000..bd8cf2918f --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes/client-service/Dockerfile @@ -0,0 +1,5 @@ +FROM openjdk:8-jdk-alpine +VOLUME /tmp +COPY target/client-service-1.0-SNAPSHOT.jar app.jar +ENV JAVA_OPTS="" +ENTRYPOINT exec java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=9999 -jar /app.jar \ No newline at end of file diff --git a/spring-cloud/spring-cloud-kubernetes/client-service/client-config.yaml b/spring-cloud/spring-cloud-kubernetes/client-service/client-config.yaml new file mode 100644 index 0000000000..329c01582e --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes/client-service/client-config.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: client-service +data: + application.properties: |- + bean.message=Testing reload ! Message from backend is: %s
Services : %s + diff --git a/spring-cloud/spring-cloud-kubernetes/client-service/client-service-deployment.yaml b/spring-cloud/spring-cloud-kubernetes/client-service/client-service-deployment.yaml new file mode 100644 index 0000000000..8867aecc33 --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes/client-service/client-service-deployment.yaml @@ -0,0 +1,33 @@ +kind: Service +apiVersion: v1 +metadata: + name: client-service +spec: + selector: + app: client-service + ports: + - protocol: TCP + port: 8080 + nodePort: 30083 + type: NodePort +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: client-service +spec: + selector: + matchLabels: + app: client-service + replicas: 1 + template: + metadata: + labels: + app: client-service + spec: + containers: + - name: client-service + image: client-service:latest + imagePullPolicy: Never + ports: + - containerPort: 8080 \ No newline at end of file diff --git a/spring-cloud/spring-cloud-kubernetes/client-service/pom.xml b/spring-cloud/spring-cloud-kubernetes/client-service/pom.xml new file mode 100644 index 0000000000..a4de796ee3 --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes/client-service/pom.xml @@ -0,0 +1,96 @@ + + + 4.0.0 + client-service + client-service + 1.0-SNAPSHOT + + + com.baeldung.spring.cloud + spring-cloud-kubernetes + 1.0-SNAPSHOT + + + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud-dependencies.version} + pom + import + + + org.springframework.cloud + spring-cloud-kubernetes-dependencies + ${spring.cloud.k8s.version} + pom + import + + + + + + + org.springframework.cloud + spring-cloud-kubernetes-discovery + + + org.springframework.cloud + spring-cloud-starter-kubernetes-config + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.cloud + spring-cloud-starter-netflix-hystrix + + + org.springframework.cloud + spring-cloud-starter-kubernetes-ribbon + + + org.springframework.cloud + spring-cloud-starter-netflix-ribbon + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + com.baeldung.spring.cloud.kubernetes.client.Application + JAR + + + + + repackage + + + + + + + + + 1.8 + Finchley.SR2 + 1.0.0.RELEASE + + + diff --git a/spring-cloud/spring-cloud-kubernetes/client-service/src/main/java/com/baeldung/spring/cloud/kubernetes/client/Application.java b/spring-cloud/spring-cloud-kubernetes/client-service/src/main/java/com/baeldung/spring/cloud/kubernetes/client/Application.java new file mode 100644 index 0000000000..24e562c79b --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes/client-service/src/main/java/com/baeldung/spring/cloud/kubernetes/client/Application.java @@ -0,0 +1,27 @@ +package com.baeldung.spring.cloud.kubernetes.client; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; +import org.springframework.cloud.client.loadbalancer.LoadBalanced; +import org.springframework.cloud.netflix.ribbon.RibbonClient; +import org.springframework.context.annotation.Bean; +import org.springframework.web.client.RestTemplate; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; + +@SpringBootApplication +@EnableDiscoveryClient +@EnableCircuitBreaker +@RibbonClient(name = "travel-agency-service", configuration = RibbonConfiguration.class) +public class Application { + + @LoadBalanced + @Bean + RestTemplate restTemplate() { + return new RestTemplate(); + } + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } +} diff --git a/spring-cloud/spring-cloud-kubernetes/client-service/src/main/java/com/baeldung/spring/cloud/kubernetes/client/ClientConfig.java b/spring-cloud/spring-cloud-kubernetes/client-service/src/main/java/com/baeldung/spring/cloud/kubernetes/client/ClientConfig.java new file mode 100644 index 0000000000..4bc8fbe327 --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes/client-service/src/main/java/com/baeldung/spring/cloud/kubernetes/client/ClientConfig.java @@ -0,0 +1,19 @@ +package com.baeldung.spring.cloud.kubernetes.client; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ConfigurationProperties(prefix = "bean") +public class ClientConfig { + + private String message = "Message from backend is: %s
Services : %s"; + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } +} \ No newline at end of file diff --git a/spring-cloud/spring-cloud-kubernetes/client-service/src/main/java/com/baeldung/spring/cloud/kubernetes/client/ClientController.java b/spring-cloud/spring-cloud-kubernetes/client-service/src/main/java/com/baeldung/spring/cloud/kubernetes/client/ClientController.java new file mode 100755 index 0000000000..952bccc3a8 --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes/client-service/src/main/java/com/baeldung/spring/cloud/kubernetes/client/ClientController.java @@ -0,0 +1,54 @@ +package com.baeldung.spring.cloud.kubernetes.client; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.client.discovery.DiscoveryClient; +import org.springframework.http.ResponseEntity; +import org.springframework.util.CollectionUtils; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.RestTemplate; + +import java.net.UnknownHostException; +import java.util.List; + +@RestController +public class ClientController { + + @Autowired + private DiscoveryClient discoveryClient; + + @Autowired + private ClientConfig config; + + @Autowired + private TravelAgencyService travelAgencyService; + + @RequestMapping("/deals") + public String getDeals() { + return travelAgencyService.getDeals(); + } + + @GetMapping + public String load() { + + RestTemplate restTemplate = new RestTemplate(); + String resourceUrl = "http://travel-agency-service:8080"; + ResponseEntity response = restTemplate.getForEntity(resourceUrl, String.class); + + String serviceList = ""; + if (discoveryClient != null) { + List services = this.discoveryClient.getServices(); + + for (String service : services) { + + List instances = this.discoveryClient.getInstances(service); + + serviceList += ("[" + service + " : " + ((!CollectionUtils.isEmpty(instances)) ? instances.size() : 0) + " instances ]"); + } + } + + return String.format(config.getMessage(), response.getBody(), serviceList); + } +} diff --git a/spring-cloud/spring-cloud-kubernetes/client-service/src/main/java/com/baeldung/spring/cloud/kubernetes/client/RibbonConfiguration.java b/spring-cloud/spring-cloud-kubernetes/client-service/src/main/java/com/baeldung/spring/cloud/kubernetes/client/RibbonConfiguration.java new file mode 100755 index 0000000000..2b81c78be4 --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes/client-service/src/main/java/com/baeldung/spring/cloud/kubernetes/client/RibbonConfiguration.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2016 to the original 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 + * + * http://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. + */ + +package com.baeldung.spring.cloud.kubernetes.client; + +import com.netflix.client.config.IClientConfig; +import com.netflix.loadbalancer.AvailabilityFilteringRule; +import com.netflix.loadbalancer.IPing; +import com.netflix.loadbalancer.IRule; +import com.netflix.loadbalancer.PingUrl; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; + +public class RibbonConfiguration { + + @Autowired + IClientConfig ribbonClientConfig; + + /** + * PingUrl will ping a URL to check the status of each server. + * Say Hello has, as you’ll recall, a method mapped to the /path; that means that Ribbon will get an HTTP 200 response when it pings a running Backend Server + * + * @param config Client configuration + * @return The URL to be used for the Ping + */ + @Bean + public IPing ribbonPing(IClientConfig config) { + return new PingUrl(); + } + + /** + * AvailabilityFilteringRule will use Ribbon’s built-in circuit breaker functionality to filter out any servers in an “open-circuit” state: + * if a ping fails to connect to a given server, or if it gets a read failure for the server, Ribbon will consider that server “dead” until it begins to respond normally. + * + * @param config Client configuration + * @return The Load Balancer rule + */ + @Bean + public IRule ribbonRule(IClientConfig config) { + return new AvailabilityFilteringRule(); + } +} diff --git a/spring-cloud/spring-cloud-kubernetes/client-service/src/main/java/com/baeldung/spring/cloud/kubernetes/client/TravelAgencyService.java b/spring-cloud/spring-cloud-kubernetes/client-service/src/main/java/com/baeldung/spring/cloud/kubernetes/client/TravelAgencyService.java new file mode 100644 index 0000000000..5ce6d7b8a1 --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes/client-service/src/main/java/com/baeldung/spring/cloud/kubernetes/client/TravelAgencyService.java @@ -0,0 +1,26 @@ +package com.baeldung.spring.cloud.kubernetes.client; + +import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; +import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +@Service +public class TravelAgencyService { + + private final RestTemplate restTemplate; + + public TravelAgencyService(RestTemplate restTemplate) { + this.restTemplate = restTemplate; + } + + @HystrixCommand(fallbackMethod = "getFallbackName", commandProperties = { + @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1000") }) + public String getDeals() { + return this.restTemplate.getForObject("http://travel-agency-service:8080/deals", String.class); + } + + private String getFallbackName() { + return "Fallback"; + } +} diff --git a/spring-cloud/spring-cloud-kubernetes/client-service/src/main/resources/application.yaml b/spring-cloud/spring-cloud-kubernetes/client-service/src/main/resources/application.yaml new file mode 100644 index 0000000000..f966fdd7a5 --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes/client-service/src/main/resources/application.yaml @@ -0,0 +1,16 @@ +spring: + application.name: client-service + cloud.kubernetes.reload.enabled: true +server.port: 8080 +management: + endpoint: + restart: + enabled: true + health: + enabled: true + info: + enabled: true +ribbon: + http: + client: + enabled: true \ No newline at end of file diff --git a/spring-cloud/spring-cloud-kubernetes/client-service/src/main/resources/logback.xml b/spring-cloud/spring-cloud-kubernetes/client-service/src/main/resources/logback.xml new file mode 100644 index 0000000000..7d900d8ea8 --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes/client-service/src/main/resources/logback.xml @@ -0,0 +1,13 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + \ No newline at end of file diff --git a/spring-cloud/spring-cloud-kubernetes/client-service/src/test/java/org/baeldung/SpringContextIntegrationTest.java b/spring-cloud/spring-cloud-kubernetes/client-service/src/test/java/org/baeldung/SpringContextIntegrationTest.java new file mode 100644 index 0000000000..a6a978a354 --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes/client-service/src/test/java/org/baeldung/SpringContextIntegrationTest.java @@ -0,0 +1,17 @@ +package org.baeldung; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import com.baeldung.spring.cloud.kubernetes.client.Application; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = Application.class) +public class SpringContextIntegrationTest { + + @Test + public void contextLoads() { + } +} diff --git a/spring-cloud/spring-cloud-kubernetes/deployment-travel-client.sh b/spring-cloud/spring-cloud-kubernetes/deployment-travel-client.sh new file mode 100755 index 0000000000..90f92f31a6 --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes/deployment-travel-client.sh @@ -0,0 +1,34 @@ +### set docker env +eval $(minikube docker-env) + +### build the repository +#mvn clean install + +### build the docker images on minikube +cd travel-agency-service +docker build -t travel-agency-service . +cd ../client-service +docker build -t client-service . +cd .. + +### secret and mongodb +kubectl delete -f travel-agency-service/secret.yaml +kubectl delete -f travel-agency-service/mongo-deployment.yaml + +kubectl create -f travel-agency-service/secret.yaml +kubectl create -f travel-agency-service/mongo-deployment.yaml + +### travel-agency-service +kubectl delete -f travel-agency-service/travel-agency-deployment.yaml +kubectl create -f travel-agency-service/travel-agency-deployment.yaml + + +### client-service +kubectl delete configmap client-service +kubectl delete -f client-service/client-service-deployment.yaml + +kubectl create -f client-service/client-config.yaml +kubectl create -f client-service/client-service-deployment.yaml + +# Check that the pods are running +kubectl get pods diff --git a/spring-cloud/spring-cloud-kubernetes/pom.xml b/spring-cloud/spring-cloud-kubernetes/pom.xml index 51e1456358..a9563fc582 100644 --- a/spring-cloud/spring-cloud-kubernetes/pom.xml +++ b/spring-cloud/spring-cloud-kubernetes/pom.xml @@ -9,17 +9,19 @@ pom - parent-boot-1 + parent-boot-2 com.baeldung 0.0.1-SNAPSHOT - ../../parent-boot-1 + ../../parent-boot-2 - + demo-frontend demo-backend liveness-example readiness-example + client-service + travel-agency-service \ No newline at end of file diff --git a/spring-cloud/spring-cloud-kubernetes/travel-agency-service/Dockerfile b/spring-cloud/spring-cloud-kubernetes/travel-agency-service/Dockerfile new file mode 100755 index 0000000000..30b66d5eff --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes/travel-agency-service/Dockerfile @@ -0,0 +1,5 @@ +FROM openjdk:8-jdk-alpine +VOLUME /tmp +COPY target/travel-agency-service-1.0-SNAPSHOT.jar app.jar +ENV JAVA_OPTS="" +ENTRYPOINT exec java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=9999 -jar /app.jar \ No newline at end of file diff --git a/spring-cloud/spring-cloud-kubernetes/travel-agency-service/mongo-deployment.yaml b/spring-cloud/spring-cloud-kubernetes/travel-agency-service/mongo-deployment.yaml new file mode 100644 index 0000000000..3d40581578 --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes/travel-agency-service/mongo-deployment.yaml @@ -0,0 +1,45 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + app: mongo + name: mongodb-service +spec: + type: NodePort + ports: + - name: "http" + port: 27017 + protocol: TCP + targetPort: 27017 + selector: + service: mongo +--- +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: mongo +spec: + replicas: 1 + template: + metadata: + labels: + service: mongo + name: mongodb-service + spec: + containers: + - args: + - mongod + - --smallfiles + image: mongo:latest + name: mongo + env: + - name: MONGO_INITDB_ROOT_USERNAME + valueFrom: + secretKeyRef: + name: db-secret + key: username + - name: MONGO_INITDB_ROOT_PASSWORD + valueFrom: + secretKeyRef: + name: db-secret + key: password diff --git a/spring-cloud/spring-cloud-kubernetes/travel-agency-service/pom.xml b/spring-cloud/spring-cloud-kubernetes/travel-agency-service/pom.xml new file mode 100755 index 0000000000..19eea2612c --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes/travel-agency-service/pom.xml @@ -0,0 +1,75 @@ + + + 4.0.0 + travel-agency-service + 1.0-SNAPSHOT + + + com.baeldung.spring.cloud + spring-cloud-kubernetes + 1.0-SNAPSHOT + + + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud-dependencies.version} + pom + import + + + ch.qos.logback + logback-classic + 1.2.3 + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-actuator + + + org.springframework.boot + spring-boot-actuator-autoconfigure + + + org.springframework.boot + spring-boot-starter-data-mongodb + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + com.baeldung.spring.cloud.kubernetes.travelagency.Application + JAR + + + + + repackage + + + + + + + + + 1.8 + Finchley.SR2 + + + \ No newline at end of file diff --git a/spring-cloud/spring-cloud-kubernetes/travel-agency-service/secret.yaml b/spring-cloud/spring-cloud-kubernetes/travel-agency-service/secret.yaml new file mode 100644 index 0000000000..a813c35be7 --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes/travel-agency-service/secret.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: Secret +metadata: + name: db-secret +data: + username: dXNlcg== + password: cDQ1NXcwcmQ= diff --git a/spring-cloud/spring-cloud-kubernetes/travel-agency-service/src/main/java/com/baeldung/spring/cloud/kubernetes/travelagency/Application.java b/spring-cloud/spring-cloud-kubernetes/travel-agency-service/src/main/java/com/baeldung/spring/cloud/kubernetes/travelagency/Application.java new file mode 100755 index 0000000000..bfc7356176 --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes/travel-agency-service/src/main/java/com/baeldung/spring/cloud/kubernetes/travelagency/Application.java @@ -0,0 +1,23 @@ +package com.baeldung.spring.cloud.kubernetes.travelagency; + +import com.baeldung.spring.cloud.kubernetes.travelagency.controller.TravelAgencyController; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application implements CommandLineRunner { + + private static final Log log = LogFactory.getLog(TravelAgencyController.class); + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + + public void run(String... args) throws Exception { + log.info("Travel Agency Started! "); + } + +} diff --git a/spring-cloud/spring-cloud-kubernetes/travel-agency-service/src/main/java/com/baeldung/spring/cloud/kubernetes/travelagency/controller/TravelAgencyController.java b/spring-cloud/spring-cloud-kubernetes/travel-agency-service/src/main/java/com/baeldung/spring/cloud/kubernetes/travelagency/controller/TravelAgencyController.java new file mode 100644 index 0000000000..42f001616a --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes/travel-agency-service/src/main/java/com/baeldung/spring/cloud/kubernetes/travelagency/controller/TravelAgencyController.java @@ -0,0 +1,55 @@ +package com.baeldung.spring.cloud.kubernetes.travelagency.controller; + +import com.baeldung.spring.cloud.kubernetes.travelagency.model.TravelDeal; +import com.baeldung.spring.cloud.kubernetes.travelagency.repository.TravelDealRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.List; +import java.util.Random; +import static org.springframework.web.bind.annotation.RequestMethod.GET; + +@RestController +public class TravelAgencyController { + + @Autowired + private TravelDealRepository travelDealRepository; + + private static final Log log = LogFactory.getLog(TravelAgencyController.class); + + @RequestMapping(method = GET, path = "/deals") + public String deals() { + log.info("Client is requesting new deals!"); + + List travelDealList = travelDealRepository.findAll(); + if (!travelDealList.isEmpty()) { + int randomDeal = new Random().nextInt(travelDealList.size()); + return travelDealList.get(randomDeal) + .toString(); + } else { + return "NO DEALS"; + } + } + + @RequestMapping(method = GET, path = "/") + @ResponseBody + public String get() throws UnknownHostException { + + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append("Host: ") + .append(InetAddress.getLocalHost() + .getHostName()) + .append("
"); + stringBuilder.append("IP: ") + .append(InetAddress.getLocalHost() + .getHostAddress()) + .append("
"); + stringBuilder.append("Type: ") + .append("Travel Agency") + .append("
"); + return stringBuilder.toString(); + } +} diff --git a/spring-cloud/spring-cloud-kubernetes/travel-agency-service/src/main/java/com/baeldung/spring/cloud/kubernetes/travelagency/model/TravelDeal.java b/spring-cloud/spring-cloud-kubernetes/travel-agency-service/src/main/java/com/baeldung/spring/cloud/kubernetes/travelagency/model/TravelDeal.java new file mode 100644 index 0000000000..2cd2bf2d45 --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes/travel-agency-service/src/main/java/com/baeldung/spring/cloud/kubernetes/travelagency/model/TravelDeal.java @@ -0,0 +1,92 @@ +package com.baeldung.spring.cloud.kubernetes.travelagency.model; + +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.mongodb.core.mapping.Field; + +import java.math.BigInteger; +import java.util.Date; + +@Document(collection = "travel_deal") +public class TravelDeal { + + @Id + private BigInteger id; + + private String destination; + + private String description; + + @Field("deal_price") + private double dealPrice; + + @Field("old_price") + private double oldPrice; + + @Field("departure_date") + private Date departureDate; + + @Field("arrival_date") + private Date arrivalDate; + + public BigInteger getId() { + return id; + } + + public void setId(BigInteger id) { + this.id = id; + } + + public String getDestination() { + return destination; + } + + public void setDestination(String destination) { + this.destination = destination; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public double getDealPrice() { + return dealPrice; + } + + public void setDealPrice(double dealPrice) { + this.dealPrice = dealPrice; + } + + public double getOldPrice() { + return oldPrice; + } + + public void setOldPrice(double oldPrice) { + this.oldPrice = oldPrice; + } + + public Date getDepartureDate() { + return departureDate; + } + + public void setDepartureDate(Date departureDate) { + this.departureDate = departureDate; + } + + public Date getArrivalDate() { + return arrivalDate; + } + + public void setArrivalDate(Date arrivalDate) { + this.arrivalDate = arrivalDate; + } + + @Override + public String toString() { + return "TravelDeal{" + "id=" + id + ", destination='" + destination + '\'' + ", description='" + description + '\'' + ", dealPrice=" + dealPrice + ", oldPrice=" + oldPrice + ", departureDate=" + departureDate + ", arrivalDate=" + arrivalDate + '}'; + } +} diff --git a/spring-cloud/spring-cloud-kubernetes/travel-agency-service/src/main/java/com/baeldung/spring/cloud/kubernetes/travelagency/repository/TravelDealRepository.java b/spring-cloud/spring-cloud-kubernetes/travel-agency-service/src/main/java/com/baeldung/spring/cloud/kubernetes/travelagency/repository/TravelDealRepository.java new file mode 100644 index 0000000000..20c1e3b67a --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes/travel-agency-service/src/main/java/com/baeldung/spring/cloud/kubernetes/travelagency/repository/TravelDealRepository.java @@ -0,0 +1,12 @@ +package com.baeldung.spring.cloud.kubernetes.travelagency.repository; + +import java.util.List; + +import com.baeldung.spring.cloud.kubernetes.travelagency.model.TravelDeal; +import org.springframework.data.mongodb.repository.MongoRepository; + +public interface TravelDealRepository extends MongoRepository { + + public List findByDestination(String destination); + +} \ No newline at end of file diff --git a/spring-cloud/spring-cloud-kubernetes/travel-agency-service/src/main/resources/application.properties b/spring-cloud/spring-cloud-kubernetes/travel-agency-service/src/main/resources/application.properties new file mode 100644 index 0000000000..ffe78f0917 --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes/travel-agency-service/src/main/resources/application.properties @@ -0,0 +1,14 @@ +spring.application.name=travel-agency-service +server.port=8080 +spring.cloud.kubernetes.reload.enabled=true +spring.cloud.kubernetes.secrets.name=db-secret +spring.data.mongodb.host=mongodb-service +spring.data.mongodb.port=27017 +spring.data.mongodb.database=admin +spring.data.mongodb.username=${MONGO_USERNAME} +spring.data.mongodb.password=${MONGO_PASSWORD} +management.endpoint.health.enabled=true +management.endpoint.info.enabled=true +management.endpoint.restart.enabled=true +com.baeldung.spring.cloud.kubernetes.services=debug + diff --git a/spring-cloud/spring-cloud-kubernetes/travel-agency-service/src/main/resources/logback-spring.xml b/spring-cloud/spring-cloud-kubernetes/travel-agency-service/src/main/resources/logback-spring.xml new file mode 100644 index 0000000000..49aeda8f9f --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes/travel-agency-service/src/main/resources/logback-spring.xml @@ -0,0 +1,17 @@ + + + + + + logstash:5000 + + + + + + + + + + + \ No newline at end of file diff --git a/spring-cloud/spring-cloud-kubernetes/travel-agency-service/src/main/resources/logback.xml b/spring-cloud/spring-cloud-kubernetes/travel-agency-service/src/main/resources/logback.xml new file mode 100644 index 0000000000..37492be5bf --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes/travel-agency-service/src/main/resources/logback.xml @@ -0,0 +1,13 @@ + + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n + + + + + + + diff --git a/spring-cloud/spring-cloud-kubernetes/travel-agency-service/src/test/java/com/baeldung/spring/cloud/kubernetes/travelagency/SpringContextIntegrationTest.java b/spring-cloud/spring-cloud-kubernetes/travel-agency-service/src/test/java/com/baeldung/spring/cloud/kubernetes/travelagency/SpringContextIntegrationTest.java new file mode 100644 index 0000000000..2f901d39f6 --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes/travel-agency-service/src/test/java/com/baeldung/spring/cloud/kubernetes/travelagency/SpringContextIntegrationTest.java @@ -0,0 +1,16 @@ +package com.baeldung.spring.cloud.kubernetes.travelagency; + + +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(classes = Application.class) +public class SpringContextIntegrationTest { + + @Test + public void whenSpringContextIsBootstrapped_thenNoExceptions() { + } +} \ No newline at end of file diff --git a/spring-cloud/spring-cloud-kubernetes/travel-agency-service/travel-agency-deployment.yaml b/spring-cloud/spring-cloud-kubernetes/travel-agency-service/travel-agency-deployment.yaml new file mode 100644 index 0000000000..a41f13bf61 --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes/travel-agency-service/travel-agency-deployment.yaml @@ -0,0 +1,44 @@ +kind: Service +apiVersion: v1 +metadata: + name: travel-agency-service +spec: + selector: + app: travel-agency-service + ports: + - protocol: TCP + port: 8080 + nodePort: 30081 + type: NodePort +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: travel-agency-service +spec: + selector: + matchLabels: + app: travel-agency-service + replicas: 2 + template: + metadata: + labels: + app: travel-agency-service + spec: + containers: + - name: travel-agency-service + image: travel-agency-service:latest + imagePullPolicy: Never + ports: + - containerPort: 8080 + env: + - name: MONGO_USERNAME + valueFrom: + secretKeyRef: + name: db-secret + key: username + - name: MONGO_PASSWORD + valueFrom: + secretKeyRef: + name: db-secret + key: password \ No newline at end of file diff --git a/spring-cloud/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/SpringContextIntegrationTest.java b/spring-cloud/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/SpringContextIntegrationTest.java new file mode 100644 index 0000000000..77d294093c --- /dev/null +++ b/spring-cloud/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/SpringContextIntegrationTest.java @@ -0,0 +1,16 @@ +package com.baeldung.cloud.openfeign; + + +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(classes = ExampleApplication.class) +public class SpringContextIntegrationTest { + + @Test + public void whenSpringContextIsBootstrapped_thenNoExceptions() { + } +} \ No newline at end of file diff --git a/spring-cloud/spring-cloud-rest/spring-cloud-rest-books-api/src/test/java/org/baeldung/SpringContextLiveTest.java b/spring-cloud/spring-cloud-rest/spring-cloud-rest-books-api/src/test/java/org/baeldung/SpringContextLiveTest.java new file mode 100644 index 0000000000..eb56c16c6a --- /dev/null +++ b/spring-cloud/spring-cloud-rest/spring-cloud-rest-books-api/src/test/java/org/baeldung/SpringContextLiveTest.java @@ -0,0 +1,21 @@ +package org.baeldung; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +/** + * + * This Live Test requires: + * * A Redis instance running in port 6379 (e.g. using `docker run --name some-redis -p 6379:6379 -d redis`) + * + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = BooksApiApplication.class) +public class SpringContextLiveTest { + + @Test + public void whenSpringContextIsBootstrapped_thenNoExceptions() { + } +} diff --git a/spring-cloud/spring-cloud-rest/spring-cloud-rest-discovery-server/src/test/java/org/baeldung/SpringContextLiveTest.java b/spring-cloud/spring-cloud-rest/spring-cloud-rest-discovery-server/src/test/java/org/baeldung/SpringContextLiveTest.java new file mode 100644 index 0000000000..01266a3bda --- /dev/null +++ b/spring-cloud/spring-cloud-rest/spring-cloud-rest-discovery-server/src/test/java/org/baeldung/SpringContextLiveTest.java @@ -0,0 +1,21 @@ +package org.baeldung; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +/** + * + * This Live Test requires: + * * A Redis instance running in port 6379 (e.g. using `docker run --name some-redis -p 6379:6379 -d redis`) + * + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = SpringCloudRestServerApplication.class) +public class SpringContextLiveTest { + + @Test + public void whenSpringContextIsBootstrapped_thenNoExceptions() { + } +} diff --git a/spring-cloud/spring-cloud-rest/spring-cloud-rest-reviews-api/src/test/java/org/baeldung/SpringContextLiveTest.java b/spring-cloud/spring-cloud-rest/spring-cloud-rest-reviews-api/src/test/java/org/baeldung/SpringContextLiveTest.java new file mode 100644 index 0000000000..070abd246f --- /dev/null +++ b/spring-cloud/spring-cloud-rest/spring-cloud-rest-reviews-api/src/test/java/org/baeldung/SpringContextLiveTest.java @@ -0,0 +1,21 @@ +package org.baeldung; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +/** + * + * This Live Test requires: + * * A Redis instance running in port 6379 (e.g. using `docker run --name some-redis -p 6379:6379 -d redis`) + * + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = BookReviewsApiApplication.class) +public class SpringContextLiveTest { + + @Test + public void whenSpringContextIsBootstrapped_thenNoExceptions() { + } +} diff --git a/spring-cloud/spring-cloud-stream-starters/twitterhdfs/src/test/java/com/baeldung/twitterhdfs/aggregate/SpringContextIntegrationTest.java b/spring-cloud/spring-cloud-stream-starters/twitterhdfs/src/test/java/com/baeldung/twitterhdfs/aggregate/SpringContextIntegrationTest.java new file mode 100644 index 0000000000..b5cef1b5ed --- /dev/null +++ b/spring-cloud/spring-cloud-stream-starters/twitterhdfs/src/test/java/com/baeldung/twitterhdfs/aggregate/SpringContextIntegrationTest.java @@ -0,0 +1,15 @@ +package com.baeldung.twitterhdfs.aggregate; + +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(classes = AggregateApp.class) +public class SpringContextIntegrationTest { + + @Test + public void whenSpringContextIsBootstrapped_thenNoExceptions() { + } +} diff --git a/spring-cloud/spring-cloud-stream-starters/twitterhdfs/src/test/java/org/baeldung/SpringContextIntegrationTest.java b/spring-cloud/spring-cloud-stream-starters/twitterhdfs/src/test/java/org/baeldung/SpringContextIntegrationTest.java deleted file mode 100644 index 3d370e7b48..0000000000 --- a/spring-cloud/spring-cloud-stream-starters/twitterhdfs/src/test/java/org/baeldung/SpringContextIntegrationTest.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.baeldung; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; - -import com.baeldung.twitterhdfs.aggregate.AggregateApp; -import com.baeldung.twitterhdfs.processor.ProcessorApp; -import com.baeldung.twitterhdfs.sink.SinkApp; -import com.baeldung.twitterhdfs.source.SourceApp; - -@RunWith(SpringRunner.class) -@SpringBootTest(classes = {AggregateApp.class, ProcessorApp.class, SinkApp.class, SourceApp.class}) -public class SpringContextIntegrationTest { - - @Test - public void whenSpringContextIsBootstrapped_thenNoExceptions() { - } -} diff --git a/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/main/resources/application.yml b/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/main/resources/application.yml index 1187c12fe7..71275793ec 100644 --- a/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/main/resources/application.yml +++ b/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/main/resources/application.yml @@ -3,11 +3,11 @@ logging: org: springframework: cloud: - task=DEBUG + task: DEBUG spring: application: - name=helloWorld + name: helloWorld datasource: url: jdbc:mysql://localhost:3306/springcloud?useSSL=false username: root diff --git a/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/test/java/org/baeldung/SpringContextLiveTest.java b/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/test/java/org/baeldung/SpringContextLiveTest.java new file mode 100644 index 0000000000..ddbcbf65ea --- /dev/null +++ b/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/test/java/org/baeldung/SpringContextLiveTest.java @@ -0,0 +1,29 @@ +package org.baeldung; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.test.context.ConfigFileApplicationContextInitializer; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.baeldung.task.JobConfiguration; +import com.baeldung.task.TaskDemo; + +/** + * This Live Test requires: + * * a MySql instance running, that allows a root user with no password, and with a database named + * + * (e.g. with the following command `docker run -p 3306:3306 --name bael-mysql -e MYSQL_ALLOW_EMPTY_PASSWORD=true -e MYSQL_DATABASE=springcloud mysql:latest`) + * + */ +@RunWith(SpringJUnit4ClassRunner.class) +@SpringBootApplication +@ContextConfiguration(classes = { JobConfiguration.class, TaskDemo.class }, initializers = { + ConfigFileApplicationContextInitializer.class }) +public class SpringContextLiveTest { + + @Test + public void whenSpringContextIsBootstrapped_thenNoExceptions() { + } +} diff --git a/spring-cloud/spring-cloud-vault/src/test/java/org/baeldung/spring/cloud/vaultsample/SpringContextIntegrationTest.java b/spring-cloud/spring-cloud-vault/src/test/java/org/baeldung/spring/cloud/vaultsample/SpringContextIntegrationTest.java new file mode 100644 index 0000000000..e1eb2f8e24 --- /dev/null +++ b/spring-cloud/spring-cloud-vault/src/test/java/org/baeldung/spring/cloud/vaultsample/SpringContextIntegrationTest.java @@ -0,0 +1,15 @@ +package org.baeldung.spring.cloud.vaultsample; + +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(classes = VaultSampleApplication.class) +public class SpringContextIntegrationTest { + + @Test + public void whenSpringContextIsBootstrapped_thenNoExceptions() { + } +} \ No newline at end of file diff --git a/spring-cloud/spring-cloud-zookeeper/HelloWorld/pom.xml b/spring-cloud/spring-cloud-zookeeper/HelloWorld/pom.xml index 262b059544..0da0f7503e 100644 --- a/spring-cloud/spring-cloud-zookeeper/HelloWorld/pom.xml +++ b/spring-cloud/spring-cloud-zookeeper/HelloWorld/pom.xml @@ -34,6 +34,12 @@ + + org.springframework.boot + spring-boot-starter-test + ${spring-boot.version} + test + diff --git a/spring-cloud/spring-cloud-zookeeper/HelloWorld/src/test/java/com/baeldung/spring/cloud/helloworld/SpringContextIntegrationTest.java b/spring-cloud/spring-cloud-zookeeper/HelloWorld/src/test/java/com/baeldung/spring/cloud/helloworld/SpringContextIntegrationTest.java new file mode 100644 index 0000000000..2770649aa3 --- /dev/null +++ b/spring-cloud/spring-cloud-zookeeper/HelloWorld/src/test/java/com/baeldung/spring/cloud/helloworld/SpringContextIntegrationTest.java @@ -0,0 +1,16 @@ +package com.baeldung.spring.cloud.helloworld; + + +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(classes = HelloWorldApplication.class) +public class SpringContextIntegrationTest { + + @Test + public void whenSpringContextIsBootstrapped_thenNoExceptions() { + } +} \ No newline at end of file diff --git a/spring-cloud/spring-cloud-zookeeper/README.md b/spring-cloud/spring-cloud-zookeeper/README.md index a639833452..a49a448833 100644 --- a/spring-cloud/spring-cloud-zookeeper/README.md +++ b/spring-cloud/spring-cloud-zookeeper/README.md @@ -1,2 +1,2 @@ ### Relevant Articles: -- [An Introduction to Spring Cloud Zookeeper](http://www.baeldung.com/spring-cloud-zookeeper) +- [An Intro to Spring Cloud Zookeeper](http://www.baeldung.com/spring-cloud-zookeeper) diff --git a/spring-cloud/spring-cloud-zuul-eureka-integration/eureka-client/pom.xml b/spring-cloud/spring-cloud-zuul-eureka-integration/eureka-client/pom.xml index 0b479ec226..af7df71d17 100644 --- a/spring-cloud/spring-cloud-zuul-eureka-integration/eureka-client/pom.xml +++ b/spring-cloud/spring-cloud-zuul-eureka-integration/eureka-client/pom.xml @@ -25,6 +25,13 @@ spring-boot-starter-web ${spring-boot-starter-web.version} + + + org.springframework.boot + spring-boot-starter-test + ${spring-boot-starter-web.version} + test + diff --git a/spring-cloud/spring-cloud-zuul-eureka-integration/eureka-client/src/test/java/com/baeldung/spring/cloud/eureka/client/SpringContextIntegrationTest.java b/spring-cloud/spring-cloud-zuul-eureka-integration/eureka-client/src/test/java/com/baeldung/spring/cloud/eureka/client/SpringContextIntegrationTest.java new file mode 100644 index 0000000000..9eaff8f510 --- /dev/null +++ b/spring-cloud/spring-cloud-zuul-eureka-integration/eureka-client/src/test/java/com/baeldung/spring/cloud/eureka/client/SpringContextIntegrationTest.java @@ -0,0 +1,16 @@ +package com.baeldung.spring.cloud.eureka.client; + +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 SpringContextIntegrationTest { + + @Test + public void whenSpringContextIsBootstrapped_thenNoExceptions() { + } + +} diff --git a/spring-cloud/spring-cloud-zuul-eureka-integration/eureka-server/pom.xml b/spring-cloud/spring-cloud-zuul-eureka-integration/eureka-server/pom.xml index eea22779a6..d1f618507f 100644 --- a/spring-cloud/spring-cloud-zuul-eureka-integration/eureka-server/pom.xml +++ b/spring-cloud/spring-cloud-zuul-eureka-integration/eureka-server/pom.xml @@ -25,7 +25,13 @@ commons-configuration ${commons-config.version} - + + + org.springframework.boot + spring-boot-starter-test + ${spring-boot-starter-web.version} + test + diff --git a/spring-cloud/spring-cloud-zuul-eureka-integration/eureka-server/src/test/java/com/baeldung/spring/cloud/eureka/server/SpringContextIntegrationTest.java b/spring-cloud/spring-cloud-zuul-eureka-integration/eureka-server/src/test/java/com/baeldung/spring/cloud/eureka/server/SpringContextIntegrationTest.java new file mode 100644 index 0000000000..f03913b474 --- /dev/null +++ b/spring-cloud/spring-cloud-zuul-eureka-integration/eureka-server/src/test/java/com/baeldung/spring/cloud/eureka/server/SpringContextIntegrationTest.java @@ -0,0 +1,16 @@ +package com.baeldung.spring.cloud.eureka.server; + +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 SpringContextIntegrationTest { + + @Test + public void whenSpringContextIsBootstrapped_thenNoExceptions() { + } + +} diff --git a/spring-cloud/spring-cloud-zuul-eureka-integration/zuul-server/pom.xml b/spring-cloud/spring-cloud-zuul-eureka-integration/zuul-server/pom.xml index 39f94efdf0..57a11f3385 100644 --- a/spring-cloud/spring-cloud-zuul-eureka-integration/zuul-server/pom.xml +++ b/spring-cloud/spring-cloud-zuul-eureka-integration/zuul-server/pom.xml @@ -33,6 +33,13 @@ rxjava ${rxjava.version} + + + org.springframework.boot + spring-boot-starter-test + ${spring-boot-starter-web.version} + test + diff --git a/spring-cloud/spring-cloud-zuul-eureka-integration/zuul-server/src/test/java/com/baeldung/spring/cloud/zuul/config/SpringContextIntegrationTest.java b/spring-cloud/spring-cloud-zuul-eureka-integration/zuul-server/src/test/java/com/baeldung/spring/cloud/zuul/config/SpringContextIntegrationTest.java new file mode 100644 index 0000000000..cfd362edf8 --- /dev/null +++ b/spring-cloud/spring-cloud-zuul-eureka-integration/zuul-server/src/test/java/com/baeldung/spring/cloud/zuul/config/SpringContextIntegrationTest.java @@ -0,0 +1,16 @@ +package com.baeldung.spring.cloud.zuul.config; + +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 SpringContextIntegrationTest { + + @Test + public void whenSpringContextIsBootstrapped_thenNoExceptions() { + } + +} diff --git a/spring-cloud/spring-cloud-aws/src/test/java/org/baeldung/SpringContextIntegrationTest.java b/spring-cloud/spring-cloud-zuul/src/test/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/SpringContextIntegrationTest.java similarity index 62% rename from spring-cloud/spring-cloud-aws/src/test/java/org/baeldung/SpringContextIntegrationTest.java rename to spring-cloud/spring-cloud-zuul/src/test/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/SpringContextIntegrationTest.java index fcba9c4132..dbcdbdd434 100644 --- a/spring-cloud/spring-cloud-aws/src/test/java/org/baeldung/SpringContextIntegrationTest.java +++ b/spring-cloud/spring-cloud-zuul/src/test/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/SpringContextIntegrationTest.java @@ -1,17 +1,17 @@ -package org.baeldung; +package com.baeldung.spring.cloud.zuulratelimitdemo.controller; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; -import com.baeldung.spring.cloud.aws.InstanceProfileAwsApplication; +import com.baeldung.spring.cloud.zuulratelimitdemo.ZuulRatelimitDemoApplication; @RunWith(SpringRunner.class) -@SpringBootTest(classes = InstanceProfileAwsApplication.class) +@SpringBootTest(classes = ZuulRatelimitDemoApplication.class) public class SpringContextIntegrationTest { @Test public void whenSpringContextIsBootstrapped_thenNoExceptions() { } -} +} \ No newline at end of file diff --git a/spring-core/README.md b/spring-core/README.md index dcc15a4cb9..d542fa8ed1 100644 --- a/spring-core/README.md +++ b/spring-core/README.md @@ -23,3 +23,4 @@ - [Unsatisfied Dependency in Spring](https://www.baeldung.com/spring-unsatisfied-dependency) - [What is a Spring Bean?](https://www.baeldung.com/spring-bean) - [Spring PostConstruct and PreDestroy Annotations](https://www.baeldung.com/spring-postconstruct-predestroy) +- [Guice vs Spring – Dependency Injection](https://www.baeldung.com/guice-spring-dependency-injection) diff --git a/spring-core/pom.xml b/spring-core/pom.xml index d348d742e7..814addecdd 100644 --- a/spring-core/pom.xml +++ b/spring-core/pom.xml @@ -10,9 +10,9 @@ com.baeldung - parent-spring-4 + parent-spring-5 0.0.1-SNAPSHOT - ../parent-spring-4 + ../parent-spring-5 diff --git a/spring-data-rest/README.md b/spring-data-rest/README.md index 1624a3abfd..abbacb69cc 100644 --- a/spring-data-rest/README.md +++ b/spring-data-rest/README.md @@ -22,3 +22,4 @@ To view the running application, visit [http://localhost:8080](http://localhost: - [Spring Data REST Events with @RepositoryEventHandler](http://www.baeldung.com/spring-data-rest-events) - [Customizing HTTP Endpoints in Spring Data REST](https://www.baeldung.com/spring-data-rest-customize-http-endpoints) - [Spring Boot with SQLite](https://www.baeldung.com/spring-boot-sqlite) +- [Spring Data Web Support](https://www.baeldung.com/spring-data-web-support) diff --git a/spring-data-rest/pom.xml b/spring-data-rest/pom.xml index 772d6f2553..525c88c9d8 100644 --- a/spring-data-rest/pom.xml +++ b/spring-data-rest/pom.xml @@ -1,8 +1,7 @@ + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - com.baeldung spring-data-rest 1.0 spring-data-rest @@ -21,6 +20,10 @@ org.springframework.boot spring-boot-starter + + org.springframework.boot + spring-boot-starter-web + org.springframework.boot spring-boot-starter-data-rest @@ -29,32 +32,59 @@ org.springframework.boot spring-boot-starter-data-jpa - - com.h2database - h2 - org.springframework.boot spring-boot-autoconfigure + + org.springframework.boot + spring-boot-starter-test + test + + + com.querydsl + querydsl-apt + + + com.querydsl + querydsl-jpa + org.xerial sqlite-jdbc - ${sqlite.version} - ${project.artifactId} + + + com.mysema.maven + maven-apt-plugin + 1.0 + + + generate-sources + + process + + + target/generated-sources + com.querydsl.apt.jpa.JPAAnnotationProcessor + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + UTF-8 com.baeldung.SpringDataRestApplication - 3.25.2 - 2.1.0.RELEASE diff --git a/spring-data-rest/src/main/java/com/baeldung/springdatawebsupport/application/Application.java b/spring-data-rest/src/main/java/com/baeldung/springdatawebsupport/application/Application.java new file mode 100644 index 0000000000..fe2f996d37 --- /dev/null +++ b/spring-data-rest/src/main/java/com/baeldung/springdatawebsupport/application/Application.java @@ -0,0 +1,28 @@ +package com.baeldung.springdatawebsupport.application; + +import com.baeldung.springdatawebsupport.application.entities.User; +import com.baeldung.springdatawebsupport.application.repositories.UserRepository; +import java.util.stream.Stream; +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 + CommandLineRunner initialize(UserRepository userRepository) { + return args -> { + Stream.of("John", "Robert", "Nataly", "Helen", "Mary").forEach(name -> { + User user = new User(name); + userRepository.save(user); + }); + userRepository.findAll().forEach(System.out::println); + }; + } +} diff --git a/spring-data-rest/src/main/java/com/baeldung/springdatawebsupport/application/controllers/UserController.java b/spring-data-rest/src/main/java/com/baeldung/springdatawebsupport/application/controllers/UserController.java new file mode 100644 index 0000000000..8258c3b7aa --- /dev/null +++ b/spring-data-rest/src/main/java/com/baeldung/springdatawebsupport/application/controllers/UserController.java @@ -0,0 +1,47 @@ +package com.baeldung.springdatawebsupport.application.controllers; + +import com.baeldung.springdatawebsupport.application.entities.User; +import com.baeldung.springdatawebsupport.application.repositories.UserRepository; +import com.querydsl.core.types.Predicate; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.querydsl.binding.QuerydslPredicate; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestParam; +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/{id}") + public User findUserById(@PathVariable("id") User user) { + return user; + } + + @GetMapping("/users") + public Page findAllUsers(Pageable pageable) { + return userRepository.findAll(pageable); + } + + @GetMapping("/sortedusers") + public Page findAllUsersSortedByName() { + Pageable pageable = PageRequest.of(0, 5, Sort.by("name")); + return userRepository.findAll(pageable); + } + + @GetMapping("/filteredusers") + public Iterable getUsersByQuerydslPredicate(@QuerydslPredicate(root = User.class) Predicate predicate) { + return userRepository.findAll(predicate); + } +} diff --git a/spring-data-rest/src/main/java/com/baeldung/springdatawebsupport/application/entities/User.java b/spring-data-rest/src/main/java/com/baeldung/springdatawebsupport/application/entities/User.java new file mode 100644 index 0000000000..e9aaeb119a --- /dev/null +++ b/spring-data-rest/src/main/java/com/baeldung/springdatawebsupport/application/entities/User.java @@ -0,0 +1,38 @@ +package com.baeldung.springdatawebsupport.application.entities; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +@Entity +@Table(name = "users") +public class User { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private long id; + private final String name; + + public User() { + this.name = ""; + } + + public User(String name) { + this.name = name; + } + + public long getId() { + return id; + } + + public String getName() { + return name; + } + + @Override + public String toString() { + return "User{" + "id=" + id + ", name=" + name + '}'; + } +} diff --git a/spring-data-rest/src/main/java/com/baeldung/springdatawebsupport/application/repositories/UserRepository.java b/spring-data-rest/src/main/java/com/baeldung/springdatawebsupport/application/repositories/UserRepository.java new file mode 100644 index 0000000000..41d7ed9d98 --- /dev/null +++ b/spring-data-rest/src/main/java/com/baeldung/springdatawebsupport/application/repositories/UserRepository.java @@ -0,0 +1,14 @@ +package com.baeldung.springdatawebsupport.application.repositories; + +import com.baeldung.springdatawebsupport.application.entities.User; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.querydsl.QuerydslPredicateExecutor; +import org.springframework.data.repository.PagingAndSortingRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface UserRepository extends PagingAndSortingRepository, + QuerydslPredicateExecutor { + +} 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 ad219ccd53..274ae3bc1d 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 @@ -37,7 +37,7 @@ public class SpringDataProjectionLiveTest { @Before public void setup() { - if (bookRepo.findById(1L) == null) { + if (!bookRepo.findById(1L).isPresent()) { Book book = new Book("Animal Farm"); book.setIsbn("978-1943138425"); book = bookRepo.save(book); diff --git a/spring-data-rest/src/test/java/com/baeldung/springdatawebsupport/application/test/UserControllerIntegrationTest.java b/spring-data-rest/src/test/java/com/baeldung/springdatawebsupport/application/test/UserControllerIntegrationTest.java new file mode 100644 index 0000000000..db522b1413 --- /dev/null +++ b/spring-data-rest/src/test/java/com/baeldung/springdatawebsupport/application/test/UserControllerIntegrationTest.java @@ -0,0 +1,74 @@ +package com.baeldung.springdatawebsupport.application.test; + +import com.baeldung.springdatawebsupport.application.controllers.UserController; +import static org.assertj.core.api.Assertions.assertThat; +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 org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; + +@RunWith(SpringRunner.class) +@SpringBootTest +@AutoConfigureMockMvc +public class UserControllerIntegrationTest { + + @Autowired + private UserController userController; + + @Autowired + private MockMvc mockMvc; + + @Test + public void whenUserControllerInjected_thenNotNull() throws Exception { + assertThat(userController).isNotNull(); + } + + @Test + public void whenGetRequestToUsersEndPointWithIdPathVariable_thenCorrectResponse() throws Exception { + mockMvc.perform(MockMvcRequestBuilders.get("/users/{id}", "1") + .contentType(MediaType.APPLICATION_JSON_UTF8)) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$.id").value("1")); + } + + @Test + public void whenGetRequestToUsersEndPoint_thenCorrectResponse() throws Exception { + mockMvc.perform(MockMvcRequestBuilders.get("/users") + .contentType(MediaType.APPLICATION_JSON_UTF8)) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$['pageable']['paged']").value("true")); + + } + + @Test + public void whenGetRequestToUserEndPointWithNameRequestParameter_thenCorrectResponse() throws Exception { + mockMvc.perform(MockMvcRequestBuilders.get("/user") + .param("name", "John") + .contentType(MediaType.APPLICATION_JSON_UTF8)) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$['content'][0].['name']").value("John")); + } + + @Test + public void whenGetRequestToSorteredUsersEndPoint_thenCorrectResponse() throws Exception { + mockMvc.perform(MockMvcRequestBuilders.get("/sortedusers") + .contentType(MediaType.APPLICATION_JSON_UTF8)) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$['sort']['sorted']").value("true")); + } + + @Test + public void whenGetRequestToFilteredUsersEndPoint_thenCorrectResponse() throws Exception { + mockMvc.perform(MockMvcRequestBuilders.get("/filteredusers") + .param("name", "John") + .contentType(MediaType.APPLICATION_JSON_UTF8)) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$[0].name").value("John")); + } +} diff --git a/spring-ehcache/README.md b/spring-ehcache/README.md index 749441375e..ecf96cd7c7 100644 --- a/spring-ehcache/README.md +++ b/spring-ehcache/README.md @@ -3,5 +3,5 @@ A simple example of using ehcache with spring-boot. ### Relevant Articles: -- [Spring Boot Ehcache Example](http://www.baeldung.com/spring-ehcache) +- [Spring Boot Ehcache Example](https://www.baeldung.com/spring-boot-ehcache) diff --git a/spring-freemarker/pom.xml b/spring-freemarker/pom.xml index c71643dc39..40558476ef 100644 --- a/spring-freemarker/pom.xml +++ b/spring-freemarker/pom.xml @@ -48,7 +48,7 @@ org.springframework.boot spring-boot-starter-test - 1.5.10.RELEASE + ${spring-boot.version} test @@ -59,6 +59,7 @@ 2.3.28 3.1.0 false + 1.5.10.RELEASE diff --git a/spring-jersey/pom.xml b/spring-jersey/pom.xml index c12f6a1241..5a12d27180 100644 --- a/spring-jersey/pom.xml +++ b/spring-jersey/pom.xml @@ -95,28 +95,28 @@ com.github.tomakehurst wiremock - 1.58 + ${wiremock.version} test com.fasterxml.jackson.jaxrs jackson-jaxrs-json-provider - 2.9.7 + ${jackson.version} com.fasterxml.jackson.core jackson-databind - 2.9.7 + ${jackson.version} org.slf4j slf4j-jdk14 - 1.7.25 + ${org.slf4j.version} org.assertj assertj-core - 3.10.0 + ${assertj-core.version} test @@ -124,7 +124,7 @@ org.springframework.boot spring-boot-starter-test - 1.5.10.RELEASE + ${spring-boot.version} test @@ -228,6 +228,9 @@ 4.4.9 4.5.5 4.0.0 + 1.58 + 3.10.0 + 1.5.10.RELEASE diff --git a/spring-mvc-java/README.md b/spring-mvc-java/README.md index 851a3689ab..3deeb21afc 100644 --- a/spring-mvc-java/README.md +++ b/spring-mvc-java/README.md @@ -19,7 +19,7 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring - [Introduction to HtmlUnit](http://www.baeldung.com/htmlunit) - [Spring @RequestMapping New Shortcut Annotations](http://www.baeldung.com/spring-new-requestmapping-shortcuts) - [Guide to Spring Handler Mappings](http://www.baeldung.com/spring-handler-mappings) -- [Uploading and Displaying Excel Files with Spring MVC](http://www.baeldung.com/spring-mvc-excel-files) +- [Upload and Display Excel Files with Spring MVC](http://www.baeldung.com/spring-mvc-excel-files) - [Spring MVC Custom Validation](http://www.baeldung.com/spring-mvc-custom-validator) - [web.xml vs Initializer with Spring](http://www.baeldung.com/spring-xml-vs-java-config) - [The HttpMediaTypeNotAcceptableException in Spring MVC](http://www.baeldung.com/spring-httpmediatypenotacceptable) @@ -29,6 +29,6 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring - [A Quick Example of Spring Websockets’ @SendToUser Annotation](http://www.baeldung.com/spring-websockets-sendtouser) - [Using Spring ResponseEntity to Manipulate the HTTP Response](http://www.baeldung.com/spring-response-entity) - [Using Spring @ResponseStatus to Set HTTP Status Code](http://www.baeldung.com/spring-response-status) -- [Bootstrap a Web Application with Spring 5](https://www.baeldung.com/bootstraping-a-web-application-with-spring-and-java-based-configuration) - [Spring MVC Tutorial](https://www.baeldung.com/spring-mvc-tutorial) - [Working with Date Parameters in Spring](https://www.baeldung.com/spring-date-parameters) +- [A Java Web Application Without a web.xml](https://www.baeldung.com/java-web-app-without-web-xml) diff --git a/spring-mvc-java/src/main/java/com/baeldung/filters/EmptyParamFilter.java b/spring-mvc-java/src/main/java/com/baeldung/filters/EmptyParamFilter.java new file mode 100644 index 0000000000..b0b5392237 --- /dev/null +++ b/spring-mvc-java/src/main/java/com/baeldung/filters/EmptyParamFilter.java @@ -0,0 +1,35 @@ +package com.baeldung.filters; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.annotation.WebFilter; +import java.io.IOException; + +@WebFilter(urlPatterns = "/uppercase") +public class EmptyParamFilter implements Filter { + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + } + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, + FilterChain filterChain) throws IOException, ServletException { + String inputString = servletRequest.getParameter("input"); + + if (inputString != null && inputString.matches("[A-Za-z0-9]+")) { + filterChain.doFilter(servletRequest, servletResponse); + } else { + servletResponse.getWriter().println("Missing input parameter"); + } + } + + @Override + public void destroy() { + } + +} diff --git a/spring-mvc-java/src/main/java/com/baeldung/listeners/AppListener.java b/spring-mvc-java/src/main/java/com/baeldung/listeners/AppListener.java new file mode 100644 index 0000000000..ed16dd1654 --- /dev/null +++ b/spring-mvc-java/src/main/java/com/baeldung/listeners/AppListener.java @@ -0,0 +1,21 @@ +package com.baeldung.listeners; + +import javax.servlet.ServletContext; +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; +import javax.servlet.annotation.WebListener; + +@WebListener +public class AppListener implements ServletContextListener { + + @Override + public void contextInitialized(ServletContextEvent event) { + ServletContext context = event.getServletContext(); + context.setAttribute("counter", 0); + } + + @Override + public void contextDestroyed(ServletContextEvent event) { + + } +} diff --git a/spring-mvc-java/src/main/java/com/baeldung/listeners/RequestListener.java b/spring-mvc-java/src/main/java/com/baeldung/listeners/RequestListener.java new file mode 100644 index 0000000000..7f0c37b666 --- /dev/null +++ b/spring-mvc-java/src/main/java/com/baeldung/listeners/RequestListener.java @@ -0,0 +1,24 @@ +package com.baeldung.listeners; + +import javax.servlet.ServletContext; +import javax.servlet.ServletRequestEvent; +import javax.servlet.ServletRequestListener; +import javax.servlet.annotation.WebListener; +import javax.servlet.http.HttpServletRequest; + +@WebListener +public class RequestListener implements ServletRequestListener { + + @Override + public void requestInitialized(ServletRequestEvent event) { + } + + @Override + public void requestDestroyed(ServletRequestEvent event) { + HttpServletRequest request = (HttpServletRequest)event.getServletRequest(); + if (!request.getServletPath().equals("/counter")) { + ServletContext context = event.getServletContext(); + context.setAttribute("counter", (int)context.getAttribute("counter") + 1); + } + } +} diff --git a/spring-mvc-java/src/main/java/com/baeldung/servlets/CounterServlet.java b/spring-mvc-java/src/main/java/com/baeldung/servlets/CounterServlet.java new file mode 100644 index 0000000000..a11f084db2 --- /dev/null +++ b/spring-mvc-java/src/main/java/com/baeldung/servlets/CounterServlet.java @@ -0,0 +1,21 @@ +package com.baeldung.servlets; + +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.PrintWriter; + +@WebServlet(urlPatterns = "/counter", name = "counterServlet") +public class CounterServlet extends HttpServlet { + + public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { + PrintWriter out = response.getWriter(); + + int count = (int)request.getServletContext().getAttribute("counter"); + + out.println("Request counter: " + count); + } + +} diff --git a/spring-mvc-java/src/main/java/com/baeldung/servlets/UppercaseServlet.java b/spring-mvc-java/src/main/java/com/baeldung/servlets/UppercaseServlet.java new file mode 100644 index 0000000000..766ec2e6ff --- /dev/null +++ b/spring-mvc-java/src/main/java/com/baeldung/servlets/UppercaseServlet.java @@ -0,0 +1,20 @@ +package com.baeldung.servlets; + +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.PrintWriter; + +@WebServlet(urlPatterns = "/uppercase", name = "uppercaseServlet") +public class UppercaseServlet extends HttpServlet { + + public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { + String inputString = request.getParameter("input").toUpperCase(); + + PrintWriter out = response.getWriter(); + + out.println(inputString); + } +} diff --git a/spring-mvc-simple-2/pom.xml b/spring-mvc-simple-2/pom.xml new file mode 100644 index 0000000000..74302cff78 --- /dev/null +++ b/spring-mvc-simple-2/pom.xml @@ -0,0 +1,37 @@ + + + 4.0.0 + spring-mvc-simple-2 + war + spring-mvc-simple-2 + + + com.baeldung + parent-boot-2 + 0.0.1-SNAPSHOT + ../parent-boot-2 + + + + + org.springframework.boot + spring-boot-starter-web + + + + + 1.8 + 1.8 + + + + + + org.apache.maven.plugins + maven-war-plugin + + + spring-mvc-simple2 + + diff --git a/spring-mvc-simple-2/src/main/java/com/baeldung/spring/Application.java b/spring-mvc-simple-2/src/main/java/com/baeldung/spring/Application.java new file mode 100644 index 0000000000..40a0a55761 --- /dev/null +++ b/spring-mvc-simple-2/src/main/java/com/baeldung/spring/Application.java @@ -0,0 +1,11 @@ +package com.baeldung.spring; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } +} diff --git a/spring-mvc-simple-2/src/main/java/com/baeldung/spring/headers/controller/ReadHeaderRestController.java b/spring-mvc-simple-2/src/main/java/com/baeldung/spring/headers/controller/ReadHeaderRestController.java new file mode 100644 index 0000000000..6a0f3b6a0d --- /dev/null +++ b/spring-mvc-simple-2/src/main/java/com/baeldung/spring/headers/controller/ReadHeaderRestController.java @@ -0,0 +1,97 @@ +package com.baeldung.spring.headers.controller; + +import java.net.InetSocketAddress; +import java.util.Map; +import java.util.stream.Collectors; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.util.MultiValueMap; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class ReadHeaderRestController { + private static final Log LOG = LogFactory.getLog(ReadHeaderRestController.class); + + @GetMapping("/") + public ResponseEntity index() { + return new ResponseEntity("Index", HttpStatus.OK); + } + + @GetMapping("/greeting") + public ResponseEntity greeting(@RequestHeader(value = "accept-language") String language) { + String greeting = ""; + String firstLanguage = (language.length() > 1 ? language.substring(0, 2) : language); + switch (firstLanguage) { + case "es": + greeting = "Hola!"; + break; + case "de": + greeting = "Hallo!"; + break; + case "fr": + greeting = "Bonjour!"; + break; + case "en": + default: + greeting = "Hello!"; + break; + } + + return new ResponseEntity(greeting, HttpStatus.OK); + } + + @GetMapping("/double") + public ResponseEntity doubleNumber(@RequestHeader("my-number") int myNumber) { + return new ResponseEntity( + String.format("%d * 2 = %d", myNumber, (myNumber * 2)), + HttpStatus.OK); + } + + @GetMapping("/listHeaders") + public ResponseEntity listAllHeaders(@RequestHeader Map headers) { + + headers.forEach((key, value) -> { + LOG.info(String.format("Header '%s' = %s", key, value)); + }); + + return new ResponseEntity(String.format("Listed %d headers", headers.size()), HttpStatus.OK); + } + + @GetMapping("/multiValue") + public ResponseEntity multiValue(@RequestHeader MultiValueMap headers) { + headers.forEach((key, value) -> { + LOG.info(String.format("Header '%s' = %s", key, value.stream().collect(Collectors.joining("|")))); + }); + + return new ResponseEntity(String.format("Listed %d headers", headers.size()), HttpStatus.OK); + } + + @GetMapping("/getBaseUrl") + public ResponseEntity getBaseUrl(@RequestHeader HttpHeaders headers) { + InetSocketAddress host = headers.getHost(); + String url = "http://" + host.getHostName() + ":" + host.getPort(); + return new ResponseEntity(String.format("Base URL = %s", url), HttpStatus.OK); + } + + @GetMapping("/nonRequiredHeader") + public ResponseEntity evaluateNonRequiredHeader( + @RequestHeader(value = "optional-header", required = false) String optionalHeader) { + + return new ResponseEntity( + String.format("Was the optional header present? %s!", (optionalHeader == null ? "No" : "Yes")), + HttpStatus.OK); + } + + @GetMapping("/default") + public ResponseEntity evaluateDefaultHeaderValue( + @RequestHeader(value = "optional-header", defaultValue = "3600") int optionalHeader) { + + return new ResponseEntity(String.format("Optional Header is %d", optionalHeader), HttpStatus.OK); + } +} diff --git a/spring-mvc-simple-2/src/test/java/com/baeldung/AppContextIntegrationTest.java b/spring-mvc-simple-2/src/test/java/com/baeldung/AppContextIntegrationTest.java new file mode 100644 index 0000000000..27207688e6 --- /dev/null +++ b/spring-mvc-simple-2/src/test/java/com/baeldung/AppContextIntegrationTest.java @@ -0,0 +1,13 @@ +package com.baeldung; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +import com.baeldung.spring.Application; + +@SpringBootTest(classes = Application.class) +public class AppContextIntegrationTest { + @Test + public void contextLoads() { + } +} diff --git a/spring-mvc-simple-2/src/test/java/com/baeldung/headers/controller/ReadHeaderRestControllerIntegrationTest.java b/spring-mvc-simple-2/src/test/java/com/baeldung/headers/controller/ReadHeaderRestControllerIntegrationTest.java new file mode 100644 index 0000000000..6f94004cc7 --- /dev/null +++ b/spring-mvc-simple-2/src/test/java/com/baeldung/headers/controller/ReadHeaderRestControllerIntegrationTest.java @@ -0,0 +1,86 @@ +package com.baeldung.headers.controller; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.context.junit.jupiter.web.SpringJUnitWebConfig; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + +import com.baeldung.spring.headers.controller.ReadHeaderRestController; + +@SpringJUnitWebConfig(ReadHeaderRestControllerIntegrationTest.Config.class) +@ExtendWith(SpringExtension.class) +public class ReadHeaderRestControllerIntegrationTest { + private static final Log LOG = LogFactory.getLog(ReadHeaderRestControllerIntegrationTest.class); + + @Configuration + static class Config { + + } + + private MockMvc mockMvc; + + @BeforeEach + public void setUp() { + mockMvc = MockMvcBuilders.standaloneSetup(new ReadHeaderRestController()) + .build(); + } + + @Test + public void whenGetRequestSentToAllHeaders_thenStatusOkAndTextReturned() throws Exception { + mockMvc.perform(get("/listHeaders").header("my-header", "Test")) + .andExpect(status().isOk()) + .andExpect(content().string("Listed 1 headers")); + } + + @Test + public void whenGetRequestSentToMultiValue_thenStatusOkAndTextReturned() throws Exception { + mockMvc.perform(get("/multiValue").header("my-header", "ABC", "DEF", "GHI")) + .andExpect(status().isOk()) + .andExpect(content().string("Listed 1 headers")); + } + + @Test + public void whenGetRequestSentToGreeting_thenStatusOKAndGreetingReturned() throws Exception { + mockMvc.perform(get("/greeting").header("accept-language", "de")) + .andExpect(status().isOk()) + .andExpect(content().string("Hallo!")); + } + + @Test + public void whenGetRequestSentToDouble_thenStatusOKAndCorrectResultReturned() throws Exception { + mockMvc.perform(get("/double").header("my-number", 2)) + .andExpect(status().isOk()) + .andExpect(content().string("2 * 2 = 4")); + } + + @Test + public void whenGetRequestSentToGetBaseUrl_thenStatusOkAndHostReturned() throws Exception { + mockMvc.perform(get("/getBaseUrl").header("host", "localhost:8080")) + .andExpect(status().isOk()) + .andExpect(content().string("Base URL = http://localhost:8080")); + } + + @Test + public void whenGetRequestSentToNonRequiredHeaderWithoutHeader_thenStatusOKAndMessageReturned() throws Exception { + mockMvc.perform(get("/nonRequiredHeader")) + .andExpect(status().isOk()) + .andExpect(content().string("Was the optional header present? No!")); + } + + @Test + public void whenGetRequestSentToDefaultWithoutHeader_thenStatusOKAndMessageReturned() throws Exception { + mockMvc.perform(get("/default")) + .andExpect(status().isOk()) + .andExpect(content().string("Optional Header is 3600")); + } +} diff --git a/spring-mvc-simple/pom.xml b/spring-mvc-simple/pom.xml index 8c2661cc27..cdd4a9e13a 100644 --- a/spring-mvc-simple/pom.xml +++ b/spring-mvc-simple/pom.xml @@ -17,12 +17,12 @@ org.springframework spring-oxm - ${spring-oxm.version} + ${spring.version} com.sun.mail javax.mail - 1.6.1 + ${javax.mail.version} javax.servlet @@ -181,8 +181,8 @@ 1.4.9 5.1.0 20180130 - 5.0.2.RELEASE 3.0.8 + 1.6.1 diff --git a/spring-mvc-xml/README.md b/spring-mvc-xml/README.md index dbc6125424..216517f52d 100644 --- a/spring-mvc-xml/README.md +++ b/spring-mvc-xml/README.md @@ -14,3 +14,4 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring - [Guide to JavaServer Pages (JSP)](http://www.baeldung.com/jsp) - [Exploring SpringMVC’s Form Tag Library](http://www.baeldung.com/spring-mvc-form-tags) - [web.xml vs Initializer with Spring](http://www.baeldung.com/spring-xml-vs-java-config) +- [A Java Web Application Without a web.xml](https://www.baeldung.com/java-web-app-without-web-xml) diff --git a/spring-mvc-xml/pom.xml b/spring-mvc-xml/pom.xml index c6a6da406c..beea8e5ee2 100644 --- a/spring-mvc-xml/pom.xml +++ b/spring-mvc-xml/pom.xml @@ -88,7 +88,7 @@ org.springframework.boot spring-boot-starter-test - 1.5.10.RELEASE + ${spring-boot.version} test @@ -118,6 +118,7 @@ 5.0.2.RELEASE + 1.5.10.RELEASE 5.1.40 diff --git a/spring-reactor/pom.xml b/spring-reactor/pom.xml index 051244c9db..2d69096c58 100644 --- a/spring-reactor/pom.xml +++ b/spring-reactor/pom.xml @@ -27,12 +27,17 @@ io.projectreactor reactor-bus - 2.0.8.RELEASE + ${reactor.version} io.projectreactor reactor-core - 2.0.8.RELEASE + ${reactor.version} + + + 2.0.2.RELEASE + 2.0.8.RELEASE + diff --git a/spring-remoting/remoting-hessian-burlap/remoting-hessian-burlap-server/pom.xml b/spring-remoting/remoting-hessian-burlap/remoting-hessian-burlap-server/pom.xml index 33b824442f..fa16a9a9b1 100644 --- a/spring-remoting/remoting-hessian-burlap/remoting-hessian-burlap-server/pom.xml +++ b/spring-remoting/remoting-hessian-burlap/remoting-hessian-burlap-server/pom.xml @@ -25,7 +25,12 @@ com.caucho hessian - 4.0.38 + ${hessian.version} + + + 4.0.38 + + \ No newline at end of file diff --git a/spring-rest-full/README.md b/spring-rest-full/README.md index ed6df1675f..e0d3a70626 100644 --- a/spring-rest-full/README.md +++ b/spring-rest-full/README.md @@ -12,7 +12,6 @@ The "Learn Spring Security" Classes: http://github.learnspringsecurity.com - [Introduction to Spring Data JPA](http://www.baeldung.com/the-persistence-layer-with-spring-data-jpa) - [Project Configuration with Spring](http://www.baeldung.com/project-configuration-with-spring) - [Metrics for your Spring REST API](http://www.baeldung.com/spring-rest-api-metrics) -- [Bootstrap a Web Application with Spring 5](http://www.baeldung.com/bootstraping-a-web-application-with-spring-and-java-based-configuration) - [Spring Security Expressions - hasRole Example](https://www.baeldung.com/spring-security-expressions-basic) diff --git a/spring-rest-hal-browser/pom.xml b/spring-rest-hal-browser/pom.xml index 413aad9e8c..cc3b1b65fe 100644 --- a/spring-rest-hal-browser/pom.xml +++ b/spring-rest-hal-browser/pom.xml @@ -8,6 +8,13 @@ 1.0-SNAPSHOT spring-rest-hal-browser + + parent-boot-1 + com.baeldung + 0.0.1-SNAPSHOT + ../parent-boot-1 + + diff --git a/spring-rest-shell/README.md b/spring-rest-shell/README.md index 901d9a51ee..b250f06a4b 100644 --- a/spring-rest-shell/README.md +++ b/spring-rest-shell/README.md @@ -2,4 +2,4 @@ ### Relevant Articles -- [Spring REST Shell](http://www.baeldung.com/spring-rest-shell) \ No newline at end of file +- [Introduction to Spring REST Shell](http://www.baeldung.com/spring-rest-shell) diff --git a/spring-rest-simple/README.md b/spring-rest-simple/README.md index 179e556202..882d0ac301 100644 --- a/spring-rest-simple/README.md +++ b/spring-rest-simple/README.md @@ -3,6 +3,5 @@ - [Guide to UriComponentsBuilder in Spring](http://www.baeldung.com/spring-uricomponentsbuilder) - [Returning Custom Status Codes from Spring Controllers](http://www.baeldung.com/spring-mvc-controller-custom-http-status-code) - [Spring RequestMapping](http://www.baeldung.com/spring-requestmapping) -- [ETags for REST with Spring](http://www.baeldung.com/etags-for-rest-with-spring) - [Spring and Apache FileUpload](http://www.baeldung.com/spring-apache-file-upload) - [Test a REST API with curl](http://www.baeldung.com/curl-rest) diff --git a/spring-rest-simple/src/main/java/org/baeldung/web/controller/FooController.java b/spring-rest-simple/src/main/java/org/baeldung/web/controller/FooController.java index e8cb218258..c68d586667 100644 --- a/spring-rest-simple/src/main/java/org/baeldung/web/controller/FooController.java +++ b/spring-rest-simple/src/main/java/org/baeldung/web/controller/FooController.java @@ -2,12 +2,21 @@ package org.baeldung.web.controller; import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic; +import java.util.List; + import org.baeldung.web.dto.Foo; import org.baeldung.web.dto.FooProtos; import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.*; +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 com.google.common.collect.Lists; @Controller public class FooController { @@ -16,6 +25,12 @@ public class FooController { super(); } + @RequestMapping(method = RequestMethod.GET, value = "/foos") + @ResponseBody + public List findListOfFoo() { + return Lists.newArrayList(new Foo(1, randomAlphabetic(4))); + } + // API - read @RequestMapping(method = RequestMethod.GET, value = "/foos/{id}") @@ -32,6 +47,27 @@ public class FooController { public Foo updateFoo(@PathVariable("id") final String id, @RequestBody final Foo foo) { return foo; } + + @RequestMapping(method = RequestMethod.PATCH, value = "/foos/{id}") + @ResponseStatus(HttpStatus.OK) + @ResponseBody + public Foo patchFoo(@PathVariable("id") final String id, @RequestBody final Foo foo) { + return foo; + } + + @RequestMapping(method = RequestMethod.POST, value = "/foos") + @ResponseStatus(HttpStatus.CREATED) + @ResponseBody + public Foo postFoo(@RequestBody final Foo foo) { + return foo; + } + + @RequestMapping(method = RequestMethod.HEAD, value = "/foos") + @ResponseStatus(HttpStatus.OK) + @ResponseBody + public Foo headFoo() { + return new Foo(1, randomAlphabetic(4)); + } @RequestMapping(method = RequestMethod.GET, value = "/foos/{id}", produces = { "application/x-protobuf" }) @ResponseBody diff --git a/spring-rest-simple/src/test/java/org/baeldung/web/test/RestTemplateBasicLiveTest.java b/spring-rest-simple/src/test/java/org/baeldung/web/test/RestTemplateBasicLiveTest.java new file mode 100644 index 0000000000..e213d0255f --- /dev/null +++ b/spring-rest-simple/src/test/java/org/baeldung/web/test/RestTemplateBasicLiveTest.java @@ -0,0 +1,269 @@ +package org.baeldung.web.test; + +import static org.apache.commons.codec.binary.Base64.encodeBase64; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.io.IOException; +import java.net.URI; +import java.util.Arrays; +import java.util.Set; + +import org.baeldung.web.dto.Foo; +import org.junit.Before; +import org.junit.Test; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.http.client.ClientHttpRequestFactory; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.RequestCallback; +import org.springframework.web.client.RestTemplate; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.dataformat.xml.XmlMapper; +import com.google.common.base.Charsets; + +public class RestTemplateBasicLiveTest { + + private RestTemplate restTemplate; + private static final String fooResourceUrl = "http://localhost:8082/spring-rest/foos"; + + @Before + public void beforeTest() { + restTemplate = new RestTemplate(); + // restTemplate.setMessageConverters(Arrays.asList(new MappingJackson2HttpMessageConverter())); + } + + // GET + + @Test + public void givenResourceUrl_whenSendGetForRequestEntity_thenStatusOk() throws IOException { + final ResponseEntity response = restTemplate.getForEntity(fooResourceUrl + "/1", Foo.class); + + assertThat(response.getStatusCode(), equalTo(HttpStatus.OK)); + } + + @Test + public void givenResourceUrl_whenSendGetForRequestEntity_thenBodyCorrect() throws IOException { + final RestTemplate template = new RestTemplate(); + final ResponseEntity response = template.getForEntity(fooResourceUrl + "/1", String.class); + + final ObjectMapper mapper = new XmlMapper(); + final JsonNode root = mapper.readTree(response.getBody()); + final JsonNode name = root.path("name"); + assertThat(name.asText(), notNullValue()); + } + + @Test + public void givenResourceUrl_whenRetrievingResource_thenCorrect() throws IOException { + final Foo foo = restTemplate.getForObject(fooResourceUrl + "/1", Foo.class); + + assertThat(foo.getName(), notNullValue()); + assertThat(foo.getId(), is(1L)); + } + + // HEAD, OPTIONS + + @Test + public void givenFooService_whenCallHeadForHeaders_thenReceiveAllHeadersForThatResource() { + final HttpHeaders httpHeaders = restTemplate.headForHeaders(fooResourceUrl); + assertTrue(httpHeaders.getContentType() + .includes(MediaType.APPLICATION_JSON)); + } + + // POST + + @Test + public void givenFooService_whenPostForObject_thenCreatedObjectIsReturned() { + final HttpEntity request = new HttpEntity<>(new Foo("bar")); + final Foo foo = restTemplate.postForObject(fooResourceUrl, request, Foo.class); + assertThat(foo, notNullValue()); + assertThat(foo.getName(), is("bar")); + } + + @Test + public void givenFooService_whenPostForLocation_thenCreatedLocationIsReturned() { + final HttpEntity request = new HttpEntity<>(new Foo("bar")); + final URI location = restTemplate.postForLocation(fooResourceUrl, request); + assertThat(location, notNullValue()); + } + + @Test + public void givenFooService_whenPostResource_thenResourceIsCreated() { + final Foo foo = new Foo("bar"); + final ResponseEntity response = restTemplate.postForEntity(fooResourceUrl, foo, Foo.class); + + assertThat(response.getStatusCode(), is(HttpStatus.CREATED)); + final Foo fooResponse = response.getBody(); + assertThat(fooResponse, notNullValue()); + assertThat(fooResponse.getName(), is("bar")); + } + + @Test + public void givenFooService_whenCallOptionsForAllow_thenReceiveValueOfAllowHeader() { + final Set optionsForAllow = restTemplate.optionsForAllow(fooResourceUrl); + final HttpMethod[] supportedMethods = { HttpMethod.GET, HttpMethod.POST, HttpMethod.HEAD }; + + assertTrue(optionsForAllow.containsAll(Arrays.asList(supportedMethods))); + } + + // PUT + + @Test + public void givenFooService_whenPutExistingEntity_thenItIsUpdated() { + final HttpHeaders headers = prepareBasicAuthHeaders(); + final HttpEntity request = new HttpEntity<>(new Foo("bar"), headers); + + // Create Resource + final ResponseEntity createResponse = restTemplate.exchange(fooResourceUrl, HttpMethod.POST, request, Foo.class); + + // Update Resource + final Foo updatedInstance = new Foo("newName"); + updatedInstance.setId(createResponse.getBody() + .getId()); + final String resourceUrl = fooResourceUrl + '/' + createResponse.getBody() + .getId(); + final HttpEntity requestUpdate = new HttpEntity<>(updatedInstance, headers); + restTemplate.exchange(resourceUrl, HttpMethod.PUT, requestUpdate, Void.class); + + // Check that Resource was updated + final ResponseEntity updateResponse = restTemplate.exchange(resourceUrl, HttpMethod.GET, new HttpEntity<>(headers), Foo.class); + final Foo foo = updateResponse.getBody(); + assertThat(foo.getName(), is(updatedInstance.getName())); + } + + @Test + public void givenFooService_whenPutExistingEntityWithCallback_thenItIsUpdated() { + final HttpHeaders headers = prepareBasicAuthHeaders(); + final HttpEntity request = new HttpEntity<>(new Foo("bar"), headers); + + // Create entity + ResponseEntity response = restTemplate.exchange(fooResourceUrl, HttpMethod.POST, request, Foo.class); + assertThat(response.getStatusCode(), is(HttpStatus.CREATED)); + + // Update entity + final Foo updatedInstance = new Foo("newName"); + updatedInstance.setId(response.getBody() + .getId()); + final String resourceUrl = fooResourceUrl + '/' + response.getBody() + .getId(); + restTemplate.execute(resourceUrl, HttpMethod.PUT, requestCallback(updatedInstance), clientHttpResponse -> null); + + // Check that entity was updated + response = restTemplate.exchange(resourceUrl, HttpMethod.GET, new HttpEntity<>(headers), Foo.class); + final Foo foo = response.getBody(); + assertThat(foo.getName(), is(updatedInstance.getName())); + } + + // PATCH + + @Test + public void givenFooService_whenPatchExistingEntity_thenItIsUpdated() { + final HttpHeaders headers = prepareBasicAuthHeaders(); + final HttpEntity request = new HttpEntity<>(new Foo("bar"), headers); + + // Create Resource + final ResponseEntity createResponse = restTemplate.exchange(fooResourceUrl, HttpMethod.POST, request, Foo.class); + + // Update Resource + final Foo updatedResource = new Foo("newName"); + updatedResource.setId(createResponse.getBody() + .getId()); + final String resourceUrl = fooResourceUrl + '/' + createResponse.getBody() + .getId(); + final HttpEntity requestUpdate = new HttpEntity<>(updatedResource, headers); + final ClientHttpRequestFactory requestFactory = getSimpleClientHttpRequestFactory(); + final RestTemplate template = new RestTemplate(requestFactory); + template.setMessageConverters(Arrays.asList(new MappingJackson2HttpMessageConverter())); + template.patchForObject(resourceUrl, requestUpdate, Void.class); + + // Check that Resource was updated + final ResponseEntity updateResponse = restTemplate.exchange(resourceUrl, HttpMethod.GET, new HttpEntity<>(headers), Foo.class); + final Foo foo = updateResponse.getBody(); + assertThat(foo.getName(), is(updatedResource.getName())); + } + + // DELETE + + @Test + public void givenFooService_whenCallDelete_thenEntityIsRemoved() { + final Foo foo = new Foo("remove me"); + final ResponseEntity response = restTemplate.postForEntity(fooResourceUrl, foo, Foo.class); + assertThat(response.getStatusCode(), is(HttpStatus.CREATED)); + + final String entityUrl = fooResourceUrl + "/" + response.getBody() + .getId(); + restTemplate.delete(entityUrl); + try { + restTemplate.getForEntity(entityUrl, Foo.class); + fail(); + } catch (final HttpClientErrorException ex) { + assertThat(ex.getStatusCode(), is(HttpStatus.NOT_FOUND)); + } + } + + @Test + public void givenFooService_whenFormSubmit_thenResourceIsCreated() { + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); + + MultiValueMap map= new LinkedMultiValueMap<>(); + map.add("id", "1"); + + HttpEntity> request = new HttpEntity<>(map, headers); + + ResponseEntity response = restTemplate.postForEntity( fooResourceUrl+"/form", request , String.class); + + assertThat(response.getStatusCode(), is(HttpStatus.CREATED)); + final String fooResponse = response.getBody(); + assertThat(fooResponse, notNullValue()); + assertThat(fooResponse, is("1")); + } + + private HttpHeaders prepareBasicAuthHeaders() { + final HttpHeaders headers = new HttpHeaders(); + final String encodedLogPass = getBase64EncodedLogPass(); + headers.add(HttpHeaders.AUTHORIZATION, "Basic " + encodedLogPass); + return headers; + } + + private String getBase64EncodedLogPass() { + final String logPass = "user1:user1Pass"; + final byte[] authHeaderBytes = encodeBase64(logPass.getBytes(Charsets.US_ASCII)); + return new String(authHeaderBytes, Charsets.US_ASCII); + } + + private RequestCallback requestCallback(final Foo updatedInstance) { + return clientHttpRequest -> { + final ObjectMapper mapper = new ObjectMapper(); + mapper.writeValue(clientHttpRequest.getBody(), updatedInstance); + clientHttpRequest.getHeaders() + .add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); + clientHttpRequest.getHeaders() + .add(HttpHeaders.AUTHORIZATION, "Basic " + getBase64EncodedLogPass()); + }; + } + + // Simply setting restTemplate timeout using ClientHttpRequestFactory + + ClientHttpRequestFactory getSimpleClientHttpRequestFactory() { + final int timeout = 5; + final HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(); + clientHttpRequestFactory.setConnectTimeout(timeout * 1000); + return clientHttpRequestFactory; + } + +} diff --git a/spring-rest-simple/src/test/java/org/baeldung/web/test/TestRestTemplateBasicLiveTest.java b/spring-rest-simple/src/test/java/org/baeldung/web/test/TestRestTemplateBasicLiveTest.java new file mode 100644 index 0000000000..b920ed38da --- /dev/null +++ b/spring-rest-simple/src/test/java/org/baeldung/web/test/TestRestTemplateBasicLiveTest.java @@ -0,0 +1,122 @@ +package org.baeldung.web.test; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertTrue; + +import org.junit.Before; +import org.junit.Test; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.client.RestTemplate; + +import okhttp3.Request; +import okhttp3.RequestBody; + +public class TestRestTemplateBasicLiveTest { + + private RestTemplate restTemplate; + + private static final String FOO_RESOURCE_URL = "http://localhost:" + 8082 + "/spring-rest/foos"; + private static final String URL_SECURED_BY_AUTHENTICATION = "http://httpbin.org/basic-auth/user/passwd"; + private static final String BASE_URL = "http://localhost:" + 8082 + "/spring-rest"; + + @Before + public void beforeTest() { + restTemplate = new RestTemplate(); + } + + // GET + @Test + public void givenTestRestTemplate_whenSendGetForEntity_thenStatusOk() { + TestRestTemplate testRestTemplate = new TestRestTemplate(); + ResponseEntity response = testRestTemplate.getForEntity(FOO_RESOURCE_URL + "/1", String.class); + assertThat(response.getStatusCode(), equalTo(HttpStatus.OK)); + } + + @Test + public void givenRestTemplateWrapper_whenSendGetForEntity_thenStatusOk() { + RestTemplateBuilder restTemplateBuilder = new RestTemplateBuilder(); + restTemplateBuilder.configure(restTemplate); + TestRestTemplate testRestTemplate = new TestRestTemplate(restTemplateBuilder); + ResponseEntity response = testRestTemplate.getForEntity(FOO_RESOURCE_URL + "/1", String.class); + assertThat(response.getStatusCode(), equalTo(HttpStatus.OK)); + } + + @Test + public void givenRestTemplateBuilderWrapper_whenSendGetForEntity_thenStatusOk() { + RestTemplateBuilder restTemplateBuilder = new RestTemplateBuilder(); + restTemplateBuilder.build(); + TestRestTemplate testRestTemplate = new TestRestTemplate(restTemplateBuilder); + ResponseEntity response = testRestTemplate.getForEntity(FOO_RESOURCE_URL + "/1", String.class); + assertThat(response.getStatusCode(), equalTo(HttpStatus.OK)); + } + + @Test + public void givenRestTemplateWrapperWithCredentials_whenSendGetForEntity_thenStatusOk() { + RestTemplateBuilder restTemplateBuilder = new RestTemplateBuilder(); + restTemplateBuilder.configure(restTemplate); + TestRestTemplate testRestTemplate = new TestRestTemplate(restTemplateBuilder, "user", "passwd"); + ResponseEntity response = testRestTemplate.getForEntity(URL_SECURED_BY_AUTHENTICATION, + String.class); + assertThat(response.getStatusCode(), equalTo(HttpStatus.OK)); + } + + @Test + public void givenTestRestTemplateWithCredentials_whenSendGetForEntity_thenStatusOk() { + TestRestTemplate testRestTemplate = new TestRestTemplate("user", "passwd"); + ResponseEntity response = testRestTemplate.getForEntity(URL_SECURED_BY_AUTHENTICATION, + String.class); + assertThat(response.getStatusCode(), equalTo(HttpStatus.OK)); + } + + @Test + public void givenTestRestTemplateWithBasicAuth_whenSendGetForEntity_thenStatusOk() { + TestRestTemplate testRestTemplate = new TestRestTemplate(); + ResponseEntity response = testRestTemplate.withBasicAuth("user", "passwd"). + getForEntity(URL_SECURED_BY_AUTHENTICATION, String.class); + assertThat(response.getStatusCode(), equalTo(HttpStatus.OK)); + } + + @Test + public void givenTestRestTemplateWithCredentialsAndEnabledCookies_whenSendGetForEntity_thenStatusOk() { + TestRestTemplate testRestTemplate = new TestRestTemplate("user", "passwd", TestRestTemplate. + HttpClientOption.ENABLE_COOKIES); + ResponseEntity response = testRestTemplate.getForEntity(URL_SECURED_BY_AUTHENTICATION, + String.class); + assertThat(response.getStatusCode(), equalTo(HttpStatus.OK)); + } + + // HEAD + @Test + public void givenFooService_whenCallHeadForHeaders_thenReceiveAllHeaders() { + TestRestTemplate testRestTemplate = new TestRestTemplate(); + final HttpHeaders httpHeaders = testRestTemplate.headForHeaders(FOO_RESOURCE_URL); + assertTrue(httpHeaders.getContentType().includes(MediaType.APPLICATION_JSON)); + } + + // POST + @Test + public void givenService_whenPostForObject_thenCreatedObjectIsReturned() { + TestRestTemplate testRestTemplate = new TestRestTemplate("user", "passwd"); + final RequestBody body = RequestBody.create(okhttp3.MediaType.parse("text/html; charset=utf-8"), + "{\"id\":1,\"name\":\"Jim\"}"); + final Request request = new Request.Builder().url(BASE_URL + "/users/detail").post(body).build(); + testRestTemplate.postForObject(URL_SECURED_BY_AUTHENTICATION, request, String.class); + } + + // PUT + @Test + public void givenService_whenPutForObject_thenCreatedObjectIsReturned() { + TestRestTemplate testRestTemplate = new TestRestTemplate("user", "passwd"); + final RequestBody body = RequestBody.create(okhttp3.MediaType.parse("text/html; charset=utf-8"), + "{\"id\":1,\"name\":\"Jim\"}"); + final Request request = new Request.Builder().url(BASE_URL + "/users/detail").post(body).build(); + testRestTemplate.put(URL_SECURED_BY_AUTHENTICATION, request, String.class); + } + +} diff --git a/spring-rest/README.md b/spring-rest/README.md index 9a2c1fd96c..6d3aac3eb8 100644 --- a/spring-rest/README.md +++ b/spring-rest/README.md @@ -20,5 +20,4 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring - [Using the Spring RestTemplate Interceptor](http://www.baeldung.com/spring-rest-template-interceptor) - [Get and Post Lists of Objects with RestTemplate](http://www.baeldung.com/spring-rest-template-list) - [How to Set a Header on a Response with Spring 5](http://www.baeldung.com/spring-response-header) -- [Spring’s RequestBody and ResponseBody Annotations](https://www.baeldung.com/spring-request-response-body) - [Uploading MultipartFile with Spring RestTemplate](http://www.baeldung.com/spring-rest-template-multipart-upload) diff --git a/spring-resttemplate/pom.xml b/spring-resttemplate/pom.xml index 9a0978f120..06d4eed9fc 100644 --- a/spring-resttemplate/pom.xml +++ b/spring-resttemplate/pom.xml @@ -25,6 +25,10 @@ org.springframework.boot spring-boot-devtools + + org.springframework.boot + spring-boot-starter-web + org.springframework.boot spring-boot-starter-test diff --git a/spring-resttemplate/src/main/java/org/baeldung/resttemplate/configuration/RestTemplateConfigurationApplication.java b/spring-resttemplate/src/main/java/org/baeldung/resttemplate/RestTemplateConfigurationApplication.java similarity index 89% rename from spring-resttemplate/src/main/java/org/baeldung/resttemplate/configuration/RestTemplateConfigurationApplication.java rename to spring-resttemplate/src/main/java/org/baeldung/resttemplate/RestTemplateConfigurationApplication.java index 76fc346aca..9a361e92c9 100644 --- a/spring-resttemplate/src/main/java/org/baeldung/resttemplate/configuration/RestTemplateConfigurationApplication.java +++ b/spring-resttemplate/src/main/java/org/baeldung/resttemplate/RestTemplateConfigurationApplication.java @@ -1,4 +1,4 @@ -package org.baeldung.resttemplate.configuration; +package org.baeldung.resttemplate; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; diff --git a/spring-resttemplate/src/main/java/org/baeldung/resttemplate/configuration/FooController.java b/spring-resttemplate/src/main/java/org/baeldung/resttemplate/configuration/FooController.java new file mode 100644 index 0000000000..a9d400b199 --- /dev/null +++ b/spring-resttemplate/src/main/java/org/baeldung/resttemplate/configuration/FooController.java @@ -0,0 +1,124 @@ +package org.baeldung.resttemplate.configuration; + +import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic; + +import java.net.URI; +import java.util.Collection; +import java.util.Map; + +import org.baeldung.resttemplate.web.dto.Foo; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +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.client.HttpClientErrorException; +import org.springframework.web.servlet.support.ServletUriComponentsBuilder; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Maps; + +@Controller +public class FooController { + + private Map fooRepository = Maps.newHashMap(ImmutableMap.of(1L, new Foo(1L, randomAlphabetic(4)))); + + public FooController() { + super(); + } + + @RequestMapping(method = RequestMethod.GET, value = "/foos") + @ResponseBody + public Collection findListOfFoo() { + return fooRepository.values(); + } + + // API - read + + @RequestMapping(method = RequestMethod.GET, value = "/foos/{id}") + @ResponseBody + public Foo findById(@PathVariable final long id) throws HttpClientErrorException { + Foo foo = fooRepository.get(id); + + if (foo == null) { + throw new HttpClientErrorException(HttpStatus.NOT_FOUND); + } else { + return foo; + } + } + + // API - write + + @RequestMapping(method = RequestMethod.PUT, value = "/foos/{id}") + @ResponseStatus(HttpStatus.OK) + @ResponseBody + public Foo updateFoo(@PathVariable("id") final long id, @RequestBody final Foo foo) { + fooRepository.put(id, foo); + return foo; + } + + @RequestMapping(method = RequestMethod.PATCH, value = "/foos/{id}") + @ResponseStatus(HttpStatus.OK) + @ResponseBody + public Foo patchFoo(@PathVariable("id") final long id, @RequestBody final Foo foo) { + fooRepository.put(id, foo); + return foo; + } + + @RequestMapping(method = RequestMethod.POST, value = "/foos") + @ResponseStatus(HttpStatus.CREATED) + @ResponseBody + public ResponseEntity postFoo(@RequestBody final Foo foo) { + + fooRepository.put(foo.getId(), foo); + final URI location = ServletUriComponentsBuilder + .fromCurrentServletMapping() + .path("/foos/{id}") + .build() + .expand(foo.getId()) + .toUri(); + + final HttpHeaders headers = new HttpHeaders(); + headers.setLocation(location); + + final ResponseEntity entity = new ResponseEntity(foo, headers, HttpStatus.CREATED); + return entity; + } + + @RequestMapping(method = RequestMethod.HEAD, value = "/foos") + @ResponseStatus(HttpStatus.OK) + @ResponseBody + public Foo headFoo() { + return new Foo(1, randomAlphabetic(4)); + } + + @RequestMapping(method = RequestMethod.POST, value = "/foos/new") + @ResponseStatus(HttpStatus.CREATED) + @ResponseBody + public Foo createFoo(@RequestBody final Foo foo) { + fooRepository.put(foo.getId(), foo); + return foo; + } + + @RequestMapping(method = RequestMethod.DELETE, value = "/foos/{id}") + @ResponseStatus(HttpStatus.OK) + @ResponseBody + public long deleteFoo(@PathVariable final long id) { + fooRepository.remove(id); + return id; + } + + @RequestMapping(method = RequestMethod.POST, value = "/foos/form") + @ResponseStatus(HttpStatus.CREATED) + @ResponseBody + public String submitFoo(@RequestParam("id") String id) { + return id; + } + +} diff --git a/spring-resttemplate/src/main/java/org/baeldung/resttemplate/configuration/SpringConfig.java b/spring-resttemplate/src/main/java/org/baeldung/resttemplate/configuration/SpringConfig.java index 4e121185b1..966d5bcaa1 100644 --- a/spring-resttemplate/src/main/java/org/baeldung/resttemplate/configuration/SpringConfig.java +++ b/spring-resttemplate/src/main/java/org/baeldung/resttemplate/configuration/SpringConfig.java @@ -7,6 +7,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.DependsOn; +import org.springframework.web.client.RestTemplate; @Configuration @EnableAutoConfiguration @@ -25,4 +26,8 @@ public class SpringConfig { return new RestTemplateBuilder(customRestTemplateCustomizer()); } + @Bean + public RestTemplate restTemplate() { + return new RestTemplate(); + } } diff --git a/spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/controller/PersonAPI.java b/spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/controller/PersonAPI.java new file mode 100644 index 0000000000..b1b56ec2f3 --- /dev/null +++ b/spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/controller/PersonAPI.java @@ -0,0 +1,38 @@ +package org.baeldung.resttemplate.web.controller; + +import javax.servlet.http.HttpServletResponse; + +import org.baeldung.resttemplate.web.dto.Person; +import org.baeldung.resttemplate.web.service.PersonService; +import org.springframework.beans.factory.annotation.Autowired; +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.RestController; +import org.springframework.web.servlet.support.ServletUriComponentsBuilder; + +@RestController +public class PersonAPI { + + @Autowired + private PersonService personService; + + @GetMapping("/") + public String home() { + return "Spring boot is working!"; + } + + @PostMapping(value = "/createPerson", consumes = "application/json", produces = "application/json") + public Person createPerson(@RequestBody Person person) { + return personService.saveUpdatePerson(person); + } + + @PostMapping(value = "/updatePerson", consumes = "application/json", produces = "application/json") + public Person updatePerson(@RequestBody Person person, HttpServletResponse response) { + response.setHeader("Location", ServletUriComponentsBuilder.fromCurrentContextPath() + .path("/findPerson/" + person.getId()) + .toUriString()); + return personService.saveUpdatePerson(person); + } + +} \ No newline at end of file diff --git a/spring-resttemplate/src/main/java/org/baeldung/web/dto/Foo.java b/spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/dto/Foo.java similarity index 93% rename from spring-resttemplate/src/main/java/org/baeldung/web/dto/Foo.java rename to spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/dto/Foo.java index 240b368b50..ed0a42c429 100644 --- a/spring-resttemplate/src/main/java/org/baeldung/web/dto/Foo.java +++ b/spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/dto/Foo.java @@ -1,4 +1,4 @@ -package org.baeldung.web.dto; +package org.baeldung.resttemplate.web.dto; import com.thoughtworks.xstream.annotations.XStreamAlias; diff --git a/spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/dto/Person.java b/spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/dto/Person.java new file mode 100644 index 0000000000..4b7679638f --- /dev/null +++ b/spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/dto/Person.java @@ -0,0 +1,32 @@ +package org.baeldung.resttemplate.web.dto; + +public class Person { + private Integer id; + private String name; + + public Person() { + + } + + public Person(Integer id, String name) { + this.id = id; + this.name = name; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + +} diff --git a/spring-resttemplate/src/main/java/org/baeldung/web/exception/NotFoundException.java b/spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/exception/NotFoundException.java similarity index 55% rename from spring-resttemplate/src/main/java/org/baeldung/web/exception/NotFoundException.java rename to spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/exception/NotFoundException.java index 5b4d80a659..3e606e9314 100644 --- a/spring-resttemplate/src/main/java/org/baeldung/web/exception/NotFoundException.java +++ b/spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/exception/NotFoundException.java @@ -1,4 +1,4 @@ -package org.baeldung.web.exception; +package org.baeldung.resttemplate.web.exception; public class NotFoundException extends RuntimeException { } diff --git a/spring-resttemplate/src/main/java/org/baeldung/web/handler/RestTemplateResponseErrorHandler.java b/spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/handler/RestTemplateResponseErrorHandler.java similarity index 82% rename from spring-resttemplate/src/main/java/org/baeldung/web/handler/RestTemplateResponseErrorHandler.java rename to spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/handler/RestTemplateResponseErrorHandler.java index b1b87e89a5..214de38746 100644 --- a/spring-resttemplate/src/main/java/org/baeldung/web/handler/RestTemplateResponseErrorHandler.java +++ b/spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/handler/RestTemplateResponseErrorHandler.java @@ -1,13 +1,14 @@ -package org.baeldung.web.handler; +package org.baeldung.resttemplate.web.handler; -import org.baeldung.web.exception.NotFoundException; +import java.io.IOException; + +import org.baeldung.resttemplate.web.exception.NotFoundException; import org.springframework.http.HttpStatus; import org.springframework.http.client.ClientHttpResponse; import org.springframework.stereotype.Component; +import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.ResponseErrorHandler; -import java.io.IOException; - @Component public class RestTemplateResponseErrorHandler implements ResponseErrorHandler { @@ -31,6 +32,7 @@ public class RestTemplateResponseErrorHandler .getStatusCode() .series() == HttpStatus.Series.SERVER_ERROR) { //Handle SERVER_ERROR + throw new HttpClientErrorException(httpResponse.getStatusCode()); } else if (httpResponse .getStatusCode() .series() == HttpStatus.Series.CLIENT_ERROR) { diff --git a/spring-resttemplate/src/main/java/org/baeldung/web/model/Bar.java b/spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/model/Bar.java similarity index 87% rename from spring-resttemplate/src/main/java/org/baeldung/web/model/Bar.java rename to spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/model/Bar.java index 474e2070a5..cf5279697f 100644 --- a/spring-resttemplate/src/main/java/org/baeldung/web/model/Bar.java +++ b/spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/model/Bar.java @@ -1,4 +1,4 @@ -package org.baeldung.web.model; +package org.baeldung.resttemplate.web.model; public class Bar { private String id; diff --git a/spring-resttemplate/src/main/java/org/baeldung/web/model/Employee.java b/spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/model/Employee.java similarity index 95% rename from spring-resttemplate/src/main/java/org/baeldung/web/model/Employee.java rename to spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/model/Employee.java index 7cab4a0430..a9b84a77b4 100644 --- a/spring-resttemplate/src/main/java/org/baeldung/web/model/Employee.java +++ b/spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/model/Employee.java @@ -1,4 +1,4 @@ -package org.baeldung.web.model; +package org.baeldung.resttemplate.web.model; import java.util.Date; import java.util.Objects; diff --git a/spring-resttemplate/src/main/java/org/baeldung/web/service/BarConsumerService.java b/spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/service/BarConsumerService.java similarity index 78% rename from spring-resttemplate/src/main/java/org/baeldung/web/service/BarConsumerService.java rename to spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/service/BarConsumerService.java index 0bf24bd480..54a66ea591 100644 --- a/spring-resttemplate/src/main/java/org/baeldung/web/service/BarConsumerService.java +++ b/spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/service/BarConsumerService.java @@ -1,7 +1,7 @@ -package org.baeldung.web.service; +package org.baeldung.resttemplate.web.service; -import org.baeldung.web.handler.RestTemplateResponseErrorHandler; -import org.baeldung.web.model.Bar; +import org.baeldung.resttemplate.web.handler.RestTemplateResponseErrorHandler; +import org.baeldung.resttemplate.web.model.Bar; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.web.client.RestTemplateBuilder; import org.springframework.stereotype.Service; diff --git a/spring-resttemplate/src/main/java/org/baeldung/web/service/EmployeeService.java b/spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/service/EmployeeService.java similarity index 89% rename from spring-resttemplate/src/main/java/org/baeldung/web/service/EmployeeService.java rename to spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/service/EmployeeService.java index 91614e90ad..c6562fbc94 100644 --- a/spring-resttemplate/src/main/java/org/baeldung/web/service/EmployeeService.java +++ b/spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/service/EmployeeService.java @@ -1,6 +1,6 @@ -package org.baeldung.web.service; +package org.baeldung.resttemplate.web.service; -import org.baeldung.web.model.Employee; +import org.baeldung.resttemplate.web.model.Employee; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; diff --git a/spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/service/PersonService.java b/spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/service/PersonService.java new file mode 100644 index 0000000000..c5ad39e101 --- /dev/null +++ b/spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/service/PersonService.java @@ -0,0 +1,10 @@ +package org.baeldung.resttemplate.web.service; + +import org.baeldung.resttemplate.web.dto.Person; + +public interface PersonService { + + public Person saveUpdatePerson(Person person); + + public Person findPersonById(Integer id); +} \ No newline at end of file diff --git a/spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/service/PersonServiceImpl.java b/spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/service/PersonServiceImpl.java new file mode 100644 index 0000000000..658e0fade0 --- /dev/null +++ b/spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/service/PersonServiceImpl.java @@ -0,0 +1,19 @@ +package org.baeldung.resttemplate.web.service; + +import org.baeldung.resttemplate.web.dto.Person; +import org.springframework.stereotype.Component; + +@Component +public class PersonServiceImpl implements PersonService { + + @Override + public Person saveUpdatePerson(Person person) { + return person; + } + + @Override + public Person findPersonById(Integer id) { + return new Person(id, "John"); + } + +} diff --git a/spring-resttemplate/src/test/java/org/baeldung/SpringContextIntegrationTest.java b/spring-resttemplate/src/test/java/org/baeldung/SpringContextIntegrationTest.java index 3a5a20cfeb..3c762b894b 100644 --- a/spring-resttemplate/src/test/java/org/baeldung/SpringContextIntegrationTest.java +++ b/spring-resttemplate/src/test/java/org/baeldung/SpringContextIntegrationTest.java @@ -1,6 +1,6 @@ package org.baeldung; -import org.baeldung.resttemplate.configuration.RestTemplateConfigurationApplication; +import org.baeldung.resttemplate.RestTemplateConfigurationApplication; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; diff --git a/spring-resttemplate/src/test/java/org/baeldung/client/RestTemplateBasicLiveTest.java b/spring-resttemplate/src/test/java/org/baeldung/client/RestTemplateBasicLiveTest.java index 143aa079d5..a54c124d5f 100644 --- a/spring-resttemplate/src/test/java/org/baeldung/client/RestTemplateBasicLiveTest.java +++ b/spring-resttemplate/src/test/java/org/baeldung/client/RestTemplateBasicLiveTest.java @@ -14,7 +14,8 @@ import java.net.URI; import java.util.Arrays; import java.util.Set; -import org.baeldung.web.dto.Foo; +import org.baeldung.resttemplate.web.dto.Foo; +import org.baeldung.resttemplate.web.handler.RestTemplateResponseErrorHandler; import org.junit.Before; import org.junit.Test; import org.springframework.http.HttpEntity; @@ -34,6 +35,7 @@ import org.springframework.web.client.RestTemplate; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.dataformat.xml.XmlMapper; import com.google.common.base.Charsets; public class RestTemplateBasicLiveTest { @@ -44,6 +46,7 @@ public class RestTemplateBasicLiveTest { @Before public void beforeTest() { restTemplate = new RestTemplate(); + restTemplate.setErrorHandler(new RestTemplateResponseErrorHandler()); // restTemplate.setMessageConverters(Arrays.asList(new MappingJackson2HttpMessageConverter())); } @@ -61,7 +64,7 @@ public class RestTemplateBasicLiveTest { final RestTemplate template = new RestTemplate(); final ResponseEntity response = template.getForEntity(fooResourceUrl + "/1", String.class); - final ObjectMapper mapper = new ObjectMapper(); + final ObjectMapper mapper = new XmlMapper(); final JsonNode root = mapper.readTree(response.getBody()); final JsonNode name = root.path("name"); assertThat(name.asText(), notNullValue()); @@ -97,7 +100,7 @@ public class RestTemplateBasicLiveTest { @Test public void givenFooService_whenPostForLocation_thenCreatedLocationIsReturned() { final HttpEntity request = new HttpEntity<>(new Foo("bar")); - final URI location = restTemplate.postForLocation(fooResourceUrl, request); + final URI location = restTemplate.postForLocation(fooResourceUrl, request, Foo.class); assertThat(location, notNullValue()); } @@ -211,7 +214,7 @@ public class RestTemplateBasicLiveTest { restTemplate.getForEntity(entityUrl, Foo.class); fail(); } catch (final HttpClientErrorException ex) { - assertThat(ex.getStatusCode(), is(HttpStatus.NOT_FOUND)); + assertThat(ex.getStatusCode(), is(HttpStatus.INTERNAL_SERVER_ERROR)); } } @@ -221,7 +224,7 @@ public class RestTemplateBasicLiveTest { headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); MultiValueMap map= new LinkedMultiValueMap<>(); - map.add("id", "1"); + map.add("id", "10"); HttpEntity> request = new HttpEntity<>(map, headers); @@ -230,7 +233,7 @@ public class RestTemplateBasicLiveTest { assertThat(response.getStatusCode(), is(HttpStatus.CREATED)); final String fooResponse = response.getBody(); assertThat(fooResponse, notNullValue()); - assertThat(fooResponse, is("1")); + assertThat(fooResponse, is("10")); } private HttpHeaders prepareBasicAuthHeaders() { diff --git a/spring-resttemplate/src/test/java/org/baeldung/client/TestRestTemplateBasicLiveTest.java b/spring-resttemplate/src/test/java/org/baeldung/client/TestRestTemplateBasicLiveTest.java index e303c75a28..967c4a6188 100644 --- a/spring-resttemplate/src/test/java/org/baeldung/client/TestRestTemplateBasicLiveTest.java +++ b/spring-resttemplate/src/test/java/org/baeldung/client/TestRestTemplateBasicLiveTest.java @@ -4,6 +4,7 @@ import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertTrue; +import org.baeldung.resttemplate.web.dto.Foo; import org.junit.Before; import org.junit.Test; import org.springframework.boot.test.web.client.TestRestTemplate; @@ -34,7 +35,7 @@ public class TestRestTemplateBasicLiveTest { @Test public void givenTestRestTemplate_whenSendGetForEntity_thenStatusOk() { TestRestTemplate testRestTemplate = new TestRestTemplate(); - ResponseEntity response = testRestTemplate.getForEntity(FOO_RESOURCE_URL + "/1", String.class); + ResponseEntity response = testRestTemplate.getForEntity(FOO_RESOURCE_URL + "/1", Foo.class); assertThat(response.getStatusCode(), equalTo(HttpStatus.OK)); } @@ -43,7 +44,7 @@ public class TestRestTemplateBasicLiveTest { RestTemplateBuilder restTemplateBuilder = new RestTemplateBuilder(); restTemplateBuilder.configure(restTemplate); TestRestTemplate testRestTemplate = new TestRestTemplate(restTemplateBuilder); - ResponseEntity response = testRestTemplate.getForEntity(FOO_RESOURCE_URL + "/1", String.class); + ResponseEntity response = testRestTemplate.getForEntity(FOO_RESOURCE_URL + "/1", Foo.class); assertThat(response.getStatusCode(), equalTo(HttpStatus.OK)); } @@ -52,7 +53,7 @@ public class TestRestTemplateBasicLiveTest { RestTemplateBuilder restTemplateBuilder = new RestTemplateBuilder(); restTemplateBuilder.build(); TestRestTemplate testRestTemplate = new TestRestTemplate(restTemplateBuilder); - ResponseEntity response = testRestTemplate.getForEntity(FOO_RESOURCE_URL + "/1", String.class); + ResponseEntity response = testRestTemplate.getForEntity(FOO_RESOURCE_URL + "/1", Foo.class); assertThat(response.getStatusCode(), equalTo(HttpStatus.OK)); } diff --git a/spring-resttemplate/src/test/java/org/baeldung/resttemplate/PersonAPILiveTest.java b/spring-resttemplate/src/test/java/org/baeldung/resttemplate/PersonAPILiveTest.java new file mode 100644 index 0000000000..de18f6db09 --- /dev/null +++ b/spring-resttemplate/src/test/java/org/baeldung/resttemplate/PersonAPILiveTest.java @@ -0,0 +1,96 @@ +package org.baeldung.resttemplate; + +import static org.junit.Assert.assertNotNull; + +import java.io.IOException; +import java.net.URI; + +import org.baeldung.resttemplate.web.dto.Person; +import org.json.JSONException; +import org.json.JSONObject; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.web.client.RestTemplate; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = RestTemplateConfigurationApplication.class) +public class PersonAPILiveTest { + + private static String createPersonUrl; + private static String updatePersonUrl; + + private static RestTemplate restTemplate; + + private static HttpHeaders headers; + + private final ObjectMapper objectMapper = new ObjectMapper(); + + private static JSONObject personJsonObject; + + @BeforeClass + public static void runBeforeAllTestMethods() throws JSONException { + createPersonUrl = "http://localhost:8082/spring-rest/createPerson"; + updatePersonUrl = "http://localhost:8082/spring-rest/updatePerson"; + + restTemplate = new RestTemplate(); + + headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + personJsonObject = new JSONObject(); + personJsonObject.put("id", 1); + personJsonObject.put("name", "John"); + } + + @Test + public void givenDataIsJson_whenDataIsPostedByPostForObject_thenResponseBodyIsNotNull() throws IOException { + HttpEntity request = new HttpEntity(personJsonObject.toString(), headers); + String personResultAsJsonStr = restTemplate.postForObject(createPersonUrl, request, String.class); + JsonNode root = objectMapper.readTree(personResultAsJsonStr); + + Person person = restTemplate.postForObject(createPersonUrl, request, Person.class); + + assertNotNull(personResultAsJsonStr); + assertNotNull(root); + assertNotNull(root.path("name") + .asText()); + + assertNotNull(person); + assertNotNull(person.getName()); + } + + @Test + public void givenDataIsJson_whenDataIsPostedByPostForEntity_thenResponseBodyIsNotNull() throws IOException { + HttpEntity request = new HttpEntity(personJsonObject.toString(), headers); + ResponseEntity responseEntityStr = restTemplate.postForEntity(createPersonUrl, request, String.class); + JsonNode root = objectMapper.readTree(responseEntityStr.getBody()); + + ResponseEntity responseEntityPerson = restTemplate.postForEntity(createPersonUrl, request, Person.class); + + assertNotNull(responseEntityStr.getBody()); + assertNotNull(root.path("name") + .asText()); + + assertNotNull(responseEntityPerson.getBody()); + assertNotNull(responseEntityPerson.getBody() + .getName()); + } + + @Test + public void givenDataIsJson_whenDataIsPostedByPostForLocation_thenResponseBodyIsTheLocationHeader() throws JsonProcessingException { + HttpEntity request = new HttpEntity(personJsonObject.toString(), headers); + URI locationHeader = restTemplate.postForLocation(updatePersonUrl, request); + + assertNotNull(locationHeader); + } +} \ No newline at end of file diff --git a/spring-resttemplate/src/test/java/org/baeldung/web/handler/RestTemplateResponseErrorHandlerIntegrationTest.java b/spring-resttemplate/src/test/java/org/baeldung/web/handler/RestTemplateResponseErrorHandlerIntegrationTest.java index 2dfa81f441..60069cea71 100644 --- a/spring-resttemplate/src/test/java/org/baeldung/web/handler/RestTemplateResponseErrorHandlerIntegrationTest.java +++ b/spring-resttemplate/src/test/java/org/baeldung/web/handler/RestTemplateResponseErrorHandlerIntegrationTest.java @@ -1,7 +1,8 @@ package org.baeldung.web.handler; -import org.baeldung.web.exception.NotFoundException; -import org.baeldung.web.model.Bar; +import org.baeldung.resttemplate.web.exception.NotFoundException; +import org.baeldung.resttemplate.web.handler.RestTemplateResponseErrorHandler; +import org.baeldung.resttemplate.web.model.Bar; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/spring-resttemplate/src/test/java/org/baeldung/web/service/EmployeeServiceMockRestServiceServerUnitTest.java b/spring-resttemplate/src/test/java/org/baeldung/web/service/EmployeeServiceMockRestServiceServerUnitTest.java index a45af318f1..f93ba71666 100644 --- a/spring-resttemplate/src/test/java/org/baeldung/web/service/EmployeeServiceMockRestServiceServerUnitTest.java +++ b/spring-resttemplate/src/test/java/org/baeldung/web/service/EmployeeServiceMockRestServiceServerUnitTest.java @@ -7,7 +7,8 @@ import static org.springframework.test.web.client.response.MockRestResponseCreat import java.net.URI; import org.baeldung.SpringTestConfig; -import org.baeldung.web.model.Employee; +import org.baeldung.resttemplate.web.model.Employee; +import org.baeldung.resttemplate.web.service.EmployeeService; import org.junit.Assert; import org.junit.Before; import org.junit.Test; diff --git a/spring-resttemplate/src/test/java/org/baeldung/web/service/EmployeeServiceUnitTest.java b/spring-resttemplate/src/test/java/org/baeldung/web/service/EmployeeServiceUnitTest.java index 23cd9a8fd2..f4b391573a 100644 --- a/spring-resttemplate/src/test/java/org/baeldung/web/service/EmployeeServiceUnitTest.java +++ b/spring-resttemplate/src/test/java/org/baeldung/web/service/EmployeeServiceUnitTest.java @@ -1,6 +1,7 @@ package org.baeldung.web.service; -import org.baeldung.web.model.Employee; +import org.baeldung.resttemplate.web.model.Employee; +import org.baeldung.resttemplate.web.service.EmployeeService; import org.junit.Assert; import org.junit.Before; import org.junit.Test; diff --git a/spring-security-kerberos/README.md b/spring-security-kerberos/README.md new file mode 100644 index 0000000000..0338c2058c --- /dev/null +++ b/spring-security-kerberos/README.md @@ -0,0 +1,10 @@ +## @PreFilter and @PostFilter annotations + +### Build the Project ### + +``` +mvn clean install +``` + +### Relevant Articles: +- [Spring Security – Kerberos](http://www.baeldung.com/xxxxxx) diff --git a/spring-security-kerberos/pom.xml b/spring-security-kerberos/pom.xml new file mode 100644 index 0000000000..35c4ba4926 --- /dev/null +++ b/spring-security-kerberos/pom.xml @@ -0,0 +1,61 @@ + + 4.0.0 + com.baeldung + spring-security-kerberos + 0.1-SNAPSHOT + spring-security-kerberos + war + + parent-boot-1 + com.baeldung + 0.0.1-SNAPSHOT + ../parent-boot-1 + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-security + + + + org.springframework.security.kerberos + spring-security-kerberos-core + 1.0.1.RELEASE + + + org.springframework.security.kerberos + spring-security-kerberos-web + 1.0.1.RELEASE + + + org.springframework.security.kerberos + spring-security-kerberos-client + 1.0.1.RELEASE + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.security + spring-security-test + test + + + + + + org.apache.maven.plugins + maven-war-plugin + + + + diff --git a/spring-security-kerberos/src/main/java/org/baeldung/Application.java b/spring-security-kerberos/src/main/java/org/baeldung/Application.java new file mode 100644 index 0000000000..39c2b51356 --- /dev/null +++ b/spring-security-kerberos/src/main/java/org/baeldung/Application.java @@ -0,0 +1,13 @@ +package org.baeldung; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} diff --git a/spring-security-kerberos/src/main/java/org/baeldung/config/WebSecurityConfig.java b/spring-security-kerberos/src/main/java/org/baeldung/config/WebSecurityConfig.java new file mode 100644 index 0000000000..49a1cf0a8e --- /dev/null +++ b/spring-security-kerberos/src/main/java/org/baeldung/config/WebSecurityConfig.java @@ -0,0 +1,87 @@ +package org.baeldung.config; + +import org.baeldung.security.DummyUserDetailsService; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.FileSystemResource; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.kerberos.authentication.KerberosAuthenticationProvider; +import org.springframework.security.kerberos.authentication.KerberosServiceAuthenticationProvider; +import org.springframework.security.kerberos.authentication.sun.SunJaasKerberosClient; +import org.springframework.security.kerberos.authentication.sun.SunJaasKerberosTicketValidator; +import org.springframework.security.kerberos.web.authentication.SpnegoAuthenticationProcessingFilter; +import org.springframework.security.kerberos.web.authentication.SpnegoEntryPoint; +import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; + +@Configuration +public class WebSecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http.authorizeRequests() + .anyRequest() + .authenticated() + .and() + .addFilterBefore(spnegoAuthenticationProcessingFilter(authenticationManagerBean()), BasicAuthenticationFilter.class); + } + + @Override + @Bean + public AuthenticationManager authenticationManagerBean() throws Exception { + return super.authenticationManagerBean(); + } + + @Override + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + auth.authenticationProvider(kerberosAuthenticationProvider()) + .authenticationProvider(kerberosServiceAuthenticationProvider()); + } + + @Bean + public KerberosAuthenticationProvider kerberosAuthenticationProvider() { + KerberosAuthenticationProvider provider = new KerberosAuthenticationProvider(); + SunJaasKerberosClient client = new SunJaasKerberosClient(); + client.setDebug(true); + provider.setKerberosClient(client); + provider.setUserDetailsService(dummyUserDetailsService()); + return provider; + } + + @Bean + public SpnegoEntryPoint spnegoEntryPoint() { + return new SpnegoEntryPoint("/login"); + } + + @Bean + public SpnegoAuthenticationProcessingFilter spnegoAuthenticationProcessingFilter(AuthenticationManager authenticationManager) { + SpnegoAuthenticationProcessingFilter filter = new SpnegoAuthenticationProcessingFilter(); + filter.setAuthenticationManager(authenticationManager); + return filter; + } + + @Bean + public KerberosServiceAuthenticationProvider kerberosServiceAuthenticationProvider() { + KerberosServiceAuthenticationProvider provider = new KerberosServiceAuthenticationProvider(); + provider.setTicketValidator(sunJaasKerberosTicketValidator()); + provider.setUserDetailsService(dummyUserDetailsService()); + return provider; + } + + @Bean + public SunJaasKerberosTicketValidator sunJaasKerberosTicketValidator() { + SunJaasKerberosTicketValidator ticketValidator = new SunJaasKerberosTicketValidator(); + ticketValidator.setServicePrincipal("HTTP/demo.kerberos.bealdung.com@baeldung.com"); + ticketValidator.setKeyTabLocation(new FileSystemResource("baeldung.keytab")); + ticketValidator.setDebug(true); + return ticketValidator; + } + + @Bean + public DummyUserDetailsService dummyUserDetailsService() { + return new DummyUserDetailsService(); + } + +} \ No newline at end of file diff --git a/spring-security-kerberos/src/main/java/org/baeldung/security/DummyUserDetailsService.java b/spring-security-kerberos/src/main/java/org/baeldung/security/DummyUserDetailsService.java new file mode 100644 index 0000000000..10d71fca8f --- /dev/null +++ b/spring-security-kerberos/src/main/java/org/baeldung/security/DummyUserDetailsService.java @@ -0,0 +1,16 @@ +package org.baeldung.security; + +import org.springframework.security.core.authority.AuthorityUtils; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; + +public class DummyUserDetailsService implements UserDetailsService { + + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + return new User(username, "notUsed", true, true, true, true, AuthorityUtils.createAuthorityList("ROLE_USER")); + } + +} \ No newline at end of file diff --git a/spring-security-mvc-custom/pom.xml b/spring-security-mvc-custom/pom.xml index b4239fb2b8..7c60a8e18a 100644 --- a/spring-security-mvc-custom/pom.xml +++ b/spring-security-mvc-custom/pom.xml @@ -21,17 +21,17 @@ org.springframework.security spring-security-web - ${org.springframework.security.version} + ${spring-security.version} org.springframework.security spring-security-config - ${org.springframework.security.version} + ${spring-security.version} org.springframework.security spring-security-taglibs - ${org.springframework.security.version} + ${spring-security.version} @@ -144,7 +144,7 @@ org.springframework.security spring-security-test - ${org.springframework.security.version} + ${spring-security.version} test @@ -192,9 +192,6 @@
- - 5.0.6.RELEASE - 3.1.0 1.2 diff --git a/spring-security-mvc-digest-auth/src/test/java/org/baeldung/client/RawClientLiveTest.java b/spring-security-mvc-digest-auth/src/test/java/org/baeldung/client/RawClientLiveTest.java index 90c2a29968..e8dcf82ebc 100644 --- a/spring-security-mvc-digest-auth/src/test/java/org/baeldung/client/RawClientLiveTest.java +++ b/spring-security-mvc-digest-auth/src/test/java/org/baeldung/client/RawClientLiveTest.java @@ -1,7 +1,8 @@ package org.baeldung.client; +import java.io.IOException; + import org.apache.http.HttpResponse; -import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; @@ -12,10 +13,6 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.support.AnnotationConfigContextLoader; -import java.io.IOException; -import java.util.Timer; -import java.util.TimerTask; - @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = {ClientConfig.class}, loader = AnnotationConfigContextLoader.class) public class RawClientLiveTest { @@ -25,22 +22,7 @@ public class RawClientLiveTest { @Test public void whenSecuredRestApiIsConsumed_then200OK() throws IOException { CloseableHttpClient httpClient = HttpClientBuilder.create().build(); - - int timeout = 20; // seconds - RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(timeout) - .setConnectTimeout(timeout).setSocketTimeout(timeout).build(); HttpGet getMethod = new HttpGet("http://localhost:8082/spring-security-rest-basic-auth/api/bars/1"); - getMethod.setConfig(requestConfig); - - int hardTimeout = 5; // seconds - TimerTask task = new TimerTask() { - @Override - public void run() { - getMethod.abort(); - } - }; - new Timer(true).schedule(task, hardTimeout * 1000); - HttpResponse response = httpClient.execute(getMethod); System.out.println("HTTP Status of response: " + response.getStatusLine().getStatusCode()); } diff --git a/spring-security-mvc-jsonview/pom.xml b/spring-security-mvc-jsonview/pom.xml index 7f1129128f..8fa7b4ffb5 100644 --- a/spring-security-mvc-jsonview/pom.xml +++ b/spring-security-mvc-jsonview/pom.xml @@ -20,17 +20,17 @@ com.fasterxml.jackson.core jackson-core - 2.9.7 + ${jackson.version} com.fasterxml.jackson.core jackson-annotations - 2.9.7 + ${jackson.version} com.fasterxml.jackson.core jackson-databind - 2.9.7 + ${jackson.version} @@ -38,17 +38,17 @@ org.springframework.security spring-security-web - ${org.springframework.security.version} + ${spring-security.version} org.springframework.security spring-security-config - ${org.springframework.security.version} + ${spring-security.version} org.springframework.security spring-security-taglibs - ${org.springframework.security.version} + ${spring-security.version} @@ -133,13 +133,13 @@ org.springframework.security spring-security-test - ${org.springframework.security.version} + ${spring-security.version} test com.jayway.jsonpath json-path - 2.4.0 + ${json-path.version} test @@ -206,9 +206,6 @@ - - 5.0.5.RELEASE - 3.1.0 1.2 @@ -216,6 +213,7 @@ 2.6 1.6.1 + 2.4.0 diff --git a/spring-security-mvc-ldap/README.md b/spring-security-mvc-ldap/README.md index fe6a667c40..6f03143183 100644 --- a/spring-security-mvc-ldap/README.md +++ b/spring-security-mvc-ldap/README.md @@ -5,8 +5,7 @@ The "Learn Spring Security" Classes: http://github.learnspringsecurity.com ### Relevant Article: -- [Spring Security - security none, filters none, access permitAll](http://www.baeldung.com/security-none-filters-none-access-permitAll) -- [Spring Security Basic Authentication](http://www.baeldung.com/spring-security-basic-authentication) +- [Spring Security – security none, filters none, access permitAll](http://www.baeldung.com/security-none-filters-none-access-permitAll) - [Intro to Spring Security LDAP](http://www.baeldung.com/spring-security-ldap) ### Notes diff --git a/spring-security-mvc-login/README.md b/spring-security-mvc-login/README.md index c19cbc87a5..983d949cb8 100644 --- a/spring-security-mvc-login/README.md +++ b/spring-security-mvc-login/README.md @@ -10,7 +10,7 @@ The "Learn Spring Security" Classes: http://github.learnspringsecurity.com - [Spring Security Logout](http://www.baeldung.com/spring-security-logout) - [Spring Security Expressions – hasRole Example](http://www.baeldung.com/spring-security-expressions-basic) - [Spring HTTP/HTTPS Channel Security](http://www.baeldung.com/spring-channel-security-https) -- [Spring Security - Customize the 403 Forbidden/Access Denied Page](http://www.baeldung.com/spring-security-custom-access-denied-page) +- [Spring Security – Customize the 403 Forbidden/Access Denied Page](http://www.baeldung.com/spring-security-custom-access-denied-page) - [Spring Security – Redirect to the Previous URL After Login](http://www.baeldung.com/spring-security-redirect-login) - [Spring Security Custom AuthenticationFailureHandler](http://www.baeldung.com/spring-security-custom-authentication-failure-handler) diff --git a/spring-security-mvc-login/pom.xml b/spring-security-mvc-login/pom.xml index bbdff6fc2f..048297bbd4 100644 --- a/spring-security-mvc-login/pom.xml +++ b/spring-security-mvc-login/pom.xml @@ -21,17 +21,17 @@ org.springframework.security spring-security-web - ${org.springframework.security.version} + ${spring-security.version} org.springframework.security spring-security-config - ${org.springframework.security.version} + ${spring-security.version} org.springframework.security spring-security-taglibs - ${org.springframework.security.version} + ${spring-security.version} @@ -116,7 +116,7 @@ org.springframework.security spring-security-test - ${org.springframework.security.version} + ${spring-security.version} test @@ -175,7 +175,6 @@ - 5.0.5.RELEASE 3.1.0 diff --git a/spring-security-mvc-persisted-remember-me/README.md b/spring-security-mvc-persisted-remember-me/README.md index e505537be1..db2ae890f9 100644 --- a/spring-security-mvc-persisted-remember-me/README.md +++ b/spring-security-mvc-persisted-remember-me/README.md @@ -6,7 +6,7 @@ The "Learn Spring Security" Classes: http://github.learnspringsecurity.com ### Relevant Articles: -- [Spring Security Persisted Remember Me](http://www.baeldung.com/spring-security-persistent-remember-me) +- [Spring Security – Persistent Remember Me](http://www.baeldung.com/spring-security-persistent-remember-me) ### Build the Project ``` diff --git a/spring-security-mvc-persisted-remember-me/pom.xml b/spring-security-mvc-persisted-remember-me/pom.xml index c65b7a30cb..d10565255d 100644 --- a/spring-security-mvc-persisted-remember-me/pom.xml +++ b/spring-security-mvc-persisted-remember-me/pom.xml @@ -137,7 +137,7 @@ org.springframework.boot spring-boot-starter-test - 1.5.10.RELEASE + ${spring-boot.version} test @@ -211,7 +211,7 @@ 2.6 1.6.1 - + 1.5.10.RELEASE \ No newline at end of file diff --git a/spring-security-mvc-socket/src/main/java/com/baeldung/springsockets/config/WebSocketMessageBrokerConfig.java b/spring-security-mvc-socket/src/main/java/com/baeldung/springsockets/config/WebSocketMessageBrokerConfig.java new file mode 100644 index 0000000000..f1fb6549ed --- /dev/null +++ b/spring-security-mvc-socket/src/main/java/com/baeldung/springsockets/config/WebSocketMessageBrokerConfig.java @@ -0,0 +1,67 @@ +package com.baeldung.springsockets.config; + +import java.util.List; + +import org.springframework.context.annotation.Configuration; +import org.springframework.messaging.converter.MessageConverter; +import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver; +import org.springframework.messaging.handler.invocation.HandlerMethodReturnValueHandler; +import org.springframework.messaging.simp.config.ChannelRegistration; +import org.springframework.messaging.simp.config.MessageBrokerRegistry; +import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; +import org.springframework.web.socket.config.annotation.StompEndpointRegistry; +import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer; +import org.springframework.web.socket.config.annotation.WebSocketTransportRegistration; + +@Configuration +@EnableWebSocketMessageBroker +public class WebSocketMessageBrokerConfig implements WebSocketMessageBrokerConfigurer { + + @Override + public void registerStompEndpoints(StompEndpointRegistry registry) { + registry.addEndpoint("/ws"); + } + + @Override + public void configureMessageBroker(MessageBrokerRegistry config) { + config.setApplicationDestinationPrefixes("/app"); + config.enableSimpleBroker("/topic"); + } + + @Override + public void configureWebSocketTransport(WebSocketTransportRegistration registry) { + // TODO Auto-generated method stub + + } + + @Override + public void configureClientInboundChannel(ChannelRegistration registration) { + // TODO Auto-generated method stub + + } + + @Override + public void configureClientOutboundChannel(ChannelRegistration registration) { + // TODO Auto-generated method stub + + } + + @Override + public void addArgumentResolvers(List argumentResolvers) { + // TODO Auto-generated method stub + + } + + @Override + public void addReturnValueHandlers(List returnValueHandlers) { + // TODO Auto-generated method stub + + } + + @Override + public boolean configureMessageConverters(List messageConverters) { + // TODO Auto-generated method stub + return false; + } + +} \ No newline at end of file diff --git a/spring-security-mvc-socket/src/main/java/com/baeldung/springsockets/controllers/RestAPIController.java b/spring-security-mvc-socket/src/main/java/com/baeldung/springsockets/controllers/RestAPIController.java new file mode 100644 index 0000000000..a8d3d5ffae --- /dev/null +++ b/spring-security-mvc-socket/src/main/java/com/baeldung/springsockets/controllers/RestAPIController.java @@ -0,0 +1,17 @@ +package com.baeldung.springsockets.controllers; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping(path = "/rest") +public class RestAPIController { + + @GetMapping(path = "/{name}", produces = "application/json") + public String getGreeting(@PathVariable("name") String name) { + return "{\"greeting\" : \"Hello, " + name + "!\"}"; + } + +} diff --git a/spring-security-mvc-socket/src/main/java/com/baeldung/springsockets/controllers/WebSocketController.java b/spring-security-mvc-socket/src/main/java/com/baeldung/springsockets/controllers/WebSocketController.java new file mode 100644 index 0000000000..26a67e4236 --- /dev/null +++ b/spring-security-mvc-socket/src/main/java/com/baeldung/springsockets/controllers/WebSocketController.java @@ -0,0 +1,20 @@ +package com.baeldung.springsockets.controllers; + +import org.springframework.messaging.handler.annotation.MessageMapping; +import org.springframework.messaging.handler.annotation.SendTo; +import org.springframework.stereotype.Controller; +import org.springframework.web.util.HtmlUtils; + +import com.baeldung.springsockets.models.Greeting; +import com.baeldung.springsockets.models.Message; + +@Controller +public class WebSocketController { + + @MessageMapping("/hello") + @SendTo("/topic/greetings") + public Greeting greeting(Message message) throws Exception { + return new Greeting("Hello, " + HtmlUtils.htmlEscape(message.getName()) + "!"); + } + +} \ No newline at end of file diff --git a/spring-security-mvc-socket/src/main/java/com/baeldung/springsockets/models/Greeting.java b/spring-security-mvc-socket/src/main/java/com/baeldung/springsockets/models/Greeting.java new file mode 100644 index 0000000000..b6122ac1e7 --- /dev/null +++ b/spring-security-mvc-socket/src/main/java/com/baeldung/springsockets/models/Greeting.java @@ -0,0 +1,18 @@ +package com.baeldung.springsockets.models; + +public class Greeting { + + private String content; + + public Greeting() { + } + + public Greeting(String content) { + this.content = content; + } + + public String getContent() { + return content; + } + +} diff --git a/spring-security-mvc-socket/src/main/java/com/baeldung/springsockets/models/Message.java b/spring-security-mvc-socket/src/main/java/com/baeldung/springsockets/models/Message.java new file mode 100644 index 0000000000..4dd002606a --- /dev/null +++ b/spring-security-mvc-socket/src/main/java/com/baeldung/springsockets/models/Message.java @@ -0,0 +1,22 @@ +package com.baeldung.springsockets.models; + +public class Message { + + private String name; + + public Message() { + } + + public Message(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + +} \ No newline at end of file diff --git a/spring-security-mvc-socket/src/main/resources/static/rest.html b/spring-security-mvc-socket/src/main/resources/static/rest.html new file mode 100644 index 0000000000..476d053eea --- /dev/null +++ b/spring-security-mvc-socket/src/main/resources/static/rest.html @@ -0,0 +1,39 @@ + + + + Demo for RESTful Service for Comparison to WebSocket + + + + + + + +
+
+
+
+
+ + +
+ +
+
+
+
+
+ + + + + + + + +
Greetings
+
+
+
+ + \ No newline at end of file diff --git a/spring-security-mvc-socket/src/main/resources/static/rest.js b/spring-security-mvc-socket/src/main/resources/static/rest.js new file mode 100644 index 0000000000..403cc63585 --- /dev/null +++ b/spring-security-mvc-socket/src/main/resources/static/rest.js @@ -0,0 +1,21 @@ +var request = new XMLHttpRequest() + +function sendName() { + request.open('GET', 'http://localhost:8080/rest/'+$("#name").val(), true) + request.onload = function () { + var data = JSON.parse(this.response) + showGreeting(data.greeting) + } + request.send() +} + +function showGreeting(message) { + $("#greetings").append("" + message + ""); +} + +$(function () { + $("form").on('submit', function (e) { + e.preventDefault(); + }); + $( "#send" ).click(function() { sendName(); }); +}); \ No newline at end of file diff --git a/spring-security-mvc-socket/src/main/resources/static/ws.html b/spring-security-mvc-socket/src/main/resources/static/ws.html new file mode 100644 index 0000000000..638b8c0857 --- /dev/null +++ b/spring-security-mvc-socket/src/main/resources/static/ws.html @@ -0,0 +1,39 @@ + + + + Demo for WebSocket for Comparison to RESTful Service + + + + + + + +
+
+
+
+
+ + +
+ +
+
+
+
+
+ + + + + + + + +
Greetings
+
+
+
+ + \ No newline at end of file diff --git a/spring-security-mvc-socket/src/main/resources/static/ws.js b/spring-security-mvc-socket/src/main/resources/static/ws.js new file mode 100644 index 0000000000..538faf4e61 --- /dev/null +++ b/spring-security-mvc-socket/src/main/resources/static/ws.js @@ -0,0 +1,26 @@ +var stompClient = null; + +function connect() { + stompClient = Stomp.client('ws://localhost:8080/ws'); + stompClient.connect({}, function (frame) { + stompClient.subscribe('/topic/greetings', function (response) { + showGreeting(JSON.parse(response.body).content); + }); + }); +} + +function sendName() { + stompClient.send("/app/hello", {}, JSON.stringify({'name': $("#name").val()})); +} + +function showGreeting(message) { + $("#greetings").append("" + message + ""); +} + +$(function () { + connect(); + $("form").on('submit', function (e) { + e.preventDefault(); + }); + $( "#send" ).click(function() { sendName(); }); +}); \ No newline at end of file diff --git a/spring-security-rest-basic-auth/README.md b/spring-security-rest-basic-auth/README.md index 30da3afbcf..b905824161 100644 --- a/spring-security-rest-basic-auth/README.md +++ b/spring-security-rest-basic-auth/README.md @@ -7,7 +7,5 @@ The "Learn Spring Security" Classes: http://github.learnspringsecurity.com ### Relevant Articles: - [Basic Authentication with the RestTemplate](http://www.baeldung.com/how-to-use-resttemplate-with-basic-authentication-in-spring) -- [HttpClient Timeout](http://www.baeldung.com/httpclient-timeout) -- [HttpClient with SSL](http://www.baeldung.com/httpclient-ssl) - [A Custom Filter in the Spring Security Filter Chain](http://www.baeldung.com/spring-security-custom-filter) - [Spring Security Basic Authentication](http://www.baeldung.com/spring-security-basic-authentication) diff --git a/spring-security-rest-basic-auth/pom.xml b/spring-security-rest-basic-auth/pom.xml index ca5c4c38e6..3c7f8eaa2b 100644 --- a/spring-security-rest-basic-auth/pom.xml +++ b/spring-security-rest-basic-auth/pom.xml @@ -272,8 +272,8 @@ - 4.4.5 - 4.5.3 + 4.4.11 + 4.5.8 1.2 diff --git a/spring-security-rest/README.md b/spring-security-rest/README.md index f71eead9ae..f450a514b2 100644 --- a/spring-security-rest/README.md +++ b/spring-security-rest/README.md @@ -11,7 +11,6 @@ The "Learn Spring Security" Classes: http://github.learnspringsecurity.com - [Spring REST Service Security](http://www.baeldung.com/2011/10/31/securing-a-restful-web-service-with-spring-security-3-1-part-3/) - [Setting Up Swagger 2 with a Spring REST API](http://www.baeldung.com/swagger-2-documentation-for-spring-rest-api) - [Custom Error Message Handling for REST API](http://www.baeldung.com/global-error-handler-in-a-spring-rest-api) -- [An Intro to Spring HATEOAS](http://www.baeldung.com/spring-hateoas-tutorial) - [Spring Security Context Propagation with @Async](http://www.baeldung.com/spring-security-async-principal-propagation) - [Servlet 3 Async Support with Spring MVC and Spring Security](http://www.baeldung.com/spring-mvc-async-security) - [Intro to Spring Security Expressions](http://www.baeldung.com/spring-security-expressions) diff --git a/spring-security-rest/pom.xml b/spring-security-rest/pom.xml index 37c743e896..b6039ce9d3 100644 --- a/spring-security-rest/pom.xml +++ b/spring-security-rest/pom.xml @@ -21,12 +21,12 @@ org.springframework.security spring-security-web - ${org.springframework.security.version} + ${spring-security.version} org.springframework.security spring-security-config - ${org.springframework.security.version} + ${spring-security.version} @@ -84,13 +84,6 @@ ${spring.version} - - - org.springframework.hateoas - spring-hateoas - ${org.springframework.hateoas.version} - - @@ -144,7 +137,7 @@ org.springframework.security spring-security-test - ${org.springframework.security.version} + ${spring-security.version} test @@ -273,10 +266,6 @@ - - 5.1.0.RELEASE - 0.25.0.RELEASE - 3.1.0 1.1.0.Final diff --git a/spring-security-sso/README.md b/spring-security-sso/README.md index 11b5f011d5..d0c1b2f7cf 100644 --- a/spring-security-sso/README.md +++ b/spring-security-sso/README.md @@ -1,2 +1,2 @@ ### Relevant Articles: -- [Simple Single Sign On with Spring Security OAuth2](http://www.baeldung.com/sso-spring-security-oauth2) +- [Simple Single Sign-On with Spring Security OAuth2](http://www.baeldung.com/sso-spring-security-oauth2) diff --git a/spring-security-sso/pom.xml b/spring-security-sso/pom.xml index 707f516da2..ed8ad87a62 100644 --- a/spring-security-sso/pom.xml +++ b/spring-security-sso/pom.xml @@ -18,12 +18,15 @@ spring-security-sso-auth-server spring-security-sso-ui spring-security-sso-ui-2 + spring-security-sso-kerberos 3.1.0 2.3.3.RELEASE - 2.1.1.RELEASE + 2.1.1.RELEASE + 1.0.1.RELEASE + 2.0.0-M2 diff --git a/spring-security-sso/spring-security-sso-kerberos/.gitignore b/spring-security-sso/spring-security-sso-kerberos/.gitignore new file mode 100644 index 0000000000..a90740bb66 --- /dev/null +++ b/spring-security-sso/spring-security-sso-kerberos/.gitignore @@ -0,0 +1,2 @@ +krb-test-workdir/ +/bin/ diff --git a/spring-security-sso/spring-security-sso-kerberos/pom.xml b/spring-security-sso/spring-security-sso-kerberos/pom.xml new file mode 100644 index 0000000000..5fb435a9b9 --- /dev/null +++ b/spring-security-sso/spring-security-sso-kerberos/pom.xml @@ -0,0 +1,94 @@ + + + 4.0.0 + spring-security-sso-kerberos + + + org.baeldung + spring-security-sso + 1.0.0-SNAPSHOT + + + + + + ${basedir}/src/main/resources + true + + **/* + + + + + + org.apache.maven.plugins + maven-resources-plugin + 2.7 + + + @ + + false + + + + + + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.security.kerberos + spring-security-kerberos-web + ${spring-security-kerberos.version} + + + org.springframework.security.kerberos + spring-security-kerberos-client + ${spring-security-kerberos.version} + + + org.apache.directory.jdbm + apacheds-jdbm1 + ${apacheds-jdbm1.version} + + + org.springframework.security.kerberos + spring-security-kerberos-test + + + org.apache.directory.jdbm + apacheds-jdbm1 + + + org.slf4j + slf4j-log4j12 + + + ${spring-security-kerberos.version} + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-logging + + + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + \ No newline at end of file diff --git a/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/client/KerberosClientApp.java b/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/client/KerberosClientApp.java new file mode 100644 index 0000000000..9fb86e7658 --- /dev/null +++ b/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/client/KerberosClientApp.java @@ -0,0 +1,22 @@ +package kerberos.client; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +import java.nio.file.Paths; + +@SpringBootApplication +class KerberosClientApp { + + static { + System.setProperty("java.security.krb5.conf", + Paths.get(".\\krb-test-workdir\\krb5.conf").normalize().toAbsolutePath().toString()); + System.setProperty("sun.security.krb5.debug", "true"); + // disable usage of local kerberos ticket cache + System.setProperty("http.use.global.creds", "false"); + } + + public static void main(String[] args) { + SpringApplication.run(KerberosClientApp.class, args); + } +} diff --git a/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/client/SampleClient.java b/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/client/SampleClient.java new file mode 100644 index 0000000000..745193e3b0 --- /dev/null +++ b/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/client/SampleClient.java @@ -0,0 +1,26 @@ +package kerberos.client; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +@Service +class SampleClient { + + @Value("${app.access-url}") + private String endpoint; + + private RestTemplate restTemplate; + + public SampleClient(RestTemplate restTemplate) { + this.restTemplate = restTemplate; + } + + void setRestTemplate(RestTemplate restTemplate) { + this.restTemplate = restTemplate; + } + + String getData() { + return restTemplate.getForObject(endpoint, String.class); + } +} diff --git a/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/client/config/AppConfig.java b/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/client/config/AppConfig.java new file mode 100644 index 0000000000..5248f648f9 --- /dev/null +++ b/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/client/config/AppConfig.java @@ -0,0 +1,10 @@ +package kerberos.client.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; + +@Configuration +@Import(KerberosConfig.class) +class AppConfig { + +} diff --git a/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/client/config/KerberosConfig.java b/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/client/config/KerberosConfig.java new file mode 100644 index 0000000000..9ab775e95d --- /dev/null +++ b/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/client/config/KerberosConfig.java @@ -0,0 +1,22 @@ +package kerberos.client.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.kerberos.client.KerberosRestTemplate; +import org.springframework.web.client.RestTemplate; + +@Configuration +class KerberosConfig { + + @Value("${app.user-principal}") + private String principal; + + @Value("${app.keytab-location}") + private String keytabLocation; + + @Bean + public RestTemplate restTemplate() { + return new KerberosRestTemplate(keytabLocation, principal); + } +} diff --git a/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/kdc/KerberosMiniKdc.java b/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/kdc/KerberosMiniKdc.java new file mode 100644 index 0000000000..60cf3ca1c2 --- /dev/null +++ b/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/kdc/KerberosMiniKdc.java @@ -0,0 +1,35 @@ +package kerberos.kdc; + +import org.apache.commons.io.FileUtils; +import org.springframework.security.kerberos.test.MiniKdc; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; + +class KerberosMiniKdc { + + private static final String KRB_WORK_DIR = ".\\spring-security-sso\\spring-security-sso-kerberos\\krb-test-workdir"; + + public static void main(String[] args) throws Exception { + + String[] config = MiniKdcConfigBuilder.builder() + .workDir(prepareWorkDir()) + .confDir("minikdc-krb5.conf") + .keytabName("example.keytab") + .principals("client/localhost", "HTTP/localhost") + .build(); + + MiniKdc.main(config); + } + + private static String prepareWorkDir() throws IOException { + Path dir = Paths.get(KRB_WORK_DIR); + File directory = dir.normalize().toFile(); + + FileUtils.deleteQuietly(directory); + FileUtils.forceMkdir(directory); + return dir.toString(); + } +} diff --git a/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/kdc/MiniKdcConfigBuilder.java b/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/kdc/MiniKdcConfigBuilder.java new file mode 100644 index 0000000000..a9dd21a175 --- /dev/null +++ b/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/kdc/MiniKdcConfigBuilder.java @@ -0,0 +1,64 @@ +package kerberos.kdc; + +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Objects; + +class MiniKdcConfigBuilder { + + private String workDir; + private String confDir; + private String keytabName; + private Collection principals; + + private MiniKdcConfigBuilder() { + // desired + } + + static MiniKdcConfigBuilder builder() { + return new MiniKdcConfigBuilder(); + } + + MiniKdcConfigBuilder workDir(String workDir) { + this.workDir = workDir; + return this; + } + + MiniKdcConfigBuilder confDir(String cfg) { + try { + URL resource = Thread.currentThread().getContextClassLoader().getResource(cfg); + URI uri = Objects.requireNonNull(resource).toURI(); + this.confDir = Paths.get(uri).toString(); + } catch (URISyntaxException cause) { + throw new IllegalStateException("Could not resolve path for: " + cfg, cause); + } + return this; + } + + MiniKdcConfigBuilder keytabName(String keytabName) { + this.keytabName = Paths.get(workDir).resolve(keytabName).toString(); + return this; + } + + MiniKdcConfigBuilder principals(String... principals) { + this.principals = Arrays.asList(principals); + return this; + } + + String[] build() { + + Collection miniKdcConfig = new ArrayList<>(); + + miniKdcConfig.add(workDir); + miniKdcConfig.add(confDir); + miniKdcConfig.add(keytabName); + miniKdcConfig.addAll(principals); + + return miniKdcConfig.toArray(new String[0]); + } +} diff --git a/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/server/KerberizedServerApp.java b/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/server/KerberizedServerApp.java new file mode 100644 index 0000000000..8286013605 --- /dev/null +++ b/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/server/KerberizedServerApp.java @@ -0,0 +1,22 @@ +package kerberos.server; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +import java.nio.file.Paths; + +@SpringBootApplication +public class KerberizedServerApp { + + static { + System.setProperty("java.security.krb5.conf", + Paths.get(".\\spring-security-sso\\spring-security-sso-kerberos\\krb-test-workdir\\krb5.conf") + .normalize().toAbsolutePath().toString()); + System.setProperty("sun.security.krb5.debug", "true"); + } + + public static void main(String[] args) { + + SpringApplication.run(KerberizedServerApp.class, args); + } +} diff --git a/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/server/config/MvcConfig.java b/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/server/config/MvcConfig.java new file mode 100644 index 0000000000..3ad07e407b --- /dev/null +++ b/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/server/config/MvcConfig.java @@ -0,0 +1,18 @@ +package kerberos.server.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; + +@Configuration +class MvcConfig extends WebMvcConfigurerAdapter { + + @Override + public void addViewControllers(ViewControllerRegistry registry) { + registry.addViewController("/home").setViewName("home"); + registry.addViewController("/").setViewName("home"); + registry.addViewController("/hello").setViewName("hello"); + registry.addViewController("/login").setViewName("login"); + } + +} \ No newline at end of file diff --git a/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/server/config/WebSecurityConfig.java b/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/server/config/WebSecurityConfig.java new file mode 100644 index 0000000000..5d241c5823 --- /dev/null +++ b/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/server/config/WebSecurityConfig.java @@ -0,0 +1,103 @@ +package kerberos.server.config; + +import kerberos.server.service.DummyUserDetailsService; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.FileSystemResource; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +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.springframework.security.kerberos.authentication.KerberosAuthenticationProvider; +import org.springframework.security.kerberos.authentication.KerberosServiceAuthenticationProvider; +import org.springframework.security.kerberos.authentication.sun.SunJaasKerberosClient; +import org.springframework.security.kerberos.authentication.sun.SunJaasKerberosTicketValidator; +import org.springframework.security.kerberos.web.authentication.SpnegoAuthenticationProcessingFilter; +import org.springframework.security.kerberos.web.authentication.SpnegoEntryPoint; +import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; + +@Configuration +@EnableWebSecurity +class WebSecurityConfig extends WebSecurityConfigurerAdapter { + + @Value("${app.service-principal}") + private String servicePrincipal; + + @Value("${app.keytab-location}") + private String keytabLocation; + + @Override + protected void configure(HttpSecurity http) throws Exception { + http.exceptionHandling() + .authenticationEntryPoint(spnegoEntryPoint()) + .and() + .authorizeRequests().antMatchers("/", "/home").permitAll() + .anyRequest().authenticated() + .and() + .formLogin().loginPage("/login").permitAll() + .and() + .logout().permitAll() + .and() + .addFilterBefore(spnegoAuthenticationProcessingFilter(authenticationManagerBean()), + BasicAuthenticationFilter.class); + } + + @Bean + public AuthenticationManager anAuthenticationManager() throws Exception { + return authenticationManager(); + } + + @Override + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + auth.authenticationProvider(kerberosAuthenticationProvider()) + .authenticationProvider(kerberosServiceAuthenticationProvider()); + } + + @Bean + public KerberosAuthenticationProvider kerberosAuthenticationProvider() { + KerberosAuthenticationProvider provider = new KerberosAuthenticationProvider(); + SunJaasKerberosClient client = new SunJaasKerberosClient(); + client.setDebug(true); + provider.setKerberosClient(client); + provider.setUserDetailsService(dummyUserDetailsService()); + return provider; + } + + @Bean + public SpnegoEntryPoint spnegoEntryPoint() { + return new SpnegoEntryPoint("/login"); + } + + @Bean + public SpnegoAuthenticationProcessingFilter spnegoAuthenticationProcessingFilter( + AuthenticationManager authenticationManager) { + SpnegoAuthenticationProcessingFilter filter = new SpnegoAuthenticationProcessingFilter(); + filter.setAuthenticationManager(authenticationManager); + return filter; + } + + @Bean + public KerberosServiceAuthenticationProvider kerberosServiceAuthenticationProvider() { + KerberosServiceAuthenticationProvider provider = new KerberosServiceAuthenticationProvider(); + provider.setTicketValidator(sunJaasKerberosTicketValidator()); + provider.setUserDetailsService(dummyUserDetailsService()); + return provider; + } + + @Bean + public SunJaasKerberosTicketValidator sunJaasKerberosTicketValidator() { + SunJaasKerberosTicketValidator ticketValidator = new SunJaasKerberosTicketValidator(); + ticketValidator.setServicePrincipal(servicePrincipal); + ticketValidator.setKeyTabLocation(new FileSystemResource(keytabLocation)); + ticketValidator.setDebug(true); + return ticketValidator; + } + + @Bean + public DummyUserDetailsService dummyUserDetailsService() { + return new DummyUserDetailsService(); + } + +} diff --git a/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/server/controller/SampleController.java b/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/server/controller/SampleController.java new file mode 100644 index 0000000000..b1d3e6fb90 --- /dev/null +++ b/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/server/controller/SampleController.java @@ -0,0 +1,15 @@ +package kerberos.server.controller; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/endpoint") +class SampleController { + + @GetMapping + String getIt() { + return "data from kerberized server"; + } +} diff --git a/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/server/service/DummyUserDetailsService.java b/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/server/service/DummyUserDetailsService.java new file mode 100644 index 0000000000..06942d8dc7 --- /dev/null +++ b/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/server/service/DummyUserDetailsService.java @@ -0,0 +1,16 @@ +package kerberos.server.service; + +import org.springframework.security.core.authority.AuthorityUtils; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; + +public class DummyUserDetailsService implements UserDetailsService { + + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + return new User(username, "notUsed", true, true, true, true, AuthorityUtils.createAuthorityList("ROLE_USER")); + } + +} diff --git a/spring-security-sso/spring-security-sso-kerberos/src/main/resources/application.properties b/spring-security-sso/spring-security-sso-kerberos/src/main/resources/application.properties new file mode 100644 index 0000000000..b36575460c --- /dev/null +++ b/spring-security-sso/spring-security-sso-kerberos/src/main/resources/application.properties @@ -0,0 +1,6 @@ +# make sure the same data is configured in KerberosMiniKdc +# otherwise configuration/communication error will occur +app.service-principal=HTTP/localhost +app.user-principal=client/localhost +app.keytab-location=@project.basedir@\\krb-test-workdir\\example.keytab +app.access-url=http://localhost:8080/endpoint diff --git a/spring-security-sso/spring-security-sso-kerberos/src/main/resources/minikdc-krb5.conf b/spring-security-sso/spring-security-sso-kerberos/src/main/resources/minikdc-krb5.conf new file mode 100644 index 0000000000..ea1e9d1ceb --- /dev/null +++ b/spring-security-sso/spring-security-sso-kerberos/src/main/resources/minikdc-krb5.conf @@ -0,0 +1,25 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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 +# +# http://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. +# +[libdefaults] +default_realm = {0} +udp_preference_limit = 1 + +[realms] +{0} = '{' + kdc = {1}:{2} + '}' \ No newline at end of file diff --git a/spring-security-sso/spring-security-sso-kerberos/src/main/resources/minikdc.ldiff b/spring-security-sso/spring-security-sso-kerberos/src/main/resources/minikdc.ldiff new file mode 100644 index 0000000000..603ccb5fd9 --- /dev/null +++ b/spring-security-sso/spring-security-sso-kerberos/src/main/resources/minikdc.ldiff @@ -0,0 +1,47 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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 +# +# http://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. +# +dn: ou=users,dc=${0},dc=${1} +objectClass: organizationalUnit +objectClass: top +ou: users + +dn: uid=krbtgt,ou=users,dc=${0},dc=${1} +objectClass: top +objectClass: person +objectClass: inetOrgPerson +objectClass: krb5principal +objectClass: krb5kdcentry +cn: KDC Service +sn: Service +uid: krbtgt +userPassword: secret +krb5PrincipalName: krbtgt/${2}.${3}@${2}.${3} +krb5KeyVersionNumber: 0 + +dn: uid=ldap,ou=users,dc=${0},dc=${1} +objectClass: top +objectClass: person +objectClass: inetOrgPerson +objectClass: krb5principal +objectClass: krb5kdcentry +cn: LDAP +sn: Service +uid: ldap +userPassword: secret +krb5PrincipalName: ldap/${4}@${2}.${3} +krb5KeyVersionNumber: 0 \ No newline at end of file diff --git a/spring-security-sso/spring-security-sso-kerberos/src/main/resources/templates/hello.html b/spring-security-sso/spring-security-sso-kerberos/src/main/resources/templates/hello.html new file mode 100644 index 0000000000..71a756386b --- /dev/null +++ b/spring-security-sso/spring-security-sso-kerberos/src/main/resources/templates/hello.html @@ -0,0 +1,10 @@ + + + + Spring Security Kerberos Example + + +

Hello [[${#httpServletRequest.remoteUser}]]!

+ + diff --git a/spring-security-sso/spring-security-sso-kerberos/src/main/resources/templates/home.html b/spring-security-sso/spring-security-sso-kerberos/src/main/resources/templates/home.html new file mode 100644 index 0000000000..d8e37e443d --- /dev/null +++ b/spring-security-sso/spring-security-sso-kerberos/src/main/resources/templates/home.html @@ -0,0 +1,10 @@ + + + + Spring Security Kerberos Example + + +

Welcome!

+

Click here to see a greeting.

+ + diff --git a/spring-security-sso/spring-security-sso-kerberos/src/main/resources/templates/login.html b/spring-security-sso/spring-security-sso-kerberos/src/main/resources/templates/login.html new file mode 100644 index 0000000000..b96252192f --- /dev/null +++ b/spring-security-sso/spring-security-sso-kerberos/src/main/resources/templates/login.html @@ -0,0 +1,20 @@ + + + + Spring Security Kerberos Example + + +
+ Invalid username and password. +
+
+ You have been logged out. +
+
+
+
+
+
+ + diff --git a/spring-security-sso/spring-security-sso-kerberos/src/test/java/kerberos/client/SampleClientManualTest.java b/spring-security-sso/spring-security-sso-kerberos/src/test/java/kerberos/client/SampleClientManualTest.java new file mode 100644 index 0000000000..fdb1b12531 --- /dev/null +++ b/spring-security-sso/spring-security-sso-kerberos/src/test/java/kerberos/client/SampleClientManualTest.java @@ -0,0 +1,39 @@ +package kerberos.client; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.web.client.RestClientException; +import org.springframework.web.client.RestTemplate; + +import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +/** + * Procedure to run this manual test: + *
    + *
  1. Start {@code KerberosMiniKdc}
  2. + *
  3. Start {@code KerberizedServerApp}
  4. + *
  5. Run the test
  6. + *
+ */ +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +public class SampleClientManualTest { + + @Autowired + private SampleClient sampleClient; + + @Test + public void givenKerberizedRestTemplate_whenServiceCall_thenSuccess() { + assertEquals("data from kerberized server", sampleClient.getData()); + } + + @Test + public void givenRestTemplate_whenServiceCall_thenFail() { + sampleClient.setRestTemplate(new RestTemplate()); + assertThrows(RestClientException.class, sampleClient::getData); + } +} \ No newline at end of file diff --git a/spring-security-stormpath/pom.xml b/spring-security-stormpath/pom.xml index dd6037a22c..6db4b38d80 100644 --- a/spring-security-stormpath/pom.xml +++ b/spring-security-stormpath/pom.xml @@ -32,7 +32,7 @@ com.stormpath.spring stormpath-default-spring-boot-starter - 1.5.4 + ${stormpath-spring.version} @@ -60,5 +60,9 @@ + + + 1.5.4 + diff --git a/spring-session/spring-session-jdbc/README.MD b/spring-session/spring-session-jdbc/README.md similarity index 55% rename from spring-session/spring-session-jdbc/README.MD rename to spring-session/spring-session-jdbc/README.md index 9293dfc953..94fd1cd3e7 100644 --- a/spring-session/spring-session-jdbc/README.MD +++ b/spring-session/spring-session-jdbc/README.md @@ -2,5 +2,3 @@ This module is for Spring Session with JDBC tutorial. Jira BAEL-1911 ### Relevant Articles: - -- [Spring Session with JDBC](http://www.baeldung.com/spring-session-jdbc) diff --git a/spring-session/spring-session-jdbc/pom.xml b/spring-session/spring-session-jdbc/pom.xml index a98c4b3429..b46b549ce2 100644 --- a/spring-session/spring-session-jdbc/pom.xml +++ b/spring-session/spring-session-jdbc/pom.xml @@ -10,10 +10,6 @@ jar Spring Session with JDBC tutorial - - 1.4.197 - - parent-boot-2 com.baeldung @@ -52,5 +48,8 @@ + + 1.4.197 + \ No newline at end of file diff --git a/spring-session/spring-session-redis/README.md b/spring-session/spring-session-redis/README.md index 5e9304d778..5865913711 100644 --- a/spring-session/spring-session-redis/README.md +++ b/spring-session/spring-session-redis/README.md @@ -3,4 +3,3 @@ ## Spring Session Examples ### Relevant Articles: -- [Guide to Spring Session](http://www.baeldung.com/spring-session) diff --git a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/ForkJoinStateMachineConfiguration.java b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/ForkJoinStateMachineConfiguration.java index 3a3e632c51..55e1397823 100644 --- a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/ForkJoinStateMachineConfiguration.java +++ b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/ForkJoinStateMachineConfiguration.java @@ -64,11 +64,11 @@ public class ForkJoinStateMachineConfiguration extends StateMachineConfigurerAda @Bean public Guard mediumGuard() { - return (ctx) -> false; + return ctx -> false; } @Bean public Guard highGuard() { - return (ctx) -> false; + return ctx -> false; } } \ No newline at end of file diff --git a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/JunctionStateMachineConfiguration.java b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/JunctionStateMachineConfiguration.java index 2f48a9dbb5..21b37381df 100644 --- a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/JunctionStateMachineConfiguration.java +++ b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/JunctionStateMachineConfiguration.java @@ -50,11 +50,11 @@ public class JunctionStateMachineConfiguration extends StateMachineConfigurerAda @Bean public Guard mediumGuard() { - return (ctx) -> false; + return ctx -> false; } @Bean public Guard highGuard() { - return (ctx) -> false; + return ctx -> false; } } \ No newline at end of file diff --git a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/SimpleStateMachineConfiguration.java b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/SimpleStateMachineConfiguration.java index d1b1ce001c..0c392c2c35 100644 --- a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/SimpleStateMachineConfiguration.java +++ b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/SimpleStateMachineConfiguration.java @@ -18,7 +18,7 @@ import java.util.logging.Logger; @EnableStateMachine public class SimpleStateMachineConfiguration extends StateMachineConfigurerAdapter { - public static final Logger LOGGER = Logger.getLogger(SimpleStateMachineConfiguration.class.getName()); + private static final Logger LOGGER = Logger.getLogger(SimpleStateMachineConfiguration.class.getName()); @Override public void configure(StateMachineConfigurationConfigurer config) throws Exception { @@ -80,7 +80,7 @@ public class SimpleStateMachineConfiguration extends StateMachineConfigurerAdapt @Bean public Guard simpleGuard() { - return (ctx) -> { + return ctx -> { int approvalCount = (int) ctx .getExtendedState() .getVariables() diff --git a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/StateMachineListener.java b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/StateMachineListener.java index 47a274404e..09e8946810 100644 --- a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/StateMachineListener.java +++ b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/StateMachineListener.java @@ -7,10 +7,10 @@ import java.util.logging.Logger; public class StateMachineListener extends StateMachineListenerAdapter { - public static final Logger LOGGER = Logger.getLogger(StateMachineListener.class.getName()); + private static final Logger LOGGER = Logger.getLogger(StateMachineListener.class.getName()); @Override public void stateChanged(State from, State to) { - LOGGER.info(String.format("Transitioned from %s to %s%n", from == null ? "none" : from.getId(), to.getId())); + LOGGER.info(() -> String.format("Transitioned from %s to %s%n", from == null ? "none" : from.getId(), to.getId())); } } diff --git a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/ForkJoinStateMachineIntegrationTest.java b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/ForkJoinStateMachineIntegrationTest.java index b34d5c47c6..66acad901c 100644 --- a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/ForkJoinStateMachineIntegrationTest.java +++ b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/ForkJoinStateMachineIntegrationTest.java @@ -1,18 +1,15 @@ package com.baeldung.spring.statemachine; import com.baeldung.spring.statemachine.config.ForkJoinStateMachineConfiguration; -import com.baeldung.spring.statemachine.config.JunctionStateMachineConfiguration; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.statemachine.StateMachine; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import javax.annotation.Resource; import java.util.Arrays; import static org.junit.Assert.assertEquals; diff --git a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/HierarchicalStateMachineIntegrationTest.java b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/HierarchicalStateMachineIntegrationTest.java index 3d7c0be828..00a9c9a08c 100644 --- a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/HierarchicalStateMachineIntegrationTest.java +++ b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/HierarchicalStateMachineIntegrationTest.java @@ -1,18 +1,15 @@ package com.baeldung.spring.statemachine; import com.baeldung.spring.statemachine.config.HierarchicalStateMachineConfiguration; -import com.baeldung.spring.statemachine.config.JunctionStateMachineConfiguration; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.statemachine.StateMachine; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import javax.annotation.Resource; import java.util.Arrays; import static org.junit.Assert.assertEquals; diff --git a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/JunctionStateMachineIntegrationTest.java b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/JunctionStateMachineIntegrationTest.java index 93de23fad3..f0ee757522 100644 --- a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/JunctionStateMachineIntegrationTest.java +++ b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/JunctionStateMachineIntegrationTest.java @@ -1,20 +1,16 @@ package com.baeldung.spring.statemachine; import com.baeldung.spring.statemachine.config.JunctionStateMachineConfiguration; -import com.baeldung.spring.statemachine.config.SimpleEnumStateMachineConfiguration; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.statemachine.StateMachine; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import javax.annotation.Resource; - @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = JunctionStateMachineConfiguration.class) public class JunctionStateMachineIntegrationTest { diff --git a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateEnumMachineIntegrationTest.java b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateEnumMachineIntegrationTest.java index 9074ece001..d345cd0dfc 100644 --- a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateEnumMachineIntegrationTest.java +++ b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateEnumMachineIntegrationTest.java @@ -3,19 +3,15 @@ package com.baeldung.spring.statemachine; import com.baeldung.spring.statemachine.applicationreview.ApplicationReviewEvents; import com.baeldung.spring.statemachine.applicationreview.ApplicationReviewStates; import com.baeldung.spring.statemachine.config.SimpleEnumStateMachineConfiguration; -import com.baeldung.spring.statemachine.config.SimpleStateMachineConfiguration; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.statemachine.StateMachine; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import javax.annotation.Resource; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; diff --git a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineBuilderIntegrationTest.java b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineBuilderIntegrationTest.java index c1de8b8958..e5431d9d83 100644 --- a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineBuilderIntegrationTest.java +++ b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineBuilderIntegrationTest.java @@ -1,11 +1,11 @@ package com.baeldung.spring.statemachine; -import static org.junit.Assert.assertEquals; - import org.junit.Test; import org.springframework.statemachine.StateMachine; import org.springframework.statemachine.config.StateMachineBuilder; +import static org.junit.Assert.assertEquals; + public class StateMachineBuilderIntegrationTest { @Test diff --git a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineIntegrationTest.java b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineIntegrationTest.java index 25df7c8cd3..aab07225a3 100644 --- a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineIntegrationTest.java +++ b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineIntegrationTest.java @@ -1,22 +1,17 @@ package com.baeldung.spring.statemachine; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - +import com.baeldung.spring.statemachine.config.SimpleStateMachineConfiguration; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.statemachine.StateMachine; - -import com.baeldung.spring.statemachine.config.SimpleStateMachineConfiguration; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.test.context.junit4.SpringRunner; -import javax.annotation.Resource; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = SimpleStateMachineConfiguration.class) @@ -42,7 +37,7 @@ public class StateMachineIntegrationTest { } @Test - public void whenSimpleStringMachineActionState_thenActionExecuted() throws InterruptedException { + public void whenSimpleStringMachineActionState_thenActionExecuted() { stateMachine.sendEvent("E3"); assertEquals("S3", stateMachine.getState().getId()); diff --git a/spring-static-resources/pom.xml b/spring-static-resources/pom.xml index aedf88e384..fc2b3336bc 100644 --- a/spring-static-resources/pom.xml +++ b/spring-static-resources/pom.xml @@ -20,17 +20,17 @@ org.springframework.security spring-security-web - ${org.springframework.security.version} + ${spring-security.version} org.springframework.security spring-security-config - ${org.springframework.security.version} + ${spring-security.version} org.springframework.security spring-security-taglibs - ${org.springframework.security.version} + ${spring-security.version} @@ -196,9 +196,6 @@ - - 5.0.6.RELEASE - 1.8.9 2.3.2-b02 diff --git a/spring-thymeleaf/README.md b/spring-thymeleaf/README.md index f9e7dd90a7..b6824003db 100644 --- a/spring-thymeleaf/README.md +++ b/spring-thymeleaf/README.md @@ -8,7 +8,7 @@ - [Thymeleaf: Custom Layout Dialect](http://www.baeldung.com/thymeleaf-spring-layouts) - [Spring and Thymeleaf 3: Expressions](http://www.baeldung.com/spring-thymeleaf-3-expressions) - [Spring MVC + Thymeleaf 3.0: New Features](http://www.baeldung.com/spring-thymeleaf-3) -- [How to Work with Dates in Thymeleaef](http://www.baeldung.com/dates-in-thymeleaf) +- [How to Work with Dates in Thymeleaf](http://www.baeldung.com/dates-in-thymeleaf) - [How to Create an Executable JAR with Maven](http://www.baeldung.com/executable-jar-with-maven) - [Working with Boolean in Thymeleaf](http://www.baeldung.com/thymeleaf-boolean) - [Working with Fragments in Thymeleaf](http://www.baeldung.com/spring-thymeleaf-fragments) diff --git a/tensorflow-java/.gitignore b/tensorflow-java/.gitignore new file mode 100644 index 0000000000..eaea64ae48 --- /dev/null +++ b/tensorflow-java/.gitignore @@ -0,0 +1,6 @@ +/.settings +/model +/target +.classpath +.project +.springBeans \ No newline at end of file diff --git a/tensorflow-java/README.md b/tensorflow-java/README.md new file mode 100644 index 0000000000..f826375ac1 --- /dev/null +++ b/tensorflow-java/README.md @@ -0,0 +1,3 @@ +## Relevant articles: + +- [Introduction to Tensorflow for Java](https://www.baeldung.com/tensorflow-java) diff --git a/tensorflow-java/pom.xml b/tensorflow-java/pom.xml new file mode 100644 index 0000000000..f52cd4a68f --- /dev/null +++ b/tensorflow-java/pom.xml @@ -0,0 +1,52 @@ + + + 4.0.0 + com.baeldung + tensorflow-java + 1.0-SNAPSHOT + jar + http://maven.apache.org + + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + + + + + org.tensorflow + tensorflow + ${tensorflow.version} + + + org.junit.jupiter + junit-jupiter-api + ${junit.jupiter.version} + test + + + org.junit.jupiter + junit-jupiter-engine + ${junit.jupiter.version} + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + 1.8 + 1.12.0 + 5.4.0 + + \ No newline at end of file diff --git a/tensorflow-java/src/main/java/org/baeldung/tensorflow/TensorflowGraph.java b/tensorflow-java/src/main/java/org/baeldung/tensorflow/TensorflowGraph.java new file mode 100644 index 0000000000..a44ef4c4ee --- /dev/null +++ b/tensorflow-java/src/main/java/org/baeldung/tensorflow/TensorflowGraph.java @@ -0,0 +1,41 @@ +package org.baeldung.tensorflow; + +import org.tensorflow.DataType; +import org.tensorflow.Graph; +import org.tensorflow.Operation; +import org.tensorflow.Session; +import org.tensorflow.Tensor; + +public class TensorflowGraph { + + public static Graph createGraph() { + Graph graph = new Graph(); + Operation a = graph.opBuilder("Const", "a").setAttr("dtype", DataType.fromClass(Double.class)) + .setAttr("value", Tensor.create(3.0, Double.class)).build(); + Operation b = graph.opBuilder("Const", "b").setAttr("dtype", DataType.fromClass(Double.class)) + .setAttr("value", Tensor.create(2.0, Double.class)).build(); + Operation x = graph.opBuilder("Placeholder", "x").setAttr("dtype", DataType.fromClass(Double.class)).build(); + Operation y = graph.opBuilder("Placeholder", "y").setAttr("dtype", DataType.fromClass(Double.class)).build(); + Operation ax = graph.opBuilder("Mul", "ax").addInput(a.output(0)).addInput(x.output(0)).build(); + Operation by = graph.opBuilder("Mul", "by").addInput(b.output(0)).addInput(y.output(0)).build(); + graph.opBuilder("Add", "z").addInput(ax.output(0)).addInput(by.output(0)).build(); + return graph; + } + + public static Object runGraph(Graph graph, Double x, Double y) { + Object result; + try (Session sess = new Session(graph)) { + result = sess.runner().fetch("z").feed("x", Tensor.create(x, Double.class)) + .feed("y", Tensor.create(y, Double.class)).run().get(0).expect(Double.class) + .doubleValue(); + } + return result; + } + + public static void main(String[] args) { + Graph graph = TensorflowGraph.createGraph(); + Object result = TensorflowGraph.runGraph(graph, 3.0, 6.0); + System.out.println(result); + graph.close(); + } +} \ No newline at end of file diff --git a/tensorflow-java/src/main/java/org/baeldung/tensorflow/TensorflowSavedModel.java b/tensorflow-java/src/main/java/org/baeldung/tensorflow/TensorflowSavedModel.java new file mode 100644 index 0000000000..4259a787e8 --- /dev/null +++ b/tensorflow-java/src/main/java/org/baeldung/tensorflow/TensorflowSavedModel.java @@ -0,0 +1,14 @@ +package org.baeldung.tensorflow; + +import org.tensorflow.SavedModelBundle; +import org.tensorflow.Tensor; + +public class TensorflowSavedModel { + + public static void main(String[] args) { + SavedModelBundle model = SavedModelBundle.load("./model", "serve"); + Tensor tensor = model.session().runner().fetch("z").feed("x", Tensor.create(3, Integer.class)) + .feed("y", Tensor.create(3, Integer.class)).run().get(0).expect(Integer.class); + System.out.println(tensor.intValue()); + } +} \ No newline at end of file diff --git a/tensorflow-java/src/main/python/tensorflowGraph.py b/tensorflow-java/src/main/python/tensorflowGraph.py new file mode 100644 index 0000000000..ab7f8810ac --- /dev/null +++ b/tensorflow-java/src/main/python/tensorflowGraph.py @@ -0,0 +1,16 @@ +import tensorflow as tf +graph = tf.Graph() +builder = tf.saved_model.builder.SavedModelBuilder('./model') +writer = tf.summary.FileWriter('.') +with graph.as_default(): + a = tf.constant(2, name='a') + b = tf.constant(3, name='b') + x = tf.placeholder(tf.int32, name='x') + y = tf.placeholder(tf.int32, name='y') + z = tf.math.add(a*x, b*y, name='z') + writer.add_graph(tf.get_default_graph()) + writer.flush() + sess = tf.Session() + sess.run(z, feed_dict = {x: 2, y: 3}) + builder.add_meta_graph_and_variables(sess, [tf.saved_model.tag_constants.SERVING]) + builder.save() diff --git a/tensorflow-java/src/test/java/org/baeldung/tensorflow/TensorflowGraphUnitTest.java b/tensorflow-java/src/test/java/org/baeldung/tensorflow/TensorflowGraphUnitTest.java new file mode 100644 index 0000000000..51df6a4322 --- /dev/null +++ b/tensorflow-java/src/test/java/org/baeldung/tensorflow/TensorflowGraphUnitTest.java @@ -0,0 +1,21 @@ +package org.baeldung.tensorflow; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.Test; +import org.tensorflow.Graph; + +public class TensorflowGraphUnitTest { + + @Test + public void givenTensorflowGraphWhenRunInSessionReturnsExpectedResult() { + + Graph graph = TensorflowGraph.createGraph(); + Object result = TensorflowGraph.runGraph(graph, 3.0, 6.0); + assertEquals(21.0, result); + System.out.println(result); + graph.close(); + + } + +} diff --git a/testing-modules/groovy-spock/README.md b/testing-modules/groovy-spock/README.md index 18d26e8fc0..e61c56d470 100644 --- a/testing-modules/groovy-spock/README.md +++ b/testing-modules/groovy-spock/README.md @@ -1,3 +1,5 @@ ### Relevant articles - [Introduction to Testing with Spock and Groovy](http://www.baeldung.com/groovy-spock) +- [Difference Between Stub, Mock, and Spy in the Spock Framework](https://www.baeldung.com/spock-stub-mock-spy) +- [Guide to Spock Extensions](https://www.baeldung.com/spock-extensions) diff --git a/testing-modules/groovy-spock/pom.xml b/testing-modules/groovy-spock/pom.xml index d6097af208..35d8f5034f 100644 --- a/testing-modules/groovy-spock/pom.xml +++ b/testing-modules/groovy-spock/pom.xml @@ -48,7 +48,7 @@ - 1.3-RC1-groovy-2.4 + 1.3-groovy-2.4 2.4.7 1.5 diff --git a/testing-modules/groovy-spock/report-2019-03-29.json b/testing-modules/groovy-spock/report-2019-03-29.json new file mode 100644 index 0000000000..85f0b261fb --- /dev/null +++ b/testing-modules/groovy-spock/report-2019-03-29.json @@ -0,0 +1,402 @@ +loadLogFile([{ + "package": "mocks", + "name": "ExampleSpockTest", + "start": 1553898111660, + "features": [ + { + "name": "should calculate character occurrences in given string", + "start": 1553898111662, + "end": 1553898111699, + "result": "passed", + "attachments": [ + + ] + } + ], + "end": 1553898111709, + "result": "passed", + "attachments": [ + + ] +}]) + +loadLogFile([{ + "package": "mocks", + "name": "ItemServiceTest", + "start": 1553898111714, + "features": [ + { + "name": "should spy on EventPublisher method call", + "start": 1553898111714, + "output": [ + "I've published: item-id\n" + ], + "end": 1553898112250, + "result": "passed", + "attachments": [ + + ] + }, + { + "name": "should return items", + "start": 1553898112250, + "end": 1553898112260, + "result": "passed", + "attachments": [ + + ] + }, + { + "name": "should publish events about new non-empty saved offers", + "start": 1553898112260, + "end": 1553898112267, + "result": "passed", + "attachments": [ + + ] + }, + { + "name": "should return different items for different ids lists", + "start": 1553898112267, + "end": 1553898112280, + "result": "passed", + "attachments": [ + + ] + }, + { + "name": "should throw ExternalItemProviderException when ItemProvider fails", + "start": 1553898112281, + "end": 1553898112294, + "result": "passed", + "attachments": [ + + ] + }, + { + "name": "should return different items on subsequent call", + "start": 1553898112294, + "narrative": "When method is called for the first time\nThen empty list is returned\nWhen method is called for the second time\nThen item with id=1 is returned\nWhen method is called for the thirdtime\nThen item with id=2 is returned", + "end": 1553898112298, + "result": "passed", + "attachments": [ + + ] + }, + { + "name": "should return items sorted by name", + "start": 1553898112299, + "end": 1553898112307, + "result": "passed", + "attachments": [ + + ] + } + ], + "end": 1553898112310, + "result": "passed", + "attachments": [ + + ] +}]) + +loadLogFile([{ + "package": "FirstSpecification", + "name": "FirstSpecification", + "start": 1553898112314, + "features": [ + { + "name": "Should verify notify was called", + "start": 1553898112314, + "end": 1553898112324, + "result": "passed", + "attachments": [ + + ] + }, + { + "name": "Should return true value for mock", + "start": 1553898112325, + "end": 1553898112344, + "result": "passed", + "attachments": [ + + ] + }, + { + "name": "Should return default value for mock", + "start": 1553898112344, + "end": 1553898112347, + "result": "passed", + "attachments": [ + + ] + }, + { + "name": "numbers to the power of two", + "start": 1553898112347, + "end": 1553898112358, + "result": "passed", + "attachments": [ + + ] + }, + { + "name": "Should get an index out of bounds when removing a non-existent item", + "start": 1553898112358, + "end": 1553898112364, + "result": "passed", + "attachments": [ + + ] + }, + { + "name": "Should be able to remove from list", + "start": 1553898112364, + "end": 1553898112366, + "result": "passed", + "attachments": [ + + ] + }, + { + "name": "two plus two should equal four", + "start": 1553898112366, + "end": 1553898112368, + "result": "passed", + "attachments": [ + + ] + }, + { + "name": "one plus one should equal two", + "start": 1553898112368, + "end": 1553898112391, + "result": "passed", + "attachments": [ + + ] + } + ], + "end": 1553898112394, + "result": "passed", + "attachments": [ + + ] +}]) + +loadLogFile([{ + "package": "extensions", + "name": "IgnoreTest", + "start": 1553898112395, + "end": 1553898112395, + "result": "skipped" +}]) + +loadLogFile([{ + "package": "extensions", + "name": "RetryTest", + "start": 1553898112403, + "end": 1553898112405, + "result": "passed", + "attachments": [ + + ] +}]) + +loadLogFile([{ + "package": "extensions", + "name": "This title is easy to read for humans", + "start": 1553898112407, + "end": 1553898112408, + "result": "passed", + "attachments": [ + + ] +}]) + +loadLogFile([{ + "package": "extensions", + "name": "SeeTest", + "start": 1553898112409, + "end": 1553898112411, + "result": "passed", + "attachments": [ + + ] +}]) + +loadLogFile([{ + "package": "extensions", + "name": "StepwiseTest", + "start": 1553898112422, + "end": 1553898112423, + "result": "passed", + "attachments": [ + + ] +}]) + +loadLogFile([{ + "package": "extensions", + "name": "NarrativeDescriptionTest", + "start": 1553898112427, + "narrative": "as a user\n i want to save favourite items \n and then get the list of them", + "end": 1553898112433, + "result": "passed", + "attachments": [ + + ] +}]) + +loadLogFile([{ + "package": "extensions", + "name": "SubjectTest", + "start": 1553898112434, + "end": 1553898112436, + "result": "passed", + "attachments": [ + + ] +}]) + +loadLogFile([{ + "package": "extensions", + "name": "IgnoreRestTest", + "start": 1553898112437, + "end": 1553898112437, + "result": "passed", + "attachments": [ + + ] +}]) + +loadLogFile([{ + "package": "extensions", + "name": "StackTraceTest", + "start": 1553898112438, + "features": [ + { + "name": "stacktrace", + "start": 1553898112438, + "exceptions": [ + "java.lang.RuntimeException: blabla\n\tat extensions.StackTraceTest.stacktrace(StackTraceTest.groovy:10)\n" + ], + "end": 1553898112455, + "result": "failed", + "attachments": [ + + ] + } + ], + "end": 1553898112470, + "result": "failed", + "attachments": [ + + ] +}]) + +loadLogFile([{ + "package": "extensions", + "name": "IgnoreIfTest", + "start": 1553898112471, + "end": 1553898112472, + "result": "passed", + "attachments": [ + + ] +}]) + +loadLogFile([{ + "package": "extensions", + "name": "RequiresTest", + "start": 1553898112473, + "features": [ + { + "name": "I will run only on Windows", + "start": 1553898112474, + "end": 1553898112474, + "result": "skipped" + } + ], + "end": 1553898112476, + "result": "passed", + "attachments": [ + + ] +}]) + +loadLogFile([{ + "package": "extensions", + "name": "IssueTest", + "start": 1553898112477, + "features": [ + { + "name": "I'm using Spock configuration file", + "start": 1553898112477, + "tags": [ + { + "name": "Bug LO-1000", + "key": "issue", + "value": "LO-1000", + "url": "http:\/\/jira.org\/issues\/LO-1000" + } + ], + "end": 1553898112489, + "result": "passed", + "attachments": [ + + ] + } + ], + "end": 1553898112490, + "result": "passed", + "attachments": [ + + ] +}]) + +loadLogFile([{ + "package": "extensions", + "name": "TimeoutTest", + "start": 1553898112491, + "features": [ + { + "name": "I will fail after 200 millis", + "start": 1553898112491, + "end": 1553898112514, + "result": "passed", + "attachments": [ + + ] + } + ], + "end": 1553898112517, + "result": "passed", + "attachments": [ + + ] +}]) + +loadLogFile([{ + "package": "extensions", + "name": "RestoreSystemPropertiesTest", + "start": 1553898112518, + "features": [ + { + "name": "all environment variables will be saved before execution and restored after tests", + "start": 1553898112518, + "end": 1553898112532, + "result": "passed", + "attachments": [ + + ] + } + ], + "end": 1553898112539, + "result": "passed", + "attachments": [ + + ] +}]) + diff --git a/testing-modules/groovy-spock/src/test/groovy/extensions/CustomTitleTest.groovy b/testing-modules/groovy-spock/src/test/groovy/extensions/CustomTitleTest.groovy new file mode 100644 index 0000000000..11a5fb0eb9 --- /dev/null +++ b/testing-modules/groovy-spock/src/test/groovy/extensions/CustomTitleTest.groovy @@ -0,0 +1,20 @@ +package extensions + +import spock.lang.Narrative +import spock.lang.Specification +import spock.lang.Title + + +@Title("""This title is easy to read for humans""") +class CustomTitleTest extends Specification { + +} + +@Narrative(""" + as a user + i want to save favourite items + and then get the list of them +""") +class NarrativeDescriptionTest extends Specification { + +} diff --git a/testing-modules/groovy-spock/src/test/groovy/extensions/IgnoreIfTest.groovy b/testing-modules/groovy-spock/src/test/groovy/extensions/IgnoreIfTest.groovy new file mode 100644 index 0000000000..9010481220 --- /dev/null +++ b/testing-modules/groovy-spock/src/test/groovy/extensions/IgnoreIfTest.groovy @@ -0,0 +1,22 @@ +package extensions + +import spock.lang.IgnoreIf +import spock.lang.Specification + + +class IgnoreIfTest extends Specification { + + @IgnoreIf({System.getProperty("os.name").contains("windows")}) + def "I won't run on windows"() { + expect: + true + } + + @IgnoreIf({ os.isWindows() }) + def "I'm using Spock helper classes to run only on windows"() { + expect: + true + } + + +} diff --git a/testing-modules/groovy-spock/src/test/groovy/extensions/IgnoreRestTest.groovy b/testing-modules/groovy-spock/src/test/groovy/extensions/IgnoreRestTest.groovy new file mode 100644 index 0000000000..dead2c7393 --- /dev/null +++ b/testing-modules/groovy-spock/src/test/groovy/extensions/IgnoreRestTest.groovy @@ -0,0 +1,16 @@ +package extensions + +import spock.lang.IgnoreRest +import spock.lang.Specification + + +class IgnoreRestTest extends Specification { + + def "I won't run"() { } + + @IgnoreRest + def 'I will run'() { } + + def "I won't run too"() { } + +} diff --git a/testing-modules/groovy-spock/src/test/groovy/extensions/IgnoreTest.groovy b/testing-modules/groovy-spock/src/test/groovy/extensions/IgnoreTest.groovy new file mode 100644 index 0000000000..9af5708ae2 --- /dev/null +++ b/testing-modules/groovy-spock/src/test/groovy/extensions/IgnoreTest.groovy @@ -0,0 +1,20 @@ +package extensions + +import spock.lang.Ignore +import spock.lang.Specification + +@Ignore +class IgnoreTest extends Specification { + + @Ignore + def "I won't be executed"() { + expect: + true + } + + def 'Example test'() { + expect: + true + } + +} diff --git a/testing-modules/groovy-spock/src/test/groovy/extensions/IssueTest.groovy b/testing-modules/groovy-spock/src/test/groovy/extensions/IssueTest.groovy new file mode 100644 index 0000000000..56e0f09bf1 --- /dev/null +++ b/testing-modules/groovy-spock/src/test/groovy/extensions/IssueTest.groovy @@ -0,0 +1,25 @@ +package extensions + +import spock.lang.Issue +import spock.lang.Specification + + +class IssueTest extends Specification { + + + @Issue("http://jira.org/issues/LO-531") + def 'single issue'() { + } + + @Issue(["http://jira.org/issues/LO-531", "http://jira.org/issues/LO-123"]) + def 'multiple issues'() { + } + + @Issue("LO-1000") + def "I'm using Spock configuration file"() { + expect: + true + } + + +} diff --git a/testing-modules/groovy-spock/src/test/groovy/extensions/PendingFeatureTest.groovy b/testing-modules/groovy-spock/src/test/groovy/extensions/PendingFeatureTest.groovy new file mode 100644 index 0000000000..59bd99ceb8 --- /dev/null +++ b/testing-modules/groovy-spock/src/test/groovy/extensions/PendingFeatureTest.groovy @@ -0,0 +1,11 @@ +package extensions + +import spock.lang.PendingFeature + +class PendingFeatureTest { + + @PendingFeature + def 'test for not implemented yet feature'() { + + } +} diff --git a/testing-modules/groovy-spock/src/test/groovy/extensions/RequiresTest.groovy b/testing-modules/groovy-spock/src/test/groovy/extensions/RequiresTest.groovy new file mode 100644 index 0000000000..c384c3786b --- /dev/null +++ b/testing-modules/groovy-spock/src/test/groovy/extensions/RequiresTest.groovy @@ -0,0 +1,14 @@ +package extensions + +import spock.lang.Requires +import spock.lang.Specification + + +class RequiresTest extends Specification { + + @Requires({ System.getProperty("os.name").contains("windows") }) + def "I will run only on Windows"() { + expect: + true + } +} diff --git a/testing-modules/groovy-spock/src/test/groovy/extensions/RestoreSystemPropertiesTest.groovy b/testing-modules/groovy-spock/src/test/groovy/extensions/RestoreSystemPropertiesTest.groovy new file mode 100644 index 0000000000..824e88d84e --- /dev/null +++ b/testing-modules/groovy-spock/src/test/groovy/extensions/RestoreSystemPropertiesTest.groovy @@ -0,0 +1,18 @@ +package extensions + +import spock.lang.Specification +import spock.util.environment.RestoreSystemProperties + + +class RestoreSystemPropertiesTest extends Specification { + + @RestoreSystemProperties + def 'all environment variables will be saved before execution and restored after tests'() { + given: + System.setProperty('os.name', 'Mac OS') + + expect: + true + } + +} diff --git a/testing-modules/groovy-spock/src/test/groovy/extensions/RetryTest.groovy b/testing-modules/groovy-spock/src/test/groovy/extensions/RetryTest.groovy new file mode 100644 index 0000000000..a07ebae851 --- /dev/null +++ b/testing-modules/groovy-spock/src/test/groovy/extensions/RetryTest.groovy @@ -0,0 +1,20 @@ +package extensions + +import spock.lang.Retry +import spock.lang.Specification + +@Retry +class RetryTest extends Specification { + + @Retry + def 'I will retry three times'() { } + + @Retry(exceptions = [RuntimeException]) + def 'I will retry only on RuntimeException'() { } + + @Retry(condition = { failure.message.contains('error') }) + def 'I will retry with a specific message'() { } + + @Retry(delay = 1000) + def 'I will retry after 1000 millis'() { } +} diff --git a/testing-modules/groovy-spock/src/test/groovy/extensions/SeeTest.groovy b/testing-modules/groovy-spock/src/test/groovy/extensions/SeeTest.groovy new file mode 100644 index 0000000000..50212ad136 --- /dev/null +++ b/testing-modules/groovy-spock/src/test/groovy/extensions/SeeTest.groovy @@ -0,0 +1,20 @@ +package extensions + +import spock.lang.See +import spock.lang.Specification + + +class SeeTest extends Specification { + + + @See("https://example.org") + def 'Look at the reference'() { + + } + + @See(["https://example.org/first", "https://example.org/first"]) + def 'Look at the references'() { + + } + +} diff --git a/testing-modules/groovy-spock/src/test/groovy/extensions/StackTraceTest.groovy b/testing-modules/groovy-spock/src/test/groovy/extensions/StackTraceTest.groovy new file mode 100644 index 0000000000..00fa55e21e --- /dev/null +++ b/testing-modules/groovy-spock/src/test/groovy/extensions/StackTraceTest.groovy @@ -0,0 +1,13 @@ +package extensions + +import org.junit.Ignore +import spock.lang.Specification + + +class StackTraceTest extends Specification { + + def 'stkacktrace'() { +// expect: +// throw new RuntimeException("blabla") + } +} diff --git a/testing-modules/groovy-spock/src/test/groovy/extensions/StepwiseTest.groovy b/testing-modules/groovy-spock/src/test/groovy/extensions/StepwiseTest.groovy new file mode 100644 index 0000000000..1bf83ce84d --- /dev/null +++ b/testing-modules/groovy-spock/src/test/groovy/extensions/StepwiseTest.groovy @@ -0,0 +1,14 @@ +package extensions + +import spock.lang.Specification +import spock.lang.Stepwise + + +@Stepwise +class StepwiseTest extends Specification { + + def 'I will run as first'() { } + + def 'I will run as second'() { } + +} diff --git a/testing-modules/groovy-spock/src/test/groovy/extensions/SubjectTest.groovy b/testing-modules/groovy-spock/src/test/groovy/extensions/SubjectTest.groovy new file mode 100644 index 0000000000..8474df0f14 --- /dev/null +++ b/testing-modules/groovy-spock/src/test/groovy/extensions/SubjectTest.groovy @@ -0,0 +1,13 @@ +package extensions + +import mocks.ItemService +import spock.lang.Specification +import spock.lang.Subject + + +class SubjectTest extends Specification { + + @Subject + ItemService itemService // initialization here... + +} diff --git a/testing-modules/groovy-spock/src/test/groovy/extensions/TimeoutTest.groovy b/testing-modules/groovy-spock/src/test/groovy/extensions/TimeoutTest.groovy new file mode 100644 index 0000000000..0049d99806 --- /dev/null +++ b/testing-modules/groovy-spock/src/test/groovy/extensions/TimeoutTest.groovy @@ -0,0 +1,24 @@ +package extensions + +import spock.lang.Specification +import spock.lang.Timeout + +import java.util.concurrent.TimeUnit + +@Timeout(5) +class TimeoutTest extends Specification { + + @Timeout(1) + def 'I have one second to finish'() { + + } + + def 'I will have 5 seconds timeout'() {} + + @Timeout(value = 200, unit = TimeUnit.SECONDS) + def 'I will fail after 200 millis'() { + expect: + true + } + +} diff --git a/testing-modules/groovy-spock/src/test/resources/SpockConfig.groovy b/testing-modules/groovy-spock/src/test/resources/SpockConfig.groovy new file mode 100644 index 0000000000..4b017aeefc --- /dev/null +++ b/testing-modules/groovy-spock/src/test/resources/SpockConfig.groovy @@ -0,0 +1,30 @@ +import extensions.TimeoutTest +import spock.lang.Issue + +runner { + + if (System.getenv("FILTER_STACKTRACE") == null) { + filterStackTrace false + } + + report { + issueNamePrefix 'Bug ' + issueUrlPrefix 'http://jira.org/issues/' + } + + optimizeRunOrder true + +// exclude TimeoutTest +// exclude { +// baseClass TimeoutTest +// annotation Issue +// } + + report { + enabled true + logFileDir '.' + logFileName 'report.json' + logFileSuffix new Date().format('yyyy-MM-dd') + } + +} diff --git a/testing-modules/junit-5-configuration/README.md b/testing-modules/junit-5-configuration/README.md new file mode 100644 index 0000000000..c274391766 --- /dev/null +++ b/testing-modules/junit-5-configuration/README.md @@ -0,0 +1,2 @@ +### Relevant Articles: +- diff --git a/testing-modules/junit-5-configuration/pom.xml b/testing-modules/junit-5-configuration/pom.xml new file mode 100644 index 0000000000..aa488ebb8b --- /dev/null +++ b/testing-modules/junit-5-configuration/pom.xml @@ -0,0 +1,41 @@ + + + 4.0.0 + junit-5-configuration + 1.0-SNAPSHOT + junit-5-configuration + Intro to JUnit 5 configuration + + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + ../../ + + + + + org.junit.jupiter + junit-jupiter-params + ${junit.jupiter.version} + + + + + + + src/test/resources + true + + + + + + 5.3.1 + 1.2.0 + 5.2.0 + + + diff --git a/testing-modules/junit-5-configuration/src/test/java/com/baeldung/resourcedirectory/ReadResourceDirectoryUnitTest.java b/testing-modules/junit-5-configuration/src/test/java/com/baeldung/resourcedirectory/ReadResourceDirectoryUnitTest.java new file mode 100644 index 0000000000..20fa372abd --- /dev/null +++ b/testing-modules/junit-5-configuration/src/test/java/com/baeldung/resourcedirectory/ReadResourceDirectoryUnitTest.java @@ -0,0 +1,45 @@ +package com.baeldung.resourcedirectory; + +import org.junit.Assert; +import org.junit.Test; + +import java.io.File; +import java.nio.file.Path; +import java.nio.file.Paths; + +public class ReadResourceDirectoryUnitTest { + + @Test + public void givenResourcePath_whenReadAbsolutePathWithFile_thenAbsolutePathEndsWithDirectory() { + String path = "src/test/resources"; + + File file = new File(path); + String absolutePath = file.getAbsolutePath(); + + System.out.println(absolutePath); + Assert.assertTrue(absolutePath.endsWith("src/test/resources")); + } + + @Test + public void givenResourcePath_whenReadAbsolutePathWithPaths_thenAbsolutePathEndsWithDirectory() { + Path resourceDirectory = Paths.get("src", "test", "resources"); + + String absolutePath = resourceDirectory.toFile().getAbsolutePath(); + + System.out.println(absolutePath); + Assert.assertTrue(absolutePath.endsWith("src/test/resources")); + } + + @Test + public void givenResourceFile_whenReadResourceWithClassLoader_thenPathEndWithFilename() { + String resourceName = "example_resource.txt"; + + ClassLoader classLoader = getClass().getClassLoader(); + File file = new File(classLoader.getResource(resourceName).getFile()); + String absolutePath = file.getAbsolutePath(); + + System.out.println(absolutePath); + Assert.assertTrue(absolutePath.endsWith("/example_resource.txt")); + } + +} diff --git a/testing-modules/junit-5-configuration/src/test/resources/example_resource.txt b/testing-modules/junit-5-configuration/src/test/resources/example_resource.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/testing-modules/junit-5/README.md b/testing-modules/junit-5/README.md index d686396a1d..aafdd75e81 100644 --- a/testing-modules/junit-5/README.md +++ b/testing-modules/junit-5/README.md @@ -6,7 +6,7 @@ - [A Guide to JUnit 5 Extensions](http://www.baeldung.com/junit-5-extensions) - [Inject Parameters into JUnit Jupiter Unit Tests](http://www.baeldung.com/junit-5-parameters) - [Mockito and JUnit 5 – Using ExtendWith](http://www.baeldung.com/mockito-junit-5-extension) -- [JUnit 5 – @RunWith](http://www.baeldung.com/junit-5-runwith) +- [JUnit 5 @RunWith](http://www.baeldung.com/junit-5-runwith) - [JUnit 5 @Test Annotation](http://www.baeldung.com/junit-5-test-annotation) - [Assert an Exception is Thrown in JUnit 4 and 5](http://www.baeldung.com/junit-assert-exception) - [@Before vs @BeforeClass vs @BeforeEach vs @BeforeAll](http://www.baeldung.com/junit-before-beforeclass-beforeeach-beforeall) diff --git a/testing-modules/junit-5/pom.xml b/testing-modules/junit-5/pom.xml index a5a1ddaf0b..1d1b0bc574 100644 --- a/testing-modules/junit-5/pom.xml +++ b/testing-modules/junit-5/pom.xml @@ -103,13 +103,6 @@ maven-surefire-plugin ${maven-surefire-plugin.version} - - - org.junit.platform - junit-platform-surefire-provider - ${junit.platform.version} - - org.codehaus.mojo @@ -130,10 +123,10 @@ - 5.3.1 + 5.4.2 2.23.0 - 1.2.0 - 5.2.0 + 1.4.2 + 5.4.2 2.8.2 1.4.196 2.0.0-RC.1 diff --git a/testing-modules/junit-5/src/test/java/com/baeldung/parameterized/StringsUnitTest.java b/testing-modules/junit-5/src/test/java/com/baeldung/parameterized/StringsUnitTest.java index 7d02a5a74b..6aea7668f1 100644 --- a/testing-modules/junit-5/src/test/java/com/baeldung/parameterized/StringsUnitTest.java +++ b/testing-modules/junit-5/src/test/java/com/baeldung/parameterized/StringsUnitTest.java @@ -86,7 +86,30 @@ class StringsUnitTest { assertEquals(expected, actualValue); } + @ParameterizedTest + @NullSource + void isBlank_ShouldReturnTrueForNullInputs(String input) { + assertTrue(Strings.isBlank(input)); + } + @ParameterizedTest + @EmptySource + void isBlank_ShouldReturnTrueForEmptyStrings(String input) { + assertTrue(Strings.isBlank(input)); + } + + @ParameterizedTest + @NullAndEmptySource + void isBlank_ShouldReturnTrueForNullAndEmptyStrings(String input) { + assertTrue(Strings.isBlank(input)); + } + + @ParameterizedTest + @NullAndEmptySource + @ValueSource(strings = {" ", "\t", "\n"}) + void isBlank_ShouldReturnTrueForAllTypesOfBlankStrings(String input) { + assertTrue(Strings.isBlank(input)); + } private static Stream provideStringsForIsBlank() { return Stream.of( diff --git a/testing-modules/junit5-migration/README.md b/testing-modules/junit5-migration/README.md deleted file mode 100644 index 5fe7fc1f16..0000000000 --- a/testing-modules/junit5-migration/README.md +++ /dev/null @@ -1,3 +0,0 @@ -### Relevant Articles: -- [JUnit4 -> JUnit5 migration guide](http://www.baeldung.com/junit4-junit5-migration-guide) - diff --git a/testing-modules/load-testing-comparison/pom.xml b/testing-modules/load-testing-comparison/pom.xml index 63472d0467..44014e96ab 100644 --- a/testing-modules/load-testing-comparison/pom.xml +++ b/testing-modules/load-testing-comparison/pom.xml @@ -42,7 +42,7 @@ com.fasterxml.jackson.core jackson-databind - 2.9.4 + ${jackson.version} org.springframework.boot @@ -68,12 +68,12 @@ com.h2database h2 - 1.4.197 + ${h2.version} org.projectlombok lombok - 1.18.2 + ${lombok.version} compile @@ -145,6 +145,7 @@ 5.0 3.11 2.0.5.RELEASE + 1.4.197 \ No newline at end of file diff --git a/testing-modules/mocks/README.md b/testing-modules/mocks/README.md index 2b24ed8536..3cb20dcf92 100644 --- a/testing-modules/mocks/README.md +++ b/testing-modules/mocks/README.md @@ -1,8 +1,4 @@ ## Relevant articles: -- [JMockit Advanced Usage](http://www.baeldung.com/jmockit-advanced-usage) -- [A Guide to JMockit Expectations](http://www.baeldung.com/jmockit-expectations) -- [JMockit 101](http://www.baeldung.com/jmockit-101) -- [Mockito vs EasyMock vs JMockit](http://www.baeldung.com/mockito-vs-easymock-vs-jmockit) - [EasyMock Argument Matchers](http://www.baeldung.com/easymock-argument-matchers) - [Mock Static Method using JMockit](https://www.baeldung.com/jmockit-static-method) diff --git a/testing-modules/mocks/jmockit/README.md b/testing-modules/mocks/jmockit/README.md index 3063fdc31d..0e44b93d6e 100644 --- a/testing-modules/mocks/jmockit/README.md +++ b/testing-modules/mocks/jmockit/README.md @@ -6,5 +6,4 @@ ### Relevant Articles: - [JMockit 101](http://www.baeldung.com/jmockit-101) - [A Guide to JMockit Expectations](http://www.baeldung.com/jmockit-expectations) -- [JMockit Advanced Topics](http://www.baeldung.com/jmockit-advanced-topics) - [JMockit Advanced Usage](http://www.baeldung.com/jmockit-advanced-usage) diff --git a/testing-modules/parallel-tests-junit/math-test-functions/pom.xml b/testing-modules/parallel-tests-junit/math-test-functions/pom.xml index a3569714ef..cc9f27de05 100644 --- a/testing-modules/parallel-tests-junit/math-test-functions/pom.xml +++ b/testing-modules/parallel-tests-junit/math-test-functions/pom.xml @@ -18,7 +18,7 @@ junit junit - 4.12 + ${junit.version} test diff --git a/testing-modules/parallel-tests-junit/math-test-functions/src/test/java/com/baeldung/ArithmeticFunctionTest.java b/testing-modules/parallel-tests-junit/math-test-functions/src/test/java/com/baeldung/ArithmeticFunctionUnitTest.java similarity index 93% rename from testing-modules/parallel-tests-junit/math-test-functions/src/test/java/com/baeldung/ArithmeticFunctionTest.java rename to testing-modules/parallel-tests-junit/math-test-functions/src/test/java/com/baeldung/ArithmeticFunctionUnitTest.java index df0aa695fc..1f048b305f 100644 --- a/testing-modules/parallel-tests-junit/math-test-functions/src/test/java/com/baeldung/ArithmeticFunctionTest.java +++ b/testing-modules/parallel-tests-junit/math-test-functions/src/test/java/com/baeldung/ArithmeticFunctionUnitTest.java @@ -4,7 +4,7 @@ import static org.junit.Assert.assertEquals; import org.junit.Test; -public class ArithmeticFunctionTest { +public class ArithmeticFunctionUnitTest { @Test public void test_addingIntegers_returnsSum() { diff --git a/testing-modules/parallel-tests-junit/math-test-functions/src/test/java/com/baeldung/ComparisonFunctionTest.java b/testing-modules/parallel-tests-junit/math-test-functions/src/test/java/com/baeldung/ComparisonFunctionUnitTest.java similarity index 87% rename from testing-modules/parallel-tests-junit/math-test-functions/src/test/java/com/baeldung/ComparisonFunctionTest.java rename to testing-modules/parallel-tests-junit/math-test-functions/src/test/java/com/baeldung/ComparisonFunctionUnitTest.java index 4f72c87279..839b6c2cf3 100644 --- a/testing-modules/parallel-tests-junit/math-test-functions/src/test/java/com/baeldung/ComparisonFunctionTest.java +++ b/testing-modules/parallel-tests-junit/math-test-functions/src/test/java/com/baeldung/ComparisonFunctionUnitTest.java @@ -4,7 +4,7 @@ import static org.junit.Assert.assertEquals; import org.junit.Test; -public class ComparisonFunctionTest { +public class ComparisonFunctionUnitTest { @Test public void test_findMax() { diff --git a/testing-modules/parallel-tests-junit/math-test-functions/src/test/java/com/baeldung/FunctionTestSuite.java b/testing-modules/parallel-tests-junit/math-test-functions/src/test/java/com/baeldung/FunctionTestSuite.java index 4fe551b365..d12eab5c51 100644 --- a/testing-modules/parallel-tests-junit/math-test-functions/src/test/java/com/baeldung/FunctionTestSuite.java +++ b/testing-modules/parallel-tests-junit/math-test-functions/src/test/java/com/baeldung/FunctionTestSuite.java @@ -5,7 +5,7 @@ import org.junit.runners.Suite; import org.junit.runners.Suite.SuiteClasses; @RunWith(Suite.class) -@SuiteClasses({ ComparisonFunctionTest.class, ArithmeticFunctionTest.class }) +@SuiteClasses({ ComparisonFunctionUnitTest.class, ArithmeticFunctionUnitTest.class }) public class FunctionTestSuite { } diff --git a/testing-modules/parallel-tests-junit/pom.xml b/testing-modules/parallel-tests-junit/pom.xml index f400a5ae07..993974046c 100644 --- a/testing-modules/parallel-tests-junit/pom.xml +++ b/testing-modules/parallel-tests-junit/pom.xml @@ -6,6 +6,13 @@ 0.0.1-SNAPSHOT parallel-tests-junit pom + + + com.baeldung + parent-java + 0.0.1-SNAPSHOT + ../../parent-java + math-test-functions diff --git a/testing-modules/parallel-tests-junit/string-test-functions/pom.xml b/testing-modules/parallel-tests-junit/string-test-functions/pom.xml index 7fa09ff493..b0c0ed29fc 100644 --- a/testing-modules/parallel-tests-junit/string-test-functions/pom.xml +++ b/testing-modules/parallel-tests-junit/string-test-functions/pom.xml @@ -18,7 +18,7 @@ junit junit - 4.12 + ${junit.version} test diff --git a/testing-modules/parallel-tests-junit/string-test-functions/src/test/java/com/baeldung/StringFunctionTest.java b/testing-modules/parallel-tests-junit/string-test-functions/src/test/java/com/baeldung/StringFunctionUnitTest.java similarity index 88% rename from testing-modules/parallel-tests-junit/string-test-functions/src/test/java/com/baeldung/StringFunctionTest.java rename to testing-modules/parallel-tests-junit/string-test-functions/src/test/java/com/baeldung/StringFunctionUnitTest.java index 7f2bc5e5e7..685a33b084 100644 --- a/testing-modules/parallel-tests-junit/string-test-functions/src/test/java/com/baeldung/StringFunctionTest.java +++ b/testing-modules/parallel-tests-junit/string-test-functions/src/test/java/com/baeldung/StringFunctionUnitTest.java @@ -4,7 +4,7 @@ import static org.junit.Assert.assertEquals; import org.junit.Test; -public class StringFunctionTest { +public class StringFunctionUnitTest { @Test public void test_upperCase() { diff --git a/testing-modules/pom.xml b/testing-modules/pom.xml index 39047fb756..40ed63bc12 100644 --- a/testing-modules/pom.xml +++ b/testing-modules/pom.xml @@ -32,5 +32,6 @@ test-containers testing testng + junit-5-configuration diff --git a/testing-modules/rest-assured/README.md b/testing-modules/rest-assured/README.md index 50f36f61eb..d44fd08335 100644 --- a/testing-modules/rest-assured/README.md +++ b/testing-modules/rest-assured/README.md @@ -1,2 +1,4 @@ ###Relevant Articles: - [A Guide to REST-assured](http://www.baeldung.com/rest-assured-tutorial) +- [REST-assured Support for Spring MockMvc](https://www.baeldung.com/spring-mock-mvc-rest-assured) +- [Getting and Verifying Response Data with REST-assured](https://www.baeldung.com/rest-assured-response) diff --git a/testing-modules/rest-assured/pom.xml b/testing-modules/rest-assured/pom.xml index 687a9a2fe4..c528a34e21 100644 --- a/testing-modules/rest-assured/pom.xml +++ b/testing-modules/rest-assured/pom.xml @@ -8,16 +8,34 @@ com.baeldung - parent-java + parent-boot-2 0.0.1-SNAPSHOT - ../../parent-java + ../../parent-boot-2 + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-json + + + org.springframework.boot + spring-boot-starter-test + test + + + com.google.guava + guava + ${guava.version} + javax.servlet javax.servlet-api - ${javax.servlet-api.version} javax.servlet @@ -27,49 +45,40 @@ org.eclipse.jetty jetty-security - ${jetty.version} org.eclipse.jetty jetty-servlet - ${jetty.version} org.eclipse.jetty jetty-servlets - ${jetty.version} org.eclipse.jetty jetty-io - ${jetty.version} org.eclipse.jetty jetty-http - ${jetty.version} org.eclipse.jetty jetty-server - ${jetty.version} org.eclipse.jetty jetty-util - ${jetty.version} org.apache.httpcomponents httpcore - ${httpcore.version} org.apache.commons commons-lang3 - ${commons-lang3.version} @@ -93,18 +102,15 @@ joda-time joda-time - ${joda-time.version} com.fasterxml.jackson.core jackson-annotations - ${jackson.version} com.fasterxml.jackson.core jackson-databind - ${jackson.version} @@ -128,7 +134,6 @@ org.apache.httpcomponents httpclient - ${httpclient.version} @@ -142,17 +147,6 @@ wiremock ${wiremock.version} - - io.rest-assured - rest-assured - ${rest-assured.version} - test - - - io.rest-assured - json-schema-validator - ${rest-assured-json-schema-validator.version} - com.github.fge json-schema-validator @@ -168,9 +162,38 @@ commons-collections ${commons-collections.version} + + + org.springframework.boot + spring-boot-starter-security + + + + + io.rest-assured + rest-assured + test + + + io.rest-assured + spring-mock-mvc + test + + + io.rest-assured + json-schema-validator + test + + + com.github.scribejava + scribejava-apis + ${scribejava.version} + test + + 18.0 2.9.7 1.8 19.0 @@ -199,6 +222,8 @@ 3.0.1 3.0.1 + + 2.5.3 diff --git a/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/Application.java b/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/Application.java new file mode 100644 index 0000000000..8b53a9c63d --- /dev/null +++ b/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/Application.java @@ -0,0 +1,13 @@ +package com.baeldung.restassured; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} diff --git a/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/controller/AppController.java b/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/controller/AppController.java new file mode 100644 index 0000000000..d68ebf4b03 --- /dev/null +++ b/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/controller/AppController.java @@ -0,0 +1,100 @@ +package com.baeldung.restassured.controller; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.util.Set; +import java.util.UUID; + +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.io.InputStreamResource; +import org.springframework.core.io.Resource; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +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; + +import com.baeldung.restassured.model.Movie; +import com.baeldung.restassured.service.AppService; + +@RestController +public class AppController { + + @Autowired + AppService appService; + + @GetMapping("/movies") + public ResponseEntity getMovies() { + + Set result = appService.getAll(); + + return ResponseEntity.ok() + .body(result); + } + + @PostMapping("/movie") + @ResponseStatus(HttpStatus.CREATED) + public Movie addMovie(@RequestBody Movie movie) { + + appService.add(movie); + return movie; + } + + @GetMapping("/movie/{id}") + public ResponseEntity getMovie(@PathVariable int id) { + + Movie movie = appService.findMovie(id); + if (movie == null) { + return ResponseEntity.badRequest() + .body("Invalid movie id"); + } + + return ResponseEntity.ok(movie); + } + + @GetMapping("/welcome") + public ResponseEntity welcome(HttpServletResponse response) { + + HttpHeaders headers = new HttpHeaders(); + headers.add(HttpHeaders.CONTENT_TYPE, "application/json; charset=UTF-8"); + headers.add("sessionId", UUID.randomUUID() + .toString()); + + Cookie cookie = new Cookie("token", "some-token"); + cookie.setDomain("localhost"); + + response.addCookie(cookie); + + return ResponseEntity.noContent() + .headers(headers) + .build(); + } + + @GetMapping("/download/{id}") + public ResponseEntity getFile(@PathVariable int id) throws FileNotFoundException { + + File file = appService.getFile(id); + + if (file == null) { + return ResponseEntity.notFound() + .build(); + } + + InputStreamResource resource = new InputStreamResource(new FileInputStream(file)); + + return ResponseEntity.ok() + .contentLength(file.length()) + .contentType(MediaType.parseMediaType("application/octet-stream")) + .body(resource); + } + +} diff --git a/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/learner/Course.java b/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/learner/Course.java new file mode 100644 index 0000000000..ac958b3239 --- /dev/null +++ b/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/learner/Course.java @@ -0,0 +1,17 @@ +package com.baeldung.restassured.learner; + +class Course { + + private String code; + + public Course() { + } + + Course(String code) { + this.code = code; + } + + String getCode() { + return code; + } +} diff --git a/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/learner/CourseController.java b/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/learner/CourseController.java new file mode 100644 index 0000000000..f4a3f56608 --- /dev/null +++ b/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/learner/CourseController.java @@ -0,0 +1,31 @@ +package com.baeldung.restassured.learner; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Collection; + +import static org.springframework.http.MediaType.APPLICATION_JSON_UTF8_VALUE; + +@RestController +@RequestMapping(path = "/courses") +public class CourseController { + + private final CourseService courseService; + + public CourseController(CourseService courseService) { + this.courseService = courseService; + } + + @GetMapping(produces = APPLICATION_JSON_UTF8_VALUE) + public Collection getCourses() { + return courseService.getCourses(); + } + + @GetMapping(path = "/{code}", produces = APPLICATION_JSON_UTF8_VALUE) + public Course getCourse(@PathVariable String code) { + return courseService.getCourse(code); + } +} diff --git a/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/learner/CourseControllerExceptionHandler.java b/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/learner/CourseControllerExceptionHandler.java new file mode 100644 index 0000000000..b17e95c31c --- /dev/null +++ b/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/learner/CourseControllerExceptionHandler.java @@ -0,0 +1,18 @@ +package com.baeldung.restassured.learner; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; + +@ControllerAdvice(assignableTypes = CourseController.class) +public class CourseControllerExceptionHandler extends ResponseEntityExceptionHandler { + + @ResponseStatus(HttpStatus.NOT_FOUND) + @ExceptionHandler(CourseNotFoundException.class) + @SuppressWarnings("ThrowablePrintedToSystemOut") + public void handleCourseNotFoundException(CourseNotFoundException cnfe) { + System.out.println(cnfe); + } +} diff --git a/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/learner/CourseNotFoundException.java b/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/learner/CourseNotFoundException.java new file mode 100644 index 0000000000..dc1a3f796d --- /dev/null +++ b/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/learner/CourseNotFoundException.java @@ -0,0 +1,8 @@ +package com.baeldung.restassured.learner; + +class CourseNotFoundException extends RuntimeException { + + CourseNotFoundException(String code) { + super(code); + } +} diff --git a/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/learner/CourseService.java b/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/learner/CourseService.java new file mode 100644 index 0000000000..11508ab9ba --- /dev/null +++ b/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/learner/CourseService.java @@ -0,0 +1,27 @@ +package com.baeldung.restassured.learner; + +import org.springframework.stereotype.Service; + +import java.util.Collection; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; + +@Service +class CourseService { + + private static final Map COURSE_MAP = new ConcurrentHashMap<>(); + + static { + Course wizardry = new Course("Wizardry"); + COURSE_MAP.put(wizardry.getCode(), wizardry); + } + + Collection getCourses() { + return COURSE_MAP.values(); + } + + Course getCourse(String code) { + return Optional.ofNullable(COURSE_MAP.get(code)).orElseThrow(() -> new CourseNotFoundException(code)); + } +} diff --git a/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/model/Movie.java b/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/model/Movie.java new file mode 100644 index 0000000000..00a446fc65 --- /dev/null +++ b/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/model/Movie.java @@ -0,0 +1,58 @@ +package com.baeldung.restassured.model; + +public class Movie { + + private Integer id; + + private String name; + + private String synopsis; + + public Movie() { + } + + public Movie(Integer id, String name, String synopsis) { + super(); + this.id = id; + this.name = name; + this.synopsis = synopsis; + } + + public Integer getId() { + return id; + } + + public String getName() { + return name; + } + + public String getSynopsis() { + return synopsis; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((id == null) ? 0 : id.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Movie other = (Movie) obj; + if (id == null) { + if (other.id != null) + return false; + } else if (!id.equals(other.id)) + return false; + return true; + } + +} diff --git a/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/service/AppService.java b/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/service/AppService.java new file mode 100644 index 0000000000..15685f2924 --- /dev/null +++ b/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/service/AppService.java @@ -0,0 +1,45 @@ +package com.baeldung.restassured.service; + +import java.io.File; +import java.io.IOException; +import java.util.HashSet; +import java.util.Set; + +import org.springframework.core.io.ClassPathResource; +import org.springframework.stereotype.Service; + +import com.baeldung.restassured.model.Movie; + +@Service +public class AppService { + + private Set movieSet = new HashSet<>(); + + public Set getAll() { + return movieSet; + } + + public void add(Movie movie) { + movieSet.add(movie); + } + + public Movie findMovie(int id) { + return movieSet.stream() + .filter(movie -> movie.getId() + .equals(id)) + .findFirst() + .orElse(null); + } + + public File getFile(int id) { + File file = null; + try { + file = new ClassPathResource(String.valueOf(id)).getFile(); + } catch (IOException e) { + e.printStackTrace(); + } + + return file; + } + +} diff --git a/testing-modules/rest-assured/src/main/resources/1 b/testing-modules/rest-assured/src/main/resources/1 new file mode 100644 index 0000000000..49351eb5b7 --- /dev/null +++ b/testing-modules/rest-assured/src/main/resources/1 @@ -0,0 +1 @@ +File 1 \ No newline at end of file diff --git a/testing-modules/rest-assured/src/main/resources/2 b/testing-modules/rest-assured/src/main/resources/2 new file mode 100644 index 0000000000..9fbb45ed08 --- /dev/null +++ b/testing-modules/rest-assured/src/main/resources/2 @@ -0,0 +1 @@ +File 2 \ No newline at end of file diff --git a/testing-modules/rest-assured/src/test/java/com/baeldung/restassured/authentication/BasicAuthenticationLiveTest.java b/testing-modules/rest-assured/src/test/java/com/baeldung/restassured/authentication/BasicAuthenticationLiveTest.java new file mode 100644 index 0000000000..aff765dfa3 --- /dev/null +++ b/testing-modules/rest-assured/src/test/java/com/baeldung/restassured/authentication/BasicAuthenticationLiveTest.java @@ -0,0 +1,38 @@ +package com.baeldung.restassured.authentication; + +import static io.restassured.RestAssured.get; +import static io.restassured.RestAssured.given; + +import org.junit.jupiter.api.Test; +import org.springframework.http.HttpStatus; + +/** + * For this Live Test we need: + * * a running instance of the service located in the spring-security-rest-basic-auth module. + * @see spring-security-rest-basic-auth module + * + */ +public class BasicAuthenticationLiveTest { + + private static final String USER = "user1"; + private static final String PASSWORD = "user1Pass"; + private static final String SVC_URL = "http://localhost:8080/spring-security-rest-basic-auth/api/foos/1"; + + @Test + public void givenNoAuthentication_whenRequestSecuredResource_thenUnauthorizedResponse() { + get(SVC_URL).then() + .assertThat() + .statusCode(HttpStatus.UNAUTHORIZED.value()); + } + + @Test + public void givenBasicAuthentication_whenRequestSecuredResource_thenResourceRetrieved() { + given().auth() + .basic(USER, PASSWORD) + .when() + .get(SVC_URL) + .then() + .assertThat() + .statusCode(HttpStatus.OK.value()); + } +} diff --git a/testing-modules/rest-assured/src/test/java/com/baeldung/restassured/authentication/BasicPreemtiveAuthenticationLiveTest.java b/testing-modules/rest-assured/src/test/java/com/baeldung/restassured/authentication/BasicPreemtiveAuthenticationLiveTest.java new file mode 100644 index 0000000000..02138f22e3 --- /dev/null +++ b/testing-modules/rest-assured/src/test/java/com/baeldung/restassured/authentication/BasicPreemtiveAuthenticationLiveTest.java @@ -0,0 +1,56 @@ +package com.baeldung.restassured.authentication; + +import static io.restassured.RestAssured.get; +import static io.restassured.RestAssured.given; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.is; + +import org.junit.jupiter.api.Test; +import org.springframework.http.HttpStatus; + +/** + * For this Live Test we need: + * * a running instance of the service located in the spring-boot-admin/spring-boot-admin-server module. + * @see spring-boot-admin/spring-boot-admin-server module + * + */ +public class BasicPreemtiveAuthenticationLiveTest { + + private static final String USER = "admin"; + private static final String PASSWORD = "admin"; + private static final String SVC_URL = "http://localhost:8080/api/applications/"; + + @Test + public void givenNoAuthentication_whenRequestSecuredResource_thenUnauthorizedResponse() { + get(SVC_URL).then() + .assertThat() + .statusCode(HttpStatus.OK.value()) + .content(containsString("spring-security-mvc-digest-auth module + * + */ +public class DigestAuthenticationLiveTest { + + private static final String USER = "user1"; + private static final String PASSWORD = "user1Pass"; + private static final String SVC_URL = "http://localhost:8080/spring-security-mvc-digest-auth/homepage.html"; + + @Test + public void givenNoAuthentication_whenRequestSecuredResource_thenUnauthorizedResponse() { + get(SVC_URL).then() + .assertThat() + .statusCode(HttpStatus.UNAUTHORIZED.value()); + } + + @Test + public void givenFormAuthentication_whenRequestSecuredResource_thenResourceRetrieved() { + given().auth() + .digest(USER, PASSWORD) + .when() + .get(SVC_URL) + .then() + .assertThat() + .statusCode(HttpStatus.OK.value()) + .content(containsString("This is the body of the sample view")); + } +} diff --git a/testing-modules/rest-assured/src/test/java/com/baeldung/restassured/authentication/FormAuthenticationLiveTest.java b/testing-modules/rest-assured/src/test/java/com/baeldung/restassured/authentication/FormAuthenticationLiveTest.java new file mode 100644 index 0000000000..66ae9fb162 --- /dev/null +++ b/testing-modules/rest-assured/src/test/java/com/baeldung/restassured/authentication/FormAuthenticationLiveTest.java @@ -0,0 +1,57 @@ +package com.baeldung.restassured.authentication; + +import static io.restassured.RestAssured.get; +import static io.restassured.RestAssured.given; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.isEmptyString; + +import org.junit.jupiter.api.Test; +import org.springframework.http.HttpStatus; + +import io.restassured.authentication.FormAuthConfig; + +/** + * For this Live Test we need: + * * a running instance of the service located in the spring-security-mvc-login module. + * @see spring-security-mvc-login module + * + */ +public class FormAuthenticationLiveTest { + + private static final String USER = "user1"; + private static final String PASSWORD = "user1Pass"; + private static final String SVC_URL = "http://localhost:8080/spring-security-mvc-login/secured"; + + @Test + public void givenNoAuthentication_whenRequestSecuredResource_thenLoginFormResponse() { + get(SVC_URL).then() + .assertThat() + .statusCode(HttpStatus.OK.value()) + .content(containsString("spring-boot-admin/spring-boot-admin-server module + * + */ +public class FormAutoconfAuthenticationLiveTest { + + private static final String USER = "admin"; + private static final String PASSWORD = "admin"; + private static final String SVC_URL = "http://localhost:8080/ger1/api/applications/"; + + @Test + public void givenNoAuthentication_whenRequestSecuredResource_thenUnauthorizedResponse() { + get(SVC_URL).then() + .assertThat() + .statusCode(HttpStatus.OK.value()) + .content(containsString("spring-security-oauth/oauth-authorization-server module + * + * * a running instance of the service located in the spring-security-oauth repo - oauth-resource-server-1 module. + * @see spring-security-oauth/oauth-resource-server-1 module + * + */ +public class OAuth2AuthenticationLiveTest { + + private static final String USER = "john"; + private static final String PASSWORD = "123"; + private static final String CLIENT_ID = "fooClientIdPassword"; + private static final String SECRET = "secret"; + private static final String AUTH_SVC_TOKEN_URL = "http://localhost:8081/spring-security-oauth-server/oauth/token"; + private static final String RESOURCE_SVC_URL = "http://localhost:8082/spring-security-oauth-resource/foos/1"; + + @Test + public void givenNoAuthentication_whenRequestSecuredResource_thenUnauthorizedResponse() { + get(RESOURCE_SVC_URL).then() + .assertThat() + .statusCode(HttpStatus.UNAUTHORIZED.value()); + } + + @Test + public void givenAccessTokenAuthentication_whenRequestSecuredResource_thenResourceRetrieved() { + String accessToken = given().auth() + .basic(CLIENT_ID, SECRET) + .formParam("grant_type", "password") + .formParam("username", USER) + .formParam("password", PASSWORD) + .formParam("scope", "read foo") + .when() + .post(AUTH_SVC_TOKEN_URL) + .then() + .assertThat() + .statusCode(HttpStatus.OK.value()) + .extract() + .path("access_token"); + + given().auth() + .oauth2(accessToken) + .when() + .get(RESOURCE_SVC_URL) + .then() + .assertThat() + .statusCode(HttpStatus.OK.value()) + .body("$", hasKey("id")) + .body("$", hasKey("name")); + } +} diff --git a/testing-modules/rest-assured/src/test/java/com/baeldung/restassured/authentication/OAuthAuthenticationLiveTest.java b/testing-modules/rest-assured/src/test/java/com/baeldung/restassured/authentication/OAuthAuthenticationLiveTest.java new file mode 100644 index 0000000000..c720bc04e4 --- /dev/null +++ b/testing-modules/rest-assured/src/test/java/com/baeldung/restassured/authentication/OAuthAuthenticationLiveTest.java @@ -0,0 +1,53 @@ +package com.baeldung.restassured.authentication; + +import static io.restassured.RestAssured.get; +import static io.restassured.RestAssured.given; +import static org.hamcrest.Matchers.hasKey; + +import org.junit.jupiter.api.Test; +import org.springframework.http.HttpStatus; + +import io.restassured.http.ContentType; + +/** + * For this Live Test we need to obtain a valid Access Token and Token Secret: + * * start spring-mvc-simple application in debug mode + * @see spring-mvc-simple module + * * calling localhost:8080/spring-mvc-simple/twitter/authorization/ using the browser + * * debug the callback function where we can obtain the fields + */ +public class OAuthAuthenticationLiveTest { + + // We can obtain these two from the spring-mvc-simple / TwitterController class + private static final String OAUTH_API_KEY = "PSRszoHhRDVhyo2RIkThEbWko"; + private static final String OAUTH_API_SECRET = "prpJbz03DcGRN46sb4ucdSYtVxG8unUKhcnu3an5ItXbEOuenL"; + private static final String TWITTER_ENDPOINT = "https://api.twitter.com/1.1/account/settings.json"; + /* We can obtain the following by: + * - starting the spring-mvc-simple application + * - calling localhost:8080/spring-mvc-simple/twitter/authorization/ + * - debugging the callback function */ + private static final String ACCESS_TOKEN = "..."; + private static final String TOKEN_SECRET = "..."; + + @Test + public void givenNoAuthentication_whenRequestSecuredResource_thenUnauthorizedResponse() { + get(TWITTER_ENDPOINT).then() + .assertThat() + .statusCode(HttpStatus.BAD_REQUEST.value()); + } + + @Test + public void givenAccessTokenAuthentication_whenRequestSecuredResource_thenResourceIsRequested() { + given().accept(ContentType.JSON) + .auth() + .oauth(OAUTH_API_KEY, OAUTH_API_SECRET, ACCESS_TOKEN, TOKEN_SECRET) + .when() + .get(TWITTER_ENDPOINT) + .then() + .assertThat() + .statusCode(HttpStatus.OK.value()) + .body("$", hasKey("geo_enabled")) + .body("$", hasKey("language")); + } + +} diff --git a/testing-modules/rest-assured/src/test/java/com/baeldung/restassured/controller/AppControllerIntegrationTest.java b/testing-modules/rest-assured/src/test/java/com/baeldung/restassured/controller/AppControllerIntegrationTest.java new file mode 100644 index 0000000000..a55c0a69e4 --- /dev/null +++ b/testing-modules/rest-assured/src/test/java/com/baeldung/restassured/controller/AppControllerIntegrationTest.java @@ -0,0 +1,149 @@ +package com.baeldung.restassured.controller; + +import static io.restassured.RestAssured.get; +import static io.restassured.RestAssured.given; +import static org.assertj.core.api.Assertions.assertThat; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.mockito.Mockito.when; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import javax.annotation.PostConstruct; + +import org.junit.jupiter.api.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.core.io.ClassPathResource; +import org.springframework.http.HttpStatus; +import org.springframework.test.context.junit4.SpringRunner; + +import com.baeldung.restassured.model.Movie; +import com.baeldung.restassured.service.AppService; + +import io.restassured.response.Response; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) +public class AppControllerIntegrationTest { + + @LocalServerPort + private int port; + + private String uri; + + @PostConstruct + public void init() { + uri = "http://localhost:" + port; + } + + @MockBean + AppService appService; + + @Test + public void givenMovieId_whenMakingGetRequestToMovieEndpoint_thenReturnMovie() { + + Movie testMovie = new Movie(1, "movie1", "summary1"); + when(appService.findMovie(1)).thenReturn(testMovie); + + get(uri + "/movie/" + testMovie.getId()).then() + .assertThat() + .statusCode(HttpStatus.OK.value()) + .body("id", equalTo(testMovie.getId())) + .body("name", equalTo(testMovie.getName())) + .body("synopsis", notNullValue()); + + Movie result = get(uri + "/movie/" + testMovie.getId()).then() + .assertThat() + .statusCode(HttpStatus.OK.value()) + .extract() + .as(Movie.class); + assertThat(result).isEqualTo(testMovie); + + String responseString = get(uri + "/movie/" + testMovie.getId()).then() + .assertThat() + .statusCode(HttpStatus.OK.value()) + .extract() + .asString(); + assertThat(responseString).isNotEmpty(); + } + + @Test + public void whenCallingMoviesEndpoint_thenReturnAllMovies() { + + Set movieSet = new HashSet<>(); + movieSet.add(new Movie(1, "movie1", "summary1")); + movieSet.add(new Movie(2, "movie2", "summary2")); + when(appService.getAll()).thenReturn(movieSet); + + get(uri + "/movies").then() + .statusCode(HttpStatus.OK.value()) + .assertThat() + .body("size()", is(2)); + + Movie[] movies = get(uri + "/movies").then() + .statusCode(200) + .extract() + .as(Movie[].class); + assertThat(movies.length).isEqualTo(2); + } + + @Test + public void givenMovie_whenMakingPostRequestToMovieEndpoint_thenCorrect() { + + Map request = new HashMap<>(); + request.put("id", "11"); + request.put("name", "movie1"); + request.put("synopsis", "summary1"); + + int movieId = given().contentType("application/json") + .body(request) + .when() + .post(uri + "/movie") + .then() + .assertThat() + .statusCode(HttpStatus.CREATED.value()) + .extract() + .path("id"); + assertThat(movieId).isEqualTo(11); + + } + + @Test + public void whenCallingWelcomeEndpoint_thenCorrect() { + + get(uri + "/welcome").then() + .assertThat() + .header("sessionId", notNullValue()) + .cookie("token", notNullValue()); + + Response response = get(uri + "/welcome"); + + String headerName = response.getHeader("sessionId"); + String cookieValue = response.getCookie("token"); + assertThat(headerName).isNotBlank(); + assertThat(cookieValue).isNotBlank(); + } + + @Test + public void givenId_whenCallingDowloadEndpoint_thenCorrect() throws IOException { + + File file = new ClassPathResource("test.txt").getFile(); + long fileSize = file.length(); + when(appService.getFile(1)).thenReturn(file); + + byte[] result = get(uri + "/download/1").asByteArray(); + + assertThat(result.length).isEqualTo(fileSize); + } + +} diff --git a/testing-modules/rest-assured/src/test/java/com/baeldung/restassured/learner/CourseControllerIntegrationTest.java b/testing-modules/rest-assured/src/test/java/com/baeldung/restassured/learner/CourseControllerIntegrationTest.java new file mode 100644 index 0000000000..5e36cd169b --- /dev/null +++ b/testing-modules/rest-assured/src/test/java/com/baeldung/restassured/learner/CourseControllerIntegrationTest.java @@ -0,0 +1,40 @@ +package com.baeldung.restassured.learner; + +import static io.restassured.module.mockmvc.RestAssuredMockMvc.given; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; +import static org.springframework.http.HttpStatus.NOT_FOUND; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.web.context.WebApplicationContext; + +import io.restassured.module.mockmvc.RestAssuredMockMvc; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = RANDOM_PORT) +public class CourseControllerIntegrationTest { + + @Autowired + private WebApplicationContext webApplicationContext; + + @Before + public void initialiseRestAssuredMockMvcWebApplicationContext() { + RestAssuredMockMvc.webAppContextSetup(webApplicationContext); + } + + @Test + public void givenNoMatchingCourseCodeWhenGetCourseThenRespondWithStatusNotFound() { + String nonMatchingCourseCode = "nonMatchingCourseCode"; + + given() + .when() + .get("/courses/" + nonMatchingCourseCode) + .then() + .log().ifValidationFails() + .statusCode(NOT_FOUND.value()); + } +} diff --git a/testing-modules/rest-assured/src/test/java/com/baeldung/restassured/learner/CourseControllerUnitTest.java b/testing-modules/rest-assured/src/test/java/com/baeldung/restassured/learner/CourseControllerUnitTest.java new file mode 100644 index 0000000000..2a795e2b0b --- /dev/null +++ b/testing-modules/rest-assured/src/test/java/com/baeldung/restassured/learner/CourseControllerUnitTest.java @@ -0,0 +1,63 @@ +package com.baeldung.restassured.learner; + +import io.restassured.module.mockmvc.RestAssuredMockMvc; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import java.util.Collections; + +import static io.restassured.http.ContentType.JSON; +import static io.restassured.module.mockmvc.RestAssuredMockMvc.given; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; +import static org.mockito.Mockito.when; +import static org.springframework.http.HttpStatus.NOT_FOUND; +import static org.springframework.http.HttpStatus.OK; + +@RunWith(MockitoJUnitRunner.class) +public class CourseControllerUnitTest { + + @Mock + private CourseService courseService; + @InjectMocks + private CourseController courseController; + @InjectMocks + private CourseControllerExceptionHandler courseControllerExceptionHandler; + + @Before + public void initialiseRestAssuredMockMvcStandalone() { + RestAssuredMockMvc.standaloneSetup(courseController, courseControllerExceptionHandler); + } + + @Test + public void givenNoExistingCoursesWhenGetCoursesThenRespondWithStatusOkAndEmptyArray() { + when(courseService.getCourses()).thenReturn(Collections.emptyList()); + + given() + .when() + .get("/courses") + .then() + .log().ifValidationFails() + .statusCode(OK.value()) + .contentType(JSON) + .body(is(equalTo("[]"))); + } + + @Test + public void givenNoMatchingCoursesWhenGetCoursesThenRespondWithStatusNotFound() { + String nonMatchingCourseCode = "nonMatchingCourseCode"; + + when(courseService.getCourse(nonMatchingCourseCode)).thenThrow(new CourseNotFoundException(nonMatchingCourseCode)); + + given() + .when() + .get("/courses/" + nonMatchingCourseCode) + .then() + .log().ifValidationFails() + .statusCode(NOT_FOUND.value()); + } +} diff --git a/testing-modules/rest-assured/src/test/resources/test.txt b/testing-modules/rest-assured/src/test/resources/test.txt new file mode 100644 index 0000000000..84362ca046 --- /dev/null +++ b/testing-modules/rest-assured/src/test/resources/test.txt @@ -0,0 +1 @@ +Test file \ No newline at end of file diff --git a/testing-modules/rest-testing/README.md b/testing-modules/rest-testing/README.md index 25e036ba5d..2d366bd550 100644 --- a/testing-modules/rest-testing/README.md +++ b/testing-modules/rest-testing/README.md @@ -6,9 +6,8 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring ### Relevant Articles: -- [Test a REST API with Java](http://www.baeldung.com/integration-testing-a-rest-api) - [Introduction to WireMock](http://www.baeldung.com/introduction-to-wiremock) -- [Using WireMock Scenarios](http://www.baeldung.com/using-wiremock-scenarios) +- [Using WireMock Scenarios](https://www.baeldung.com/wiremock-scenarios) - [REST API Testing with Cucumber](http://www.baeldung.com/cucumber-rest-api-testing) - [Testing a REST API with JBehave](http://www.baeldung.com/jbehave-rest-testing) - [REST API Testing with Karate](http://www.baeldung.com/karate-rest-api-testing) diff --git a/testing-modules/testing/README.md b/testing-modules/testing/README.md index e96b26ab41..4a7829e867 100644 --- a/testing-modules/testing/README.md +++ b/testing-modules/testing/README.md @@ -18,6 +18,6 @@ - [Custom JUnit 4 Test Runners](http://www.baeldung.com/junit-4-custom-runners) - [Guide to JSpec](http://www.baeldung.com/jspec) - [Custom Assertions with AssertJ](http://www.baeldung.com/assertj-custom-assertion) -- [Using Conditions with AssertJ](http://www.baeldung.com/assertj-conditions) -- [Guide to JavaFaker](https://www.baeldung.com/java-faker) +- [Using Conditions with AssertJ Assertions](http://www.baeldung.com/assertj-conditions) +- [A Guide to JavaFaker](https://www.baeldung.com/java-faker) - [Running JUnit Tests Programmatically, from a Java Application](https://www.baeldung.com/junit-tests-run-programmatically-from-java) diff --git a/testing-modules/testing/pom.xml b/testing-modules/testing/pom.xml index 2e783b2116..ccfa1070d1 100644 --- a/testing-modules/testing/pom.xml +++ b/testing-modules/testing/pom.xml @@ -91,7 +91,7 @@ com.github.javafaker javafaker - 0.15 + ${javafaker.version} @@ -177,6 +177,7 @@ 0.4 3.0.0 1.5 + 0.15 diff --git a/twilio/pom.xml b/twilio/pom.xml index 81fbf8ab20..266ac45c92 100644 --- a/twilio/pom.xml +++ b/twilio/pom.xml @@ -16,8 +16,12 @@ com.twilio.sdk twilio - 7.20.0 + ${twilio.version} + + 7.20.0 + + diff --git a/vaadin/pom.xml b/vaadin/pom.xml index d24b3dff1b..ec69e240e2 100644 --- a/vaadin/pom.xml +++ b/vaadin/pom.xml @@ -33,22 +33,6 @@ javax.servlet-api provided
- - com.vaadin - vaadin-server - - - com.vaadin - vaadin-push - - - com.vaadin - vaadin-client-compiled - - - com.vaadin - vaadin-themes - org.springframework.boot @@ -86,17 +70,6 @@ com.vaadin vaadin-maven-plugin ${vaadin.plugin.version} - - - - update-theme - update-widgetset - compile - - compile-theme - - - org.apache.maven.plugins @@ -183,9 +156,9 @@ 3.0.1 - 7.7.10 - 8.0.6 - 10.0.1 + 10.0.11 + 10.0.11 + 10.0.11 9.3.9.v20160517 UTF-8 1.8 diff --git a/vaadin/src/main/java/com/baeldung/introduction/VaadinUI.java b/vaadin/src/main/java/com/baeldung/introduction/VaadinUI.java deleted file mode 100644 index 1b3733ad74..0000000000 --- a/vaadin/src/main/java/com/baeldung/introduction/VaadinUI.java +++ /dev/null @@ -1,281 +0,0 @@ -package com.baeldung.introduction; - -import java.time.Instant; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - -import javax.servlet.annotation.WebServlet; - -import com.vaadin.annotations.Push; -import com.vaadin.annotations.Theme; -import com.vaadin.annotations.VaadinServletConfiguration; -import com.vaadin.data.Validator.InvalidValueException; -import com.vaadin.data.fieldgroup.BeanFieldGroup; -import com.vaadin.data.validator.StringLengthValidator; -import com.vaadin.server.ExternalResource; -import com.vaadin.server.FontAwesome; -import com.vaadin.server.VaadinRequest; -import com.vaadin.server.VaadinServlet; -import com.vaadin.ui.Button; -import com.vaadin.ui.CheckBox; -import com.vaadin.ui.ComboBox; -import com.vaadin.ui.DateField; -import com.vaadin.ui.FormLayout; -import com.vaadin.ui.Grid; -import com.vaadin.ui.GridLayout; -import com.vaadin.ui.HorizontalLayout; -import com.vaadin.ui.InlineDateField; -import com.vaadin.ui.Label; -import com.vaadin.ui.Link; -import com.vaadin.ui.ListSelect; -import com.vaadin.ui.NativeButton; -import com.vaadin.ui.NativeSelect; -import com.vaadin.ui.Panel; -import com.vaadin.ui.PasswordField; -import com.vaadin.ui.RichTextArea; -import com.vaadin.ui.TextArea; -import com.vaadin.ui.TextField; -import com.vaadin.ui.TwinColSelect; -import com.vaadin.ui.UI; -import com.vaadin.ui.VerticalLayout; - -@SuppressWarnings("serial") -@Push -@Theme("mytheme") -public class VaadinUI extends UI { - - private Label currentTime; - - @SuppressWarnings({ "rawtypes", "unchecked" }) - @Override - protected void init(VaadinRequest vaadinRequest) { - final VerticalLayout verticalLayout = new VerticalLayout(); - verticalLayout.setSpacing(true); - verticalLayout.setMargin(true); - final GridLayout gridLayout = new GridLayout(3, 2); - gridLayout.setSpacing(true); - gridLayout.setMargin(true); - final HorizontalLayout horizontalLayout = new HorizontalLayout(); - horizontalLayout.setSpacing(true); - horizontalLayout.setMargin(true); - final FormLayout formLayout = new FormLayout(); - formLayout.setSpacing(true); - formLayout.setMargin(true); - final GridLayout buttonLayout = new GridLayout(3, 5); - buttonLayout.setMargin(true); - buttonLayout.setSpacing(true); - - final Label label = new Label(); - label.setId("Label"); - label.setValue("Label Value"); - label.setCaption("Label"); - gridLayout.addComponent(label); - - final Link link = new Link("Baeldung", new ExternalResource("http://www.baeldung.com/")); - link.setId("Link"); - link.setTargetName("_blank"); - gridLayout.addComponent(link); - - final TextField textField = new TextField(); - textField.setId("TextField"); - textField.setCaption("TextField:"); - textField.setValue("TextField Value"); - textField.setIcon(FontAwesome.USER); - gridLayout.addComponent(textField); - - final TextArea textArea = new TextArea(); - textArea.setCaption("TextArea"); - textArea.setId("TextArea"); - textArea.setValue("TextArea Value"); - gridLayout.addComponent(textArea); - - final DateField dateField = new DateField("DateField", new Date(0)); - dateField.setId("DateField"); - gridLayout.addComponent(dateField); - - final PasswordField passwordField = new PasswordField(); - passwordField.setId("PasswordField"); - passwordField.setCaption("PasswordField:"); - passwordField.setValue("password"); - gridLayout.addComponent(passwordField); - - final RichTextArea richTextArea = new RichTextArea(); - richTextArea.setCaption("Rich Text Area"); - richTextArea.setValue("

RichTextArea

"); - richTextArea.setSizeFull(); - - Panel richTextPanel = new Panel(); - richTextPanel.setContent(richTextArea); - - final InlineDateField inlineDateField = new InlineDateField(); - inlineDateField.setValue(new Date(0)); - inlineDateField.setCaption("Inline Date Field"); - horizontalLayout.addComponent(inlineDateField); - - Button normalButton = new Button("Normal Button"); - normalButton.setId("NormalButton"); - normalButton.addClickListener(e -> { - label.setValue("CLICK"); - }); - buttonLayout.addComponent(normalButton); - - Button tinyButton = new Button("Tiny Button"); - tinyButton.addStyleName("tiny"); - buttonLayout.addComponent(tinyButton); - - Button smallButton = new Button("Small Button"); - smallButton.addStyleName("small"); - buttonLayout.addComponent(smallButton); - - Button largeButton = new Button("Large Button"); - largeButton.addStyleName("large"); - buttonLayout.addComponent(largeButton); - - Button hugeButton = new Button("Huge Button"); - hugeButton.addStyleName("huge"); - buttonLayout.addComponent(hugeButton); - - Button disabledButton = new Button("Disabled Button"); - disabledButton.setDescription("This button cannot be clicked"); - disabledButton.setEnabled(false); - buttonLayout.addComponent(disabledButton); - - Button dangerButton = new Button("Danger Button"); - dangerButton.addStyleName("danger"); - buttonLayout.addComponent(dangerButton); - - Button friendlyButton = new Button("Friendly Button"); - friendlyButton.addStyleName("friendly"); - buttonLayout.addComponent(friendlyButton); - - Button primaryButton = new Button("Primary Button"); - primaryButton.addStyleName("primary"); - buttonLayout.addComponent(primaryButton); - - NativeButton nativeButton = new NativeButton("Native Button"); - buttonLayout.addComponent(nativeButton); - - Button iconButton = new Button("Icon Button"); - iconButton.setIcon(FontAwesome.ALIGN_LEFT); - buttonLayout.addComponent(iconButton); - - Button borderlessButton = new Button("BorderLess Button"); - borderlessButton.addStyleName("borderless"); - buttonLayout.addComponent(borderlessButton); - - Button linkButton = new Button("Link Button"); - linkButton.addStyleName("link"); - buttonLayout.addComponent(linkButton); - - Button quietButton = new Button("Quiet Button"); - quietButton.addStyleName("quiet"); - buttonLayout.addComponent(quietButton); - - horizontalLayout.addComponent(buttonLayout); - - final CheckBox checkbox = new CheckBox("CheckBox"); - checkbox.setValue(true); - checkbox.addValueChangeListener(e -> checkbox.setValue(!checkbox.getValue())); - formLayout.addComponent(checkbox); - - List numbers = new ArrayList(); - numbers.add("One"); - numbers.add("Ten"); - numbers.add("Eleven"); - ComboBox comboBox = new ComboBox("ComboBox"); - comboBox.addItems(numbers); - formLayout.addComponent(comboBox); - - ListSelect listSelect = new ListSelect("ListSelect"); - listSelect.addItems(numbers); - listSelect.setRows(2); - formLayout.addComponent(listSelect); - - NativeSelect nativeSelect = new NativeSelect("NativeSelect"); - nativeSelect.addItems(numbers); - formLayout.addComponent(nativeSelect); - - TwinColSelect twinColSelect = new TwinColSelect("TwinColSelect"); - twinColSelect.addItems(numbers); - - Grid grid = new Grid("Grid"); - grid.setColumns("Column1", "Column2", "Column3"); - grid.addRow("Item1", "Item2", "Item3"); - grid.addRow("Item4", "Item5", "Item6"); - - Panel panel = new Panel("Panel"); - panel.setContent(grid); - panel.setSizeUndefined(); - - Panel serverPushPanel = new Panel("Server Push"); - FormLayout timeLayout = new FormLayout(); - timeLayout.setSpacing(true); - timeLayout.setMargin(true); - currentTime = new Label("No TIME..."); - timeLayout.addComponent(currentTime); - serverPushPanel.setContent(timeLayout); - serverPushPanel.setSizeUndefined(); - ScheduledExecutorService scheduleExecutor = Executors.newScheduledThreadPool(1); - Runnable task = () -> { - currentTime.setValue("Current Time : " + Instant.now()); - }; - scheduleExecutor.scheduleWithFixedDelay(task, 0, 1, TimeUnit.SECONDS); - - FormLayout dataBindingLayout = new FormLayout(); - dataBindingLayout.setSpacing(true); - dataBindingLayout.setMargin(true); - - BindData bindData = new BindData("BindData"); - BeanFieldGroup beanFieldGroup = new BeanFieldGroup(BindData.class); - beanFieldGroup.setItemDataSource(bindData); - TextField bindedTextField = (TextField) beanFieldGroup.buildAndBind("BindName", "bindName"); - bindedTextField.setWidth("250px"); - dataBindingLayout.addComponent(bindedTextField); - - FormLayout validatorLayout = new FormLayout(); - validatorLayout.setSpacing(true); - validatorLayout.setMargin(true); - - HorizontalLayout textValidatorLayout = new HorizontalLayout(); - textValidatorLayout.setSpacing(true); - textValidatorLayout.setMargin(true); - - TextField stringValidator = new TextField(); - stringValidator.setNullSettingAllowed(true); - stringValidator.setNullRepresentation(""); - stringValidator.addValidator(new StringLengthValidator("String must have 2-5 characters lenght", 2, 5, true)); - stringValidator.setValidationVisible(false); - textValidatorLayout.addComponent(stringValidator); - Button buttonStringValidator = new Button("Validate String"); - buttonStringValidator.addClickListener(e -> { - try { - stringValidator.setValidationVisible(false); - stringValidator.validate(); - } catch (InvalidValueException err) { - stringValidator.setValidationVisible(true); - } - }); - textValidatorLayout.addComponent(buttonStringValidator); - - validatorLayout.addComponent(textValidatorLayout); - verticalLayout.addComponent(gridLayout); - verticalLayout.addComponent(richTextPanel); - verticalLayout.addComponent(horizontalLayout); - verticalLayout.addComponent(formLayout); - verticalLayout.addComponent(twinColSelect); - verticalLayout.addComponent(panel); - verticalLayout.addComponent(serverPushPanel); - verticalLayout.addComponent(dataBindingLayout); - verticalLayout.addComponent(validatorLayout); - setContent(verticalLayout); - } - - @WebServlet(urlPatterns = "/*", name = "MyUIServlet", asyncSupported = true) - @VaadinServletConfiguration(ui = VaadinUI.class, productionMode = false) - public static class MyUIServlet extends VaadinServlet { - } -} diff --git a/xml/pom.xml b/xml/pom.xml index dfdec4da16..ba6a734dc9 100644 --- a/xml/pom.xml +++ b/xml/pom.xml @@ -30,6 +30,22 @@ ${jdom2.version}
+ + javax.xml + jaxb-api + 2.1 + + + javax.xml + jaxp-api + 1.4.2 + + + javax.xml.stream + stax-api + 1.0-2 + + commons-io diff --git a/xml/src/main/java/com/baeldung/xmlhtml/Application.java b/xml/src/main/java/com/baeldung/xmlhtml/Application.java new file mode 100644 index 0000000000..063a833810 --- /dev/null +++ b/xml/src/main/java/com/baeldung/xmlhtml/Application.java @@ -0,0 +1,10 @@ +package com.baeldung.xmlhtml; + +import com.baeldung.xmlhtml.helpers.XMLRunner; + +public class Application { + + public static void main(String[] args) { + XMLRunner.doWork(); + } +} diff --git a/xml/src/main/java/com/baeldung/xmlhtml/Constants.java b/xml/src/main/java/com/baeldung/xmlhtml/Constants.java new file mode 100644 index 0000000000..88fc5637df --- /dev/null +++ b/xml/src/main/java/com/baeldung/xmlhtml/Constants.java @@ -0,0 +1,22 @@ +package com.baeldung.xmlhtml; + +public class Constants { + + public static final String XML_FILE_IN = "src/main/resources/xml/in.xml"; + public static final String JAXB_FILE_OUT = "src/main/resources/xml/jaxb.html"; + public static final String JAXP_FILE_OUT = "src/main/resources/xml/jaxp.html"; + public static final String STAX_FILE_OUT = "src/main/resources/xml/stax.html"; + + public static final String EXCEPTION_ENCOUNTERED = "Generic exception! Error: "; + + public static final String LINE_BREAK = System.getProperty("line.separator"); + public static final String WHITE_SPACE = " "; + + public static final String DOCUMENT_START = "Document parsing has begun!"; + public static final String DOCUMENT_END = "Document parsing has ended!"; + public static final String ELEMENT_START = "Element parsing has begun!"; + public static final String ELEMENT_END = "Element parsing has ended!"; + + public static final String BREAK = "\n"; + public static final String TAB = "\t"; +} diff --git a/xml/src/main/java/com/baeldung/xmlhtml/helpers/XMLRunner.java b/xml/src/main/java/com/baeldung/xmlhtml/helpers/XMLRunner.java new file mode 100644 index 0000000000..02b2577795 --- /dev/null +++ b/xml/src/main/java/com/baeldung/xmlhtml/helpers/XMLRunner.java @@ -0,0 +1,16 @@ +package com.baeldung.xmlhtml.helpers; + + +import com.baeldung.xmlhtml.helpers.jaxb.JAXBHelper; +import com.baeldung.xmlhtml.helpers.jaxp.JAXPHelper; +import com.baeldung.xmlhtml.helpers.stax.STAXHelper; + +public class XMLRunner { + + public static void doWork() { + JAXBHelper.example(); + JAXPHelper.saxParser(); + JAXPHelper.documentBuilder(); + STAXHelper.write(STAXHelper.read()); + } +} diff --git a/xml/src/main/java/com/baeldung/xmlhtml/helpers/jaxb/JAXBHelper.java b/xml/src/main/java/com/baeldung/xmlhtml/helpers/jaxb/JAXBHelper.java new file mode 100644 index 0000000000..715f963f2e --- /dev/null +++ b/xml/src/main/java/com/baeldung/xmlhtml/helpers/jaxb/JAXBHelper.java @@ -0,0 +1,77 @@ +package com.baeldung.xmlhtml.helpers.jaxb; + +import com.baeldung.xmlhtml.pojo.jaxb.html.ExampleHTML; +import com.baeldung.xmlhtml.pojo.jaxb.html.elements.Body; +import com.baeldung.xmlhtml.pojo.jaxb.html.elements.CustomElement; +import com.baeldung.xmlhtml.pojo.jaxb.html.elements.Meta; +import com.baeldung.xmlhtml.pojo.jaxb.html.elements.NestedElement; +import com.baeldung.xmlhtml.pojo.jaxb.xml.XMLExample; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.Marshaller; +import javax.xml.bind.Unmarshaller; + +import java.io.File; + +import static com.baeldung.xmlhtml.Constants.*; + +public class JAXBHelper { + + private static void print(String xmlContent) { + System.out.println(xmlContent); + } + + private static Unmarshaller getContextUnmarshaller(Class clazz) { + Unmarshaller unmarshaller = null; + try { + JAXBContext context = JAXBContext.newInstance(clazz); + unmarshaller = context.createUnmarshaller(); + } catch (Exception ex) { + System.out.println(EXCEPTION_ENCOUNTERED + ex); + } + return unmarshaller; + } + + private static Marshaller getContextMarshaller(Class clazz) { + Marshaller marshaller = null; + try { + JAXBContext context = JAXBContext.newInstance(clazz); + marshaller = context.createMarshaller(); + marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); + marshaller.setProperty("jaxb.fragment", Boolean.TRUE); + } catch (Exception ex) { + System.out.println(EXCEPTION_ENCOUNTERED + ex); + } + return marshaller; + } + + public static void example() { + try { + XMLExample xml = (XMLExample) JAXBHelper.getContextUnmarshaller(XMLExample.class).unmarshal(new File(XML_FILE_IN)); + JAXBHelper.print(xml.toString()); + ExampleHTML html = new ExampleHTML(); + + Body body = new Body(); + CustomElement customElement = new CustomElement(); + NestedElement nested = new NestedElement(); + CustomElement child = new CustomElement(); + + customElement.setValue("descendantOne: " + xml.getAncestor().getDescendantOne().getValue()); + child.setValue("descendantThree: " + xml.getAncestor().getDescendantTwo().getDescendantThree().getValue()); + nested.setCustomElement(child); + + body.setCustomElement(customElement); + body.setNestedElement(nested); + + Meta meta = new Meta(); + meta.setTitle("example"); + html.getHead().add(meta); + html.setBody(body); + + JAXBHelper.getContextMarshaller(ExampleHTML.class).marshal(html, new File(JAXB_FILE_OUT)); + + } catch (Exception ex) { + System.out.println(EXCEPTION_ENCOUNTERED + ex); + } + } +} \ No newline at end of file diff --git a/xml/src/main/java/com/baeldung/xmlhtml/helpers/jaxp/CustomHandler.java b/xml/src/main/java/com/baeldung/xmlhtml/helpers/jaxp/CustomHandler.java new file mode 100644 index 0000000000..e6351c9e22 --- /dev/null +++ b/xml/src/main/java/com/baeldung/xmlhtml/helpers/jaxp/CustomHandler.java @@ -0,0 +1,34 @@ +package com.baeldung.xmlhtml.helpers.jaxp; + +import org.xml.sax.ContentHandler; +import org.xml.sax.Locator; + +import static com.baeldung.xmlhtml.Constants.*; + +public class CustomHandler implements ContentHandler { + + public void startDocument() {} + + public void startElement(String uri, String localName, String qName, org.xml.sax.Attributes atts) { } + + public void endDocument() { + System.out.println(DOCUMENT_END); + } + + public void endElement(String uri, String localName, String qName) { } + + public void startPrefixMapping(String prefix, String uri) { } + + public void endPrefixMapping(String prefix) { } + + public void setDocumentLocator(Locator locator) { } + + public void characters(char[] ch, int start, int length) { } + + public void ignorableWhitespace(char[] ch, int start, int length) { } + + public void processingInstruction(String target, String data) { } + + public void skippedEntity(String name) { } + +} diff --git a/xml/src/main/java/com/baeldung/xmlhtml/helpers/jaxp/JAXPHelper.java b/xml/src/main/java/com/baeldung/xmlhtml/helpers/jaxp/JAXPHelper.java new file mode 100644 index 0000000000..3196d543da --- /dev/null +++ b/xml/src/main/java/com/baeldung/xmlhtml/helpers/jaxp/JAXPHelper.java @@ -0,0 +1,90 @@ +package com.baeldung.xmlhtml.helpers.jaxp; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.XMLReader; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import java.io.File; + +import static com.baeldung.xmlhtml.Constants.*; + +public class JAXPHelper { + + private static void print(Document document) { + NodeList list = document.getChildNodes(); + try { + for (int i = 0; i < list.getLength(); i++) { + Node node = list.item(i); + String message = + node.getNodeType() + + WHITE_SPACE + + node.getNodeName() + + LINE_BREAK; + System.out.println(message); + } + } catch (Exception ex) { + System.out.println(EXCEPTION_ENCOUNTERED + ex); + } + } + + public static void saxParser() { + SAXParserFactory spf = SAXParserFactory.newInstance(); + spf.setNamespaceAware(true); + try { + SAXParser saxParser = spf.newSAXParser(); + XMLReader xmlReader = saxParser.getXMLReader(); + xmlReader.setContentHandler(new CustomHandler()); + xmlReader.parse(XML_FILE_IN); + } catch (Exception ex) { + System.out.println(EXCEPTION_ENCOUNTERED + ex); + } + } + + public static void documentBuilder() { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + try { + DocumentBuilder db = dbf.newDocumentBuilder(); + Document parsed = db.parse(new File(XML_FILE_IN)); + Element xml = parsed.getDocumentElement(); + + Document doc = db.newDocument(); + Element html = doc.createElement("html"); + Element head = doc.createElement("head"); + html.appendChild(head); + + Element body = doc.createElement("body"); + Element descendantOne = doc.createElement("p"); + descendantOne.setTextContent("descendantOne: " + + xml.getElementsByTagName("descendantOne") + .item(0).getTextContent()); + Element descendantThree = doc.createElement("p"); + descendantThree.setTextContent("descendantThree: " + + xml.getElementsByTagName("descendantThree") + .item(0).getTextContent()); + Element nested = doc.createElement("div"); + nested.appendChild(descendantThree); + + body.appendChild(descendantOne); + body.appendChild(nested); + html.appendChild(body); + doc.appendChild(html); + + TransformerFactory tFactory = TransformerFactory.newInstance(); + tFactory + .newTransformer() + .transform(new DOMSource(doc), new StreamResult(new File(JAXP_FILE_OUT))); + + } catch (Exception ex) { + System.out.println(EXCEPTION_ENCOUNTERED + ex); + } + } +} diff --git a/xml/src/main/java/com/baeldung/xmlhtml/helpers/stax/STAXHelper.java b/xml/src/main/java/com/baeldung/xmlhtml/helpers/stax/STAXHelper.java new file mode 100644 index 0000000000..a9b9217b6a --- /dev/null +++ b/xml/src/main/java/com/baeldung/xmlhtml/helpers/stax/STAXHelper.java @@ -0,0 +1,112 @@ +package com.baeldung.xmlhtml.helpers.stax; + +import com.baeldung.xmlhtml.pojo.stax.Body; +import com.baeldung.xmlhtml.pojo.stax.CustomElement; +import com.baeldung.xmlhtml.pojo.stax.NestedElement; + +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLOutputFactory; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.XMLStreamWriter; +import java.io.FileInputStream; +import java.io.FileWriter; + +import static com.baeldung.xmlhtml.Constants.*; + +public class STAXHelper { + + private static XMLStreamReader reader() { + XMLStreamReader xmlStreamReader = null; + try { + xmlStreamReader = XMLInputFactory.newInstance().createXMLStreamReader(new FileInputStream(XML_FILE_IN)); + } catch (Exception ex) { + System.out.println(EXCEPTION_ENCOUNTERED + ex); + } + return xmlStreamReader; + } + + private static XMLStreamWriter writer() { + XMLStreamWriter xmlStreamWriter = null; + try { + xmlStreamWriter = XMLOutputFactory.newInstance().createXMLStreamWriter(new FileWriter(STAX_FILE_OUT)); + } catch (Exception ex) { + System.out.println(EXCEPTION_ENCOUNTERED + ex); + } + return xmlStreamWriter; + } + + public static Body read() { + Body body = new Body(); + try { + XMLStreamReader xmlStreamReader = reader(); + + CustomElement customElement = new CustomElement(); + NestedElement nestedElement = new NestedElement(); + CustomElement child = new CustomElement(); + + while (xmlStreamReader.hasNext()) { + xmlStreamReader.next(); + if (xmlStreamReader.isStartElement()) { + System.out.println(xmlStreamReader.getLocalName()); + if (xmlStreamReader.getLocalName().equals("descendantOne")) { + customElement.setValue(xmlStreamReader.getElementText()); + } + if (xmlStreamReader.getLocalName().equals("descendantThree")) { + child.setValue(xmlStreamReader.getElementText()); + } + } + } + + nestedElement.setCustomElement(child); + body.setCustomElement(customElement); + body.setNestedElement(nestedElement); + + xmlStreamReader.close(); + + } catch (Exception ex) { + System.out.println(EXCEPTION_ENCOUNTERED + ex); + } + return body; + } + + public static void write(Body body) { + try { + + XMLStreamWriter xmlStreamWriter = writer(); + xmlStreamWriter.writeStartElement("html"); + xmlStreamWriter.writeCharacters(BREAK + TAB); + xmlStreamWriter.writeStartElement("head"); + xmlStreamWriter.writeCharacters(BREAK + TAB + TAB); + xmlStreamWriter.writeStartElement("meta"); + xmlStreamWriter.writeEndElement(); + xmlStreamWriter.writeCharacters(BREAK + TAB); + xmlStreamWriter.writeEndElement(); + xmlStreamWriter.writeCharacters(BREAK + TAB); + xmlStreamWriter.writeStartElement("body"); + xmlStreamWriter.writeCharacters(BREAK + TAB + TAB); + xmlStreamWriter.writeStartElement("p"); + xmlStreamWriter.writeCharacters("descendantOne: " + body.getCustomElement().getValue()); + xmlStreamWriter.writeEndElement(); + xmlStreamWriter.writeCharacters(BREAK + TAB + TAB); + xmlStreamWriter.writeStartElement("div"); + xmlStreamWriter.writeCharacters(BREAK + TAB + TAB + TAB); + xmlStreamWriter.writeStartElement("p"); + xmlStreamWriter.writeCharacters(BREAK); + xmlStreamWriter.writeCharacters(TAB + TAB + TAB + TAB + "descendantThree: " + body.getNestedElement().getCustomElement().getValue()); + xmlStreamWriter.writeCharacters(BREAK + TAB + TAB + TAB); + xmlStreamWriter.writeEndElement(); + xmlStreamWriter.writeCharacters(BREAK + TAB + TAB); + xmlStreamWriter.writeEndElement(); + xmlStreamWriter.writeCharacters(BREAK + TAB); + xmlStreamWriter.writeEndElement(); + xmlStreamWriter.writeCharacters(BREAK); + xmlStreamWriter.writeEndDocument(); + xmlStreamWriter.flush(); + xmlStreamWriter.close(); + + } catch (Exception ex) { + System.out.println(EXCEPTION_ENCOUNTERED + ex); + } + + } +} diff --git a/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/html/ExampleHTML.java b/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/html/ExampleHTML.java new file mode 100644 index 0000000000..d44c81f309 --- /dev/null +++ b/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/html/ExampleHTML.java @@ -0,0 +1,38 @@ +package com.baeldung.xmlhtml.pojo.jaxb.html; + +import com.baeldung.xmlhtml.pojo.jaxb.html.elements.Body; +import com.baeldung.xmlhtml.pojo.jaxb.html.elements.Meta; + +import javax.xml.bind.annotation.*; +import java.util.ArrayList; +import java.util.List; + +@XmlType(propOrder = {"head", "body"}) +@XmlRootElement(name = "html") +public class ExampleHTML { + + private List head = new ArrayList<>(); + + private Body body; + + public ExampleHTML() { } + + public List getHead() { + return head; + } + + @XmlElementWrapper(name = "head") + @XmlElement(name = "meta") + public void setHead(List head) { + this.head = head; + } + + public Body getBody() { + return body; + } + + @XmlElement(name = "body") + public void setBody(Body body) { + this.body = body; + } +} diff --git a/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/html/elements/Body.java b/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/html/elements/Body.java new file mode 100644 index 0000000000..36c6c13a04 --- /dev/null +++ b/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/html/elements/Body.java @@ -0,0 +1,29 @@ +package com.baeldung.xmlhtml.pojo.jaxb.html.elements; + +import javax.xml.bind.annotation.XmlElement; + +public class Body { + + private CustomElement customElement; + + public CustomElement getCustomElement() { + return customElement; + } + + @XmlElement(name = "p") + public void setCustomElement(CustomElement customElement) { + this.customElement = customElement; + } + + private NestedElement nestedElement; + + public NestedElement getNestedElement() { + return nestedElement; + } + + @XmlElement(name = "div") + public void setNestedElement(NestedElement nestedElement) { + this.nestedElement = nestedElement; + } + +} \ No newline at end of file diff --git a/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/html/elements/CustomElement.java b/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/html/elements/CustomElement.java new file mode 100644 index 0000000000..832c5e746e --- /dev/null +++ b/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/html/elements/CustomElement.java @@ -0,0 +1,18 @@ +package com.baeldung.xmlhtml.pojo.jaxb.html.elements; + +import javax.xml.bind.annotation.XmlValue; + +public class CustomElement { + + private String value; + + @XmlValue + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + +} diff --git a/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/html/elements/Meta.java b/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/html/elements/Meta.java new file mode 100644 index 0000000000..11b6b86c05 --- /dev/null +++ b/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/html/elements/Meta.java @@ -0,0 +1,30 @@ +package com.baeldung.xmlhtml.pojo.jaxb.html.elements; + +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlValue; + +public class Meta { + + private String title; + + public String getTitle() { + return title; + } + + @XmlAttribute(name = "title") + public void setTitle(String title) { + this.title = title; + } + + private String value; + + @XmlValue + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + +} \ No newline at end of file diff --git a/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/html/elements/NestedElement.java b/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/html/elements/NestedElement.java new file mode 100644 index 0000000000..20557064bb --- /dev/null +++ b/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/html/elements/NestedElement.java @@ -0,0 +1,17 @@ +package com.baeldung.xmlhtml.pojo.jaxb.html.elements; + +import javax.xml.bind.annotation.XmlElement; + +public class NestedElement { + + private CustomElement customElement; + + public CustomElement getCustomElement() { + return customElement; + } + + @XmlElement(name = "p") + public void setCustomElement(CustomElement customElement) { + this.customElement = customElement; + } +} \ No newline at end of file diff --git a/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/xml/XMLExample.java b/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/xml/XMLExample.java new file mode 100644 index 0000000000..587cf69223 --- /dev/null +++ b/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/xml/XMLExample.java @@ -0,0 +1,21 @@ +package com.baeldung.xmlhtml.pojo.jaxb.xml; + +import com.baeldung.xmlhtml.pojo.jaxb.xml.elements.Ancestor; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement(name = "xmlexample") +public class XMLExample { + + private Ancestor ancestor; + + @XmlElement(name = "ancestor") + public void setAncestor(Ancestor ancestor) { + this.ancestor = ancestor; + } + + public Ancestor getAncestor() { + return ancestor; + } +} \ No newline at end of file diff --git a/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/xml/elements/Ancestor.java b/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/xml/elements/Ancestor.java new file mode 100644 index 0000000000..ff2b928206 --- /dev/null +++ b/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/xml/elements/Ancestor.java @@ -0,0 +1,28 @@ +package com.baeldung.xmlhtml.pojo.jaxb.xml.elements; + +import javax.xml.bind.annotation.XmlElement; + +public class Ancestor { + + private DescendantOne descendantOne; + private DescendantTwo descendantTwo; + + public DescendantOne getDescendantOne() { + return descendantOne; + } + + @XmlElement(name = "descendantOne") + public void setDescendantOne(DescendantOne descendantOne) { + this.descendantOne = descendantOne; + } + + public DescendantTwo getDescendantTwo() { + return descendantTwo; + } + + @XmlElement(name = "descendantTwo") + public void setDescendantTwo(DescendantTwo descendantTwo) { + this.descendantTwo = descendantTwo; + } +} + diff --git a/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/xml/elements/DescendantOne.java b/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/xml/elements/DescendantOne.java new file mode 100644 index 0000000000..50624cb9fa --- /dev/null +++ b/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/xml/elements/DescendantOne.java @@ -0,0 +1,19 @@ +package com.baeldung.xmlhtml.pojo.jaxb.xml.elements; + +import javax.xml.bind.annotation.XmlValue; + +public class DescendantOne { + + private String value; + + @XmlValue + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + +} + diff --git a/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/xml/elements/DescendantThree.java b/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/xml/elements/DescendantThree.java new file mode 100644 index 0000000000..7c3ce9b6f7 --- /dev/null +++ b/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/xml/elements/DescendantThree.java @@ -0,0 +1,18 @@ +package com.baeldung.xmlhtml.pojo.jaxb.xml.elements; + +import javax.xml.bind.annotation.XmlValue; + +public class DescendantThree { + + private String value; + + @XmlValue + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + +} \ No newline at end of file diff --git a/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/xml/elements/DescendantTwo.java b/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/xml/elements/DescendantTwo.java new file mode 100644 index 0000000000..1ca989560b --- /dev/null +++ b/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/xml/elements/DescendantTwo.java @@ -0,0 +1,17 @@ +package com.baeldung.xmlhtml.pojo.jaxb.xml.elements; + +import javax.xml.bind.annotation.XmlElement; + +public class DescendantTwo { + + private DescendantThree descendantThree; + + public DescendantThree getDescendantThree() { + return descendantThree; + } + + @XmlElement(name = "descendantThree") + public void setDescendant(DescendantThree descendantThree) { + this.descendantThree = descendantThree; + } +} \ No newline at end of file diff --git a/xml/src/main/java/com/baeldung/xmlhtml/pojo/stax/Body.java b/xml/src/main/java/com/baeldung/xmlhtml/pojo/stax/Body.java new file mode 100644 index 0000000000..630dfe967f --- /dev/null +++ b/xml/src/main/java/com/baeldung/xmlhtml/pojo/stax/Body.java @@ -0,0 +1,23 @@ +package com.baeldung.xmlhtml.pojo.stax; + +public class Body { + + private CustomElement customElement; + + public CustomElement getCustomElement() { + return customElement; + } + public void setCustomElement(CustomElement customElement) { + this.customElement = customElement; + } + + private NestedElement nestedElement; + + public NestedElement getNestedElement() { + return nestedElement; + } + public void setNestedElement(NestedElement nestedElement) { + this.nestedElement = nestedElement; + } + +} \ No newline at end of file diff --git a/xml/src/main/java/com/baeldung/xmlhtml/pojo/stax/CustomElement.java b/xml/src/main/java/com/baeldung/xmlhtml/pojo/stax/CustomElement.java new file mode 100644 index 0000000000..6fc1d7b787 --- /dev/null +++ b/xml/src/main/java/com/baeldung/xmlhtml/pojo/stax/CustomElement.java @@ -0,0 +1,13 @@ +package com.baeldung.xmlhtml.pojo.stax; + +public class CustomElement { + + private String value; + + public String getValue() { + return value; + } + public void setValue(String value) { + this.value = value; + } +} diff --git a/xml/src/main/java/com/baeldung/xmlhtml/pojo/stax/NestedElement.java b/xml/src/main/java/com/baeldung/xmlhtml/pojo/stax/NestedElement.java new file mode 100644 index 0000000000..146ee068af --- /dev/null +++ b/xml/src/main/java/com/baeldung/xmlhtml/pojo/stax/NestedElement.java @@ -0,0 +1,13 @@ +package com.baeldung.xmlhtml.pojo.stax; + +public class NestedElement { + + private CustomElement customElement; + + public CustomElement getCustomElement() { + return customElement; + } + public void setCustomElement(CustomElement customElement) { + this.customElement = customElement; + } +} diff --git a/xml/src/main/resources/xml/in.xml b/xml/src/main/resources/xml/in.xml new file mode 100644 index 0000000000..6fcb404012 --- /dev/null +++ b/xml/src/main/resources/xml/in.xml @@ -0,0 +1,11 @@ + + + + Yo + + + DustyOrb + + + + \ No newline at end of file diff --git a/xml/src/main/resources/xml/jaxb.html b/xml/src/main/resources/xml/jaxb.html new file mode 100644 index 0000000000..80b894cff7 --- /dev/null +++ b/xml/src/main/resources/xml/jaxb.html @@ -0,0 +1,14 @@ + + + + + + +

descendantOne: Yo

+
+

descendantThree: + DustyOrb +

+
+ + diff --git a/xml/src/main/resources/xml/jaxp.html b/xml/src/main/resources/xml/jaxp.html new file mode 100644 index 0000000000..5392eef509 --- /dev/null +++ b/xml/src/main/resources/xml/jaxp.html @@ -0,0 +1,13 @@ + + + + + +

descendantOne: Yo

+
+

descendantThree: + DustyOrb +

+
+ + diff --git a/xml/src/main/resources/xml/stax.html b/xml/src/main/resources/xml/stax.html new file mode 100644 index 0000000000..01951dc7de --- /dev/null +++ b/xml/src/main/resources/xml/stax.html @@ -0,0 +1,15 @@ + + + + + +

descendantOne: Yo

+
+

+ descendantThree: + DustyOrb + +

+
+ + \ No newline at end of file