diff --git a/README.md b/README.md index f3fe5e3bf0..378d77196a 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Java and Spring Tutorials ================ This project is **a collection of small and focused tutorials** - each covering a single and well defined area of development in the Java ecosystem. -A strong focus of these is, of course, the Spring Framework - Spring, Spring Boot and Spring Securiyt. +A strong focus of these is, of course, the Spring Framework - Spring, Spring Boot and Spring Security. In additional to Spring, the following technologies are in focus: `core Java`, `Jackson`, `HttpClient`, `Guava`. diff --git a/akka-http/README.md b/akka-http/README.md index 583d2efa74..3831b5079f 100644 --- a/akka-http/README.md +++ b/akka-http/README.md @@ -1,3 +1,3 @@ -### Relevant articles +## Relevant articles: - [Introduction to Akka HTTP](https://www.baeldung.com/akka-http) diff --git a/algorithms-miscellaneous-1/README.md b/algorithms-miscellaneous-1/README.md index a725bbd141..59765588b0 100644 --- a/algorithms-miscellaneous-1/README.md +++ b/algorithms-miscellaneous-1/README.md @@ -12,4 +12,5 @@ - [Check If a String Contains All The Letters of The Alphabet](https://www.baeldung.com/java-string-contains-all-letters) - [Find the Middle Element of a Linked List](http://www.baeldung.com/java-linked-list-middle-element) - [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) \ No newline at end of file +- [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) diff --git a/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/permutation/Permutation.java b/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/permutation/Permutation.java new file mode 100644 index 0000000000..7fedd78ffb --- /dev/null +++ b/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/permutation/Permutation.java @@ -0,0 +1,123 @@ +package com.baeldung.algorithms.permutation; + +import java.util.Arrays; +import java.util.Collections; + +public class Permutation { + + public static void printAllRecursive(T[] elements, char delimiter) { + printAllRecursive(elements.length, elements, delimiter); + } + + public static void printAllRecursive(int n, T[] elements, char delimiter) { + + if(n == 1) { + printArray(elements, delimiter); + } else { + for(int i = 0; i < n-1; i++) { + printAllRecursive(n - 1, elements, delimiter); + if(n % 2 == 0) { + swap(elements, i, n-1); + } else { + swap(elements, 0, n-1); + } + } + printAllRecursive(n - 1, elements, delimiter); + } + } + + public static void printAllIterative(int n, T[] elements, char delimiter) { + + int[] indexes = new int[n]; + for (int i = 0; i < n; i++) { + indexes[i] = 0; + } + + printArray(elements, delimiter); + + int i = 0; + while (i < n) { + if (indexes[i] < i) { + swap(elements, i % 2 == 0 ? 0: indexes[i], i); + printArray(elements, delimiter); + indexes[i]++; + i = 0; + } + else { + indexes[i] = 0; + i++; + } + } + } + + public static > void printAllOrdered(T[] elements, char delimiter) { + + Arrays.sort(elements); + boolean hasNext = true; + + while(hasNext) { + printArray(elements, delimiter); + int k = 0, l = 0; + hasNext = false; + for (int i = elements.length - 1; i > 0; i--) { + if (elements[i].compareTo(elements[i - 1]) > 0) { + k = i - 1; + hasNext = true; + break; + } + } + + for (int i = elements.length - 1; i > k; i--) { + if (elements[i].compareTo(elements[k]) > 0) { + l = i; + break; + } + } + + swap(elements, k, l); + Collections.reverse(Arrays.asList(elements).subList(k + 1, elements.length)); + } + } + + public static void printRandom(T[] elements, char delimiter) { + + Collections.shuffle(Arrays.asList(elements)); + printArray(elements, delimiter); + } + + private static void swap(T[] elements, int a, int b) { + + T tmp = elements[a]; + elements[a] = elements[b]; + elements[b] = tmp; + } + + private static void printArray(T[] elements, char delimiter) { + + String delimiterSpace = delimiter + " "; + for(int i = 0; i < elements.length; i++) { + System.out.print(elements[i] + delimiterSpace); + } + System.out.print('\n'); + } + + public static void main(String[] argv) { + + Integer[] elements = {1,2,3,4}; + + System.out.println("Rec:"); + printAllRecursive(elements, ';'); + + System.out.println("Iter:"); + printAllIterative(elements.length, elements, ';'); + + System.out.println("Orderes:"); + printAllOrdered(elements, ';'); + + System.out.println("Random:"); + printRandom(elements, ';'); + + System.out.println("Random:"); + printRandom(elements, ';'); + } +} diff --git a/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/twopointertechnique/LinkedListFindMiddle.java b/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/twopointertechnique/LinkedListFindMiddle.java new file mode 100644 index 0000000000..a7031f4fba --- /dev/null +++ b/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/twopointertechnique/LinkedListFindMiddle.java @@ -0,0 +1,16 @@ +package com.baeldung.algorithms.twopointertechnique; + +public class LinkedListFindMiddle { + + public T findMiddle(MyNode head) { + MyNode slowPointer = head; + MyNode fastPointer = head; + + while (fastPointer.next != null && fastPointer.next.next != null) { + fastPointer = fastPointer.next.next; + slowPointer = slowPointer.next; + } + return slowPointer.data; + } + +} diff --git a/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/twopointertechnique/MyNode.java b/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/twopointertechnique/MyNode.java new file mode 100644 index 0000000000..7d93f03ef9 --- /dev/null +++ b/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/twopointertechnique/MyNode.java @@ -0,0 +1,20 @@ +package com.baeldung.algorithms.twopointertechnique; + +public class MyNode { + MyNode next; + E data; + + public MyNode(E value) { + data = value; + next = null; + } + + public MyNode(E value, MyNode n) { + data = value; + next = n; + } + + public void setNext(MyNode n) { + next = n; + } +} diff --git a/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/twopointertechnique/RotateArray.java b/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/twopointertechnique/RotateArray.java new file mode 100644 index 0000000000..b4e3698c01 --- /dev/null +++ b/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/twopointertechnique/RotateArray.java @@ -0,0 +1,22 @@ +package com.baeldung.algorithms.twopointertechnique; + +public class RotateArray { + + public void rotate(int[] input, int step) { + step %= input.length; + reverse(input, 0, input.length - 1); + reverse(input, 0, step - 1); + reverse(input, step, input.length - 1); + } + + private void reverse(int[] input, int start, int end) { + while (start < end) { + int temp = input[start]; + input[start] = input[end]; + input[end] = temp; + start++; + end--; + } + } + +} diff --git a/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/twopointertechnique/TwoSum.java b/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/twopointertechnique/TwoSum.java new file mode 100644 index 0000000000..14eceaa1bd --- /dev/null +++ b/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/twopointertechnique/TwoSum.java @@ -0,0 +1,38 @@ +package com.baeldung.algorithms.twopointertechnique; + +public class TwoSum { + + public boolean twoSum(int[] input, int targetValue) { + + int pointerOne = 0; + int pointerTwo = input.length - 1; + + while (pointerOne < pointerTwo) { + int sum = input[pointerOne] + input[pointerTwo]; + + if (sum == targetValue) { + return true; + } else if (sum < targetValue) { + pointerOne++; + } else { + pointerTwo--; + } + } + + return false; + } + + public boolean twoSumSlow(int[] input, int targetValue) { + + for (int i = 0; i < input.length; i++) { + for (int j = 1; j < input.length; j++) { + if (input[i] + input[j] == targetValue) { + return true; + } + } + } + + return false; + } + +} diff --git a/algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/twopointertechnique/LinkedListFindMiddleUnitTest.java b/algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/twopointertechnique/LinkedListFindMiddleUnitTest.java new file mode 100644 index 0000000000..422a53fa3e --- /dev/null +++ b/algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/twopointertechnique/LinkedListFindMiddleUnitTest.java @@ -0,0 +1,37 @@ +package com.baeldung.algorithms.twopointertechnique; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.Test; + +public class LinkedListFindMiddleUnitTest { + + LinkedListFindMiddle linkedListFindMiddle = new LinkedListFindMiddle(); + + @Test + public void givenLinkedListOfMyNodes_whenLinkedListFindMiddle_thenCorrect() { + + MyNode head = createNodesList(8); + + assertThat(linkedListFindMiddle.findMiddle(head)).isEqualTo("4"); + + head = createNodesList(9); + + assertThat(linkedListFindMiddle.findMiddle(head)).isEqualTo("5"); + } + + private static MyNode createNodesList(int n) { + + MyNode head = new MyNode("1"); + MyNode current = head; + + for (int i = 2; i <= n; i++) { + MyNode newNode = new MyNode(String.valueOf(i)); + current.setNext(newNode); + current = newNode; + } + + return head; + } + +} diff --git a/algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/twopointertechnique/RotateArrayUnitTest.java b/algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/twopointertechnique/RotateArrayUnitTest.java new file mode 100644 index 0000000000..da227ae751 --- /dev/null +++ b/algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/twopointertechnique/RotateArrayUnitTest.java @@ -0,0 +1,26 @@ +package com.baeldung.algorithms.twopointertechnique; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.Test; + +public class RotateArrayUnitTest { + + private RotateArray rotateArray = new RotateArray(); + + private int[] inputArray; + + private int step; + + @Test + public void givenAnArrayOfIntegers_whenRotateKsteps_thenCorrect() { + + inputArray = new int[] { 1, 2, 3, 4, 5, 6, 7 }; + step = 4; + + rotateArray.rotate(inputArray, step); + + assertThat(inputArray).containsExactly(new int[] { 4, 5, 6, 7, 1, 2, 3 }); + } + +} diff --git a/algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/twopointertechnique/TwoSumUnitTest.java b/algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/twopointertechnique/TwoSumUnitTest.java new file mode 100644 index 0000000000..aa76f8e1cf --- /dev/null +++ b/algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/twopointertechnique/TwoSumUnitTest.java @@ -0,0 +1,56 @@ +package com.baeldung.algorithms.twopointertechnique; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +public class TwoSumUnitTest { + + private TwoSum twoSum = new TwoSum(); + + private int[] sortedArray; + + private int targetValue; + + @Test + public void givenASortedArrayOfIntegers_whenTwoSumSlow_thenPairExists() { + + sortedArray = new int[] { 0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 9 }; + + targetValue = 12; + + assertTrue(twoSum.twoSumSlow(sortedArray, targetValue)); + } + + @Test + public void givenASortedArrayOfIntegers_whenTwoSumSlow_thenPairDoesNotExists() { + + sortedArray = new int[] { 0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 9 }; + + targetValue = 20; + + assertFalse(twoSum.twoSumSlow(sortedArray, targetValue)); + } + + @Test + public void givenASortedArrayOfIntegers_whenTwoSum_thenPairExists() { + + sortedArray = new int[] { 0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 9 }; + + targetValue = 12; + + assertTrue(twoSum.twoSum(sortedArray, targetValue)); + } + + @Test + public void givenASortedArrayOfIntegers_whenTwoSum_thenPairDoesNotExists() { + + sortedArray = new int[] { 0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 9 }; + + targetValue = 20; + + assertFalse(twoSum.twoSum(sortedArray, targetValue)); + } + +} diff --git a/apache-spark/pom.xml b/apache-spark/pom.xml index 290b63a14d..b05b97198d 100644 --- a/apache-spark/pom.xml +++ b/apache-spark/pom.xml @@ -15,16 +15,76 @@ - org.apache.spark - spark-core_2.10 + spark-core_2.11 ${org.apache.spark.spark-core.version} + provided + + org.apache.spark + spark-sql_2.11 + ${org.apache.spark.spark-sql.version} + provided + + + org.apache.spark + spark-streaming_2.11 + ${org.apache.spark.spark-streaming.version} + provided + + + org.apache.spark + spark-streaming-kafka-0-10_2.11 + ${org.apache.spark.spark-streaming-kafka.version} + + + com.datastax.spark + spark-cassandra-connector_2.11 + ${com.datastax.spark.spark-cassandra-connector.version} + + + com.datastax.spark + spark-cassandra-connector-java_2.11 + ${com.datastax.spark.spark-cassandra-connector-java.version} + - + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.2 + + 1.8 + 1.8 + + + + maven-assembly-plugin + + + package + + single + + + + + + jar-with-dependencies + + + + + - 2.2.0 + 2.3.0 + 2.3.0 + 2.3.0 + 2.3.0 + 2.3.0 + 1.5.2 diff --git a/apache-spark/src/main/java/com/baeldung/data/pipeline/Word.java b/apache-spark/src/main/java/com/baeldung/data/pipeline/Word.java new file mode 100644 index 0000000000..b0caa468b1 --- /dev/null +++ b/apache-spark/src/main/java/com/baeldung/data/pipeline/Word.java @@ -0,0 +1,25 @@ +package com.baeldung.data.pipeline; + +import java.io.Serializable; + +public class Word implements Serializable { + private static final long serialVersionUID = 1L; + private String word; + private int count; + Word(String word, int count) { + this.word = word; + this.count = count; + } + public String getWord() { + return word; + } + public void setWord(String word) { + this.word = word; + } + public int getCount() { + return count; + } + public void setCount(int count) { + this.count = count; + } +} \ No newline at end of file diff --git a/apache-spark/src/main/java/com/baeldung/data/pipeline/WordCountingApp.java b/apache-spark/src/main/java/com/baeldung/data/pipeline/WordCountingApp.java new file mode 100644 index 0000000000..08695b3631 --- /dev/null +++ b/apache-spark/src/main/java/com/baeldung/data/pipeline/WordCountingApp.java @@ -0,0 +1,116 @@ +package com.baeldung.data.pipeline; + +import static com.datastax.spark.connector.japi.CassandraJavaUtil.javaFunctions; +import static com.datastax.spark.connector.japi.CassandraJavaUtil.mapToRow; + +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.apache.kafka.clients.consumer.ConsumerRecord; +import org.apache.kafka.common.serialization.StringDeserializer; +import org.apache.log4j.Level; +import org.apache.log4j.Logger; +import org.apache.spark.SparkConf; +import org.apache.spark.api.java.JavaPairRDD; +import org.apache.spark.api.java.JavaRDD; +import org.apache.spark.api.java.function.FlatMapFunction; +import org.apache.spark.api.java.function.Function; +import org.apache.spark.api.java.function.Function2; +import org.apache.spark.api.java.function.PairFunction; +import org.apache.spark.api.java.function.VoidFunction; +import org.apache.spark.streaming.Durations; +import org.apache.spark.streaming.api.java.JavaDStream; +import org.apache.spark.streaming.api.java.JavaInputDStream; +import org.apache.spark.streaming.api.java.JavaPairDStream; +import org.apache.spark.streaming.api.java.JavaStreamingContext; +import org.apache.spark.streaming.kafka010.ConsumerStrategies; +import org.apache.spark.streaming.kafka010.KafkaUtils; +import org.apache.spark.streaming.kafka010.LocationStrategies; + +import scala.Tuple2; + +public class WordCountingApp { + + @SuppressWarnings("serial") + public static void main(String[] args) throws InterruptedException { + Logger.getLogger("org") + .setLevel(Level.OFF); + Logger.getLogger("akka") + .setLevel(Level.OFF); + + Map kafkaParams = new HashMap<>(); + kafkaParams.put("bootstrap.servers", "localhost:9092"); + kafkaParams.put("key.deserializer", StringDeserializer.class); + kafkaParams.put("value.deserializer", StringDeserializer.class); + kafkaParams.put("group.id", "use_a_separate_group_id_for_each_stream"); + kafkaParams.put("auto.offset.reset", "latest"); + kafkaParams.put("enable.auto.commit", false); + + Collection topics = Arrays.asList("messages"); + + SparkConf sparkConf = new SparkConf(); + sparkConf.setMaster("local[2]"); + sparkConf.setAppName("WordCountingApp"); + sparkConf.set("spark.cassandra.connection.host", "127.0.0.1"); + + JavaStreamingContext streamingContext = new JavaStreamingContext(sparkConf, Durations.seconds(1)); + + JavaInputDStream> messages = KafkaUtils.createDirectStream(streamingContext, LocationStrategies.PreferConsistent(), ConsumerStrategies. Subscribe(topics, kafkaParams)); + + JavaPairDStream results = messages.mapToPair(new PairFunction, String, String>() { + @Override + public Tuple2 call(ConsumerRecord record) { + return new Tuple2<>(record.key(), record.value()); + } + }); + + JavaDStream lines = results.map(new Function, String>() { + @Override + public String call(Tuple2 tuple2) { + return tuple2._2(); + } + }); + + JavaDStream words = lines.flatMap(new FlatMapFunction() { + @Override + public Iterator call(String x) { + return Arrays.asList(x.split("\\s+")) + .iterator(); + } + }); + + JavaPairDStream wordCounts = words.mapToPair(new PairFunction() { + @Override + public Tuple2 call(String s) { + return new Tuple2<>(s, 1); + } + }) + .reduceByKey(new Function2() { + @Override + public Integer call(Integer i1, Integer i2) { + return i1 + i2; + } + }); + + wordCounts.foreachRDD(new VoidFunction>() { + @Override + public void call(JavaPairRDD javaRdd) throws Exception { + Map wordCountMap = javaRdd.collectAsMap(); + for (String key : wordCountMap.keySet()) { + List words = Arrays.asList(new Word(key, wordCountMap.get(key))); + JavaRDD rdd = streamingContext.sparkContext() + .parallelize(words); + javaFunctions(rdd).writerBuilder("vocabulary", "words", mapToRow(Word.class)) + .saveToCassandra(); + } + } + }); + + streamingContext.start(); + streamingContext.awaitTermination(); + } +} \ No newline at end of file diff --git a/apache-spark/src/main/java/com/baeldung/data/pipeline/WordCountingAppWithCheckpoint.java b/apache-spark/src/main/java/com/baeldung/data/pipeline/WordCountingAppWithCheckpoint.java new file mode 100644 index 0000000000..e20b910635 --- /dev/null +++ b/apache-spark/src/main/java/com/baeldung/data/pipeline/WordCountingAppWithCheckpoint.java @@ -0,0 +1,140 @@ +package com.baeldung.data.pipeline; + +import static com.datastax.spark.connector.japi.CassandraJavaUtil.javaFunctions; +import static com.datastax.spark.connector.japi.CassandraJavaUtil.mapToRow; + +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.apache.kafka.clients.consumer.ConsumerRecord; +import org.apache.kafka.common.serialization.StringDeserializer; +import org.apache.log4j.Level; +import org.apache.log4j.Logger; +import org.apache.spark.SparkConf; +import org.apache.spark.api.java.JavaPairRDD; +import org.apache.spark.api.java.JavaRDD; +import org.apache.spark.api.java.JavaSparkContext; +import org.apache.spark.api.java.Optional; +import org.apache.spark.api.java.function.FlatMapFunction; +import org.apache.spark.api.java.function.Function; +import org.apache.spark.api.java.function.Function2; +import org.apache.spark.api.java.function.Function3; +import org.apache.spark.api.java.function.PairFunction; +import org.apache.spark.api.java.function.VoidFunction; +import org.apache.spark.streaming.Durations; +import org.apache.spark.streaming.State; +import org.apache.spark.streaming.StateSpec; +import org.apache.spark.streaming.api.java.JavaDStream; +import org.apache.spark.streaming.api.java.JavaInputDStream; +import org.apache.spark.streaming.api.java.JavaMapWithStateDStream; +import org.apache.spark.streaming.api.java.JavaPairDStream; +import org.apache.spark.streaming.api.java.JavaStreamingContext; +import org.apache.spark.streaming.kafka010.ConsumerStrategies; +import org.apache.spark.streaming.kafka010.KafkaUtils; +import org.apache.spark.streaming.kafka010.LocationStrategies; + +import scala.Tuple2; + +public class WordCountingAppWithCheckpoint { + + public static JavaSparkContext sparkContext; + + @SuppressWarnings("serial") + public static void main(String[] args) throws InterruptedException { + + Logger.getLogger("org") + .setLevel(Level.OFF); + Logger.getLogger("akka") + .setLevel(Level.OFF); + + Map kafkaParams = new HashMap<>(); + kafkaParams.put("bootstrap.servers", "localhost:9092"); + kafkaParams.put("key.deserializer", StringDeserializer.class); + kafkaParams.put("value.deserializer", StringDeserializer.class); + kafkaParams.put("group.id", "use_a_separate_group_id_for_each_stream"); + kafkaParams.put("auto.offset.reset", "latest"); + kafkaParams.put("enable.auto.commit", false); + + Collection topics = Arrays.asList("messages"); + + SparkConf sparkConf = new SparkConf(); + sparkConf.setMaster("local[2]"); + sparkConf.setAppName("WordCountingAppWithCheckpoint"); + sparkConf.set("spark.cassandra.connection.host", "127.0.0.1"); + + JavaStreamingContext streamingContext = new JavaStreamingContext(sparkConf, Durations.seconds(1)); + + sparkContext = streamingContext.sparkContext(); + + streamingContext.checkpoint("./.checkpoint"); + + JavaInputDStream> messages = KafkaUtils.createDirectStream(streamingContext, LocationStrategies.PreferConsistent(), ConsumerStrategies. Subscribe(topics, kafkaParams)); + + JavaPairDStream results = messages.mapToPair(new PairFunction, String, String>() { + @Override + public Tuple2 call(ConsumerRecord record) { + return new Tuple2<>(record.key(), record.value()); + } + }); + + JavaDStream lines = results.map(new Function, String>() { + @Override + public String call(Tuple2 tuple2) { + return tuple2._2(); + } + }); + + JavaDStream words = lines.flatMap(new FlatMapFunction() { + @Override + public Iterator call(String x) { + return Arrays.asList(x.split("\\s+")) + .iterator(); + } + }); + + JavaPairDStream wordCounts = words.mapToPair(new PairFunction() { + @Override + public Tuple2 call(String s) { + return new Tuple2<>(s, 1); + } + }) + .reduceByKey(new Function2() { + @Override + public Integer call(Integer i1, Integer i2) { + return i1 + i2; + } + }); + + Function3, State, Tuple2> mappingFunc = (word, one, state) -> { + int sum = one.orElse(0) + (state.exists() ? state.get() : 0); + Tuple2 output = new Tuple2<>(word, sum); + state.update(sum); + return output; + }; + + JavaPairRDD initialRDD = JavaPairRDD.fromJavaRDD(sparkContext.emptyRDD()); + + JavaMapWithStateDStream> cumulativeWordCounts = wordCounts.mapWithState(StateSpec.function(mappingFunc) + .initialState(initialRDD)); + + cumulativeWordCounts.foreachRDD(new VoidFunction>>() { + @Override + public void call(JavaRDD> javaRdd) throws Exception { + List> wordCountList = javaRdd.collect(); + for (Tuple2 tuple : wordCountList) { + List words = Arrays.asList(new Word(tuple._1, tuple._2)); + JavaRDD rdd = sparkContext.parallelize(words); + javaFunctions(rdd).writerBuilder("vocabulary", "words", mapToRow(Word.class)) + .saveToCassandra(); + } + } + }); + + streamingContext.start(); + streamingContext.awaitTermination(); + } +} \ No newline at end of file diff --git a/core-java-11/README.md b/core-java-11/README.md index 181ada3f45..c8039f4bc5 100644 --- a/core-java-11/README.md +++ b/core-java-11/README.md @@ -2,4 +2,4 @@ - [Java 11 Single File Source Code](https://www.baeldung.com/java-single-file-source-code) - [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) diff --git a/core-java-8/README.md b/core-java-8/README.md index e5fa953cc7..892dc71f76 100644 --- a/core-java-8/README.md +++ b/core-java-8/README.md @@ -33,3 +33,8 @@ - [Java Primitives versus Objects](https://www.baeldung.com/java-primitives-vs-objects) - [How to Use if/else Logic in Java 8 Streams](https://www.baeldung.com/java-8-streams-if-else-logic) - [How to Replace Many if Statements in Java](https://www.baeldung.com/java-replace-if-statements) +- [Java @Override Annotation](https://www.baeldung.com/java-override) +- [Java @SuppressWarnings Annotation](https://www.baeldung.com/java-suppresswarnings) +- [Java @SafeVarargs Annotation](https://www.baeldung.com/java-safevarargs) +- [Java @Deprecated Annotation](https://www.baeldung.com/java-deprecated) +- [Java 8 Predicate Chain](https://www.baeldung.com/java-predicate-chain) diff --git a/core-java-9/src/main/java/com/baeldung/java9/set/UnmodifiableSet.java b/core-java-9/src/main/java/com/baeldung/java9/set/UnmodifiableSet.java new file mode 100644 index 0000000000..7dbcd2a3a3 --- /dev/null +++ b/core-java-9/src/main/java/com/baeldung/java9/set/UnmodifiableSet.java @@ -0,0 +1,44 @@ +package com.baeldung.java9.set; + +import com.google.common.collect.ImmutableSet; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +public class UnmodifiableSet { + + public static void main(String[] args) { + + Set set = new HashSet<>(); + set.add("Canada"); + set.add("USA"); + + coreJDK(set); + guavaOf(); + copyOf(set); + java9Of(); + } + + private static void java9Of() { + Set immutable = Set.of("Canada", "USA"); + System.out.println(immutable); + } + + private static void guavaOf() { + Set immutable = ImmutableSet.of("Canada", "USA"); + System.out.println(immutable); + } + + private static void copyOf(Set set) { + Set immutable = ImmutableSet.copyOf(set); + set.add("Costa Rica"); + System.out.println(immutable); + } + + private static void coreJDK(Set set) { + Set unmodifiableSet = Collections.unmodifiableSet(set); + set.add("Costa Rica"); + System.out.println(unmodifiableSet); + } +} diff --git a/core-java-9/src/test/java/com/baeldung/java9/SetExamplesUnitTest.java b/core-java-9/src/test/java/com/baeldung/java9/SetExamplesUnitTest.java index 9e7e8e6e4b..28e71affcc 100644 --- a/core-java-9/src/test/java/com/baeldung/java9/SetExamplesUnitTest.java +++ b/core-java-9/src/test/java/com/baeldung/java9/SetExamplesUnitTest.java @@ -1,5 +1,7 @@ package com.baeldung.java9; +import java.util.Collections; +import java.util.HashSet; import java.util.Set; import org.junit.Test; @@ -23,4 +25,14 @@ public class SetExamplesUnitTest { Set intSet = Set.of(intArray); assertEquals(intSet.size(), intArray.length); } + + @Test(expected = UnsupportedOperationException.class) + public void testUnmodifiableSet() { + Set set = new HashSet<>(); + set.add("Canada"); + set.add("USA"); + + Set unmodifiableSet = Collections.unmodifiableSet(set); + unmodifiableSet.add("Costa Rica"); + } } diff --git a/core-java-arrays/README.md b/core-java-arrays/README.md index 56110585ac..400dd7793c 100644 --- a/core-java-arrays/README.md +++ b/core-java-arrays/README.md @@ -13,3 +13,4 @@ - [How to Invert an Array in Java](http://www.baeldung.com/java-invert-array) - [Array Operations in Java](http://www.baeldung.com/java-common-array-operations) - [Intersection Between two Integer Arrays](https://www.baeldung.com/java-array-intersection) +- [Sorting Arrays in Java](https://www.baeldung.com/java-sorting-arrays) diff --git a/core-java-collections-list/README.md b/core-java-collections-list/README.md index aba53f5b30..a35e714006 100644 --- a/core-java-collections-list/README.md +++ b/core-java-collections-list/README.md @@ -24,4 +24,5 @@ - [Java List Initialization in One Line](https://www.baeldung.com/java-init-list-one-line) - [Ways to Iterate Over a List in Java](https://www.baeldung.com/java-iterate-list) - [ClassCastException: Arrays$ArrayList cannot be cast to ArrayList](https://www.baeldung.com/java-classcastexception-arrays-arraylist) -- [Flattening Nested Collections in Java](http://www.baeldung.com/java-flatten-nested-collections) \ No newline at end of file +- [Flattening Nested Collections in Java](http://www.baeldung.com/java-flatten-nested-collections) +- [Intersection of Two Lists in Java](https://www.baeldung.com/java-lists-intersection) diff --git a/core-java-collections-list/src/main/java/com/baeldung/list/multidimensional/ArrayListOfArrayList.java b/core-java-collections-list/src/main/java/com/baeldung/list/multidimensional/ArrayListOfArrayList.java index 2c3da7b1fc..e11f8e8ba0 100644 --- a/core-java-collections-list/src/main/java/com/baeldung/list/multidimensional/ArrayListOfArrayList.java +++ b/core-java-collections-list/src/main/java/com/baeldung/list/multidimensional/ArrayListOfArrayList.java @@ -6,11 +6,11 @@ public class ArrayListOfArrayList { public static void main(String args[]) { - int numVertices = 3; - ArrayList> graph = new ArrayList<>(numVertices); + int vertexCount = 3; + ArrayList> graph = new ArrayList<>(vertexCount); //Initializing each element of ArrayList with ArrayList - for(int i=0; i< numVertices; i++) { + for(int i = 0; i< vertexCount; i++) { graph.add(new ArrayList()); } @@ -21,13 +21,14 @@ public class ArrayListOfArrayList { graph.get(1).add(0); graph.get(2).add(1); graph.get(0).add(2); - - //Printing all the edges - for(int vertexNo=0; vertexNo listOfVertices = graph.get(vertexNo); - for(int i=0; i > > space = new ArrayList<>(x_axis_length); //Initializing each element of ArrayList with ArrayList< ArrayList > - for(int i=0; i< x_axis_length; i++) { + for(int i = 0; i < x_axis_length; i++) { space.add(new ArrayList< ArrayList >(y_axis_length)); - for(int j =0; j< y_axis_length; j++) { + for(int j = 0; j < y_axis_length; j++) { space.get(i).add(new ArrayList(z_axis_length)); } } @@ -33,9 +33,9 @@ public class ThreeDimensionalArrayList { space.get(1).get(1).add(1,"Yellow"); //Printing colors for all the points - for(int i=0; i${opencsv.version} test + + + org.apache.tika + tika-core + ${tika.version} + + + net.sf.jmimemagic + jmimemagic + ${jmime-magic.version} + @@ -264,6 +275,9 @@ 2.1.0.1 1.19 2.4.5 + + 1.18 + 0.1.5 \ No newline at end of file diff --git a/core-java/src/main/java/com/baeldung/extension/Extension.java b/core-java-io/src/main/java/com/baeldung/extension/Extension.java similarity index 100% rename from core-java/src/main/java/com/baeldung/extension/Extension.java rename to core-java-io/src/main/java/com/baeldung/extension/Extension.java diff --git a/core-java/src/test/java/com/baeldung/extension/ExtensionUnitTest.java b/core-java-io/src/test/java/com/baeldung/extension/ExtensionUnitTest.java similarity index 100% rename from core-java/src/test/java/com/baeldung/extension/ExtensionUnitTest.java rename to core-java-io/src/test/java/com/baeldung/extension/ExtensionUnitTest.java diff --git a/core-java/src/test/java/com/baeldung/java/mimetype/MimeTypeUnitTest.java b/core-java-io/src/test/java/com/baeldung/java/mimetype/MimeTypeUnitTest.java similarity index 100% rename from core-java/src/test/java/com/baeldung/java/mimetype/MimeTypeUnitTest.java rename to core-java-io/src/test/java/com/baeldung/java/mimetype/MimeTypeUnitTest.java diff --git a/core-java/src/test/resources/META-INF/mime.types b/core-java-io/src/test/resources/META-INF/mime.types similarity index 100% rename from core-java/src/test/resources/META-INF/mime.types rename to core-java-io/src/test/resources/META-INF/mime.types diff --git a/core-java/src/test/resources/product.png b/core-java-io/src/test/resources/product.png similarity index 100% rename from core-java/src/test/resources/product.png rename to core-java-io/src/test/resources/product.png diff --git a/core-java-lang/README.md b/core-java-lang/README.md index 52dfe708a3..7af962558d 100644 --- a/core-java-lang/README.md +++ b/core-java-lang/README.md @@ -33,3 +33,5 @@ - [How to Separate Double into Integer and Decimal Parts](https://www.baeldung.com/java-separate-double-into-integer-decimal-parts) - [“Sneaky Throws” in Java](http://www.baeldung.com/java-sneaky-throws) - [Retrieving a Class Name in Java](https://www.baeldung.com/java-class-name) +- [Java Compound Operators](https://www.baeldung.com/java-compound-operators) +- [Guide to Java Packages](https://www.baeldung.com/java-packages) \ No newline at end of file diff --git a/core-java/native/nativedatetimeutils.dll b/core-java-lang/native/nativedatetimeutils.dll similarity index 100% rename from core-java/native/nativedatetimeutils.dll rename to core-java-lang/native/nativedatetimeutils.dll diff --git a/core-java/src/main/java/com/baeldung/nativekeyword/DateTimeUtils.java b/core-java-lang/src/main/java/com/baeldung/nativekeyword/DateTimeUtils.java similarity index 100% rename from core-java/src/main/java/com/baeldung/nativekeyword/DateTimeUtils.java rename to core-java-lang/src/main/java/com/baeldung/nativekeyword/DateTimeUtils.java diff --git a/core-java/src/main/java/com/baeldung/nativekeyword/NativeMainApp.java b/core-java-lang/src/main/java/com/baeldung/nativekeyword/NativeMainApp.java similarity index 100% rename from core-java/src/main/java/com/baeldung/nativekeyword/NativeMainApp.java rename to core-java-lang/src/main/java/com/baeldung/nativekeyword/NativeMainApp.java diff --git a/core-java/src/test/java/com/baeldung/nativekeyword/DateTimeUtilsManualTest.java b/core-java-lang/src/test/java/com/baeldung/nativekeyword/DateTimeUtilsManualTest.java similarity index 100% rename from core-java/src/test/java/com/baeldung/nativekeyword/DateTimeUtilsManualTest.java rename to core-java-lang/src/test/java/com/baeldung/nativekeyword/DateTimeUtilsManualTest.java diff --git a/core-java-security/README.md b/core-java-security/README.md new file mode 100644 index 0000000000..415171094b --- /dev/null +++ b/core-java-security/README.md @@ -0,0 +1,11 @@ +## Core Java Security + +### Relevant Articles: +- [MD5 Hashing in Java](http://www.baeldung.com/java-md5) +- [Guide to the Cipher Class](http://www.baeldung.com/java-cipher-class) +- [Introduction to SSL in Java](http://www.baeldung.com/java-ssl) +- [Java KeyStore API](http://www.baeldung.com/java-keystore) +- [Encrypting and Decrypting Files in Java](http://www.baeldung.com/java-cipher-input-output-stream) +- [Hashing a Password in Java](https://www.baeldung.com/java-password-hashing) +- [SSL Handshake Failures](https://www.baeldung.com/java-ssl-handshake-failures) +- [SHA-256 Hashing in Java](https://www.baeldung.com/sha-256-hashing-java) \ No newline at end of file diff --git a/core-java-security/pom.xml b/core-java-security/pom.xml new file mode 100644 index 0000000000..cf91121465 --- /dev/null +++ b/core-java-security/pom.xml @@ -0,0 +1,55 @@ + + 4.0.0 + com.baeldung + core-java-security + 0.1.0-SNAPSHOT + jar + core-java-security + + + com.baeldung + parent-java + 0.0.1-SNAPSHOT + ../parent-java + + + + + org.apache.commons + commons-lang3 + ${commons-lang3.version} + + + + org.assertj + assertj-core + ${assertj-core.version} + test + + + + commons-codec + commons-codec + ${commons-codec.version} + + + org.bouncycastle + bcprov-jdk15on + ${bouncycastle.version} + + + + + + + 3.8.1 + 1.55 + 1.10 + + + 3.10.0 + + + + diff --git a/core-java/src/main/java/com/baeldung/cipher/Encryptor.java b/core-java-security/src/main/java/com/baeldung/cipher/Encryptor.java similarity index 100% rename from core-java/src/main/java/com/baeldung/cipher/Encryptor.java rename to core-java-security/src/main/java/com/baeldung/cipher/Encryptor.java diff --git a/core-java/src/main/java/com/baeldung/encrypt/FileEncrypterDecrypter.java b/core-java-security/src/main/java/com/baeldung/encrypt/FileEncrypterDecrypter.java similarity index 100% rename from core-java/src/main/java/com/baeldung/encrypt/FileEncrypterDecrypter.java rename to core-java-security/src/main/java/com/baeldung/encrypt/FileEncrypterDecrypter.java diff --git a/core-java/src/main/java/com/baeldung/hashing/SHA256Hashing.java b/core-java-security/src/main/java/com/baeldung/hashing/SHA256Hashing.java similarity index 100% rename from core-java/src/main/java/com/baeldung/hashing/SHA256Hashing.java rename to core-java-security/src/main/java/com/baeldung/hashing/SHA256Hashing.java diff --git a/core-java/src/main/java/com/baeldung/keystore/JavaKeyStore.java b/core-java-security/src/main/java/com/baeldung/keystore/JavaKeyStore.java similarity index 100% rename from core-java/src/main/java/com/baeldung/keystore/JavaKeyStore.java rename to core-java-security/src/main/java/com/baeldung/keystore/JavaKeyStore.java diff --git a/core-java/src/main/java/com/baeldung/passwordhashing/PBKDF2Hasher.java b/core-java-security/src/main/java/com/baeldung/passwordhashing/PBKDF2Hasher.java similarity index 100% rename from core-java/src/main/java/com/baeldung/passwordhashing/PBKDF2Hasher.java rename to core-java-security/src/main/java/com/baeldung/passwordhashing/PBKDF2Hasher.java diff --git a/core-java/src/main/java/com/baeldung/passwordhashing/SHA512Hasher.java b/core-java-security/src/main/java/com/baeldung/passwordhashing/SHA512Hasher.java similarity index 100% rename from core-java/src/main/java/com/baeldung/passwordhashing/SHA512Hasher.java rename to core-java-security/src/main/java/com/baeldung/passwordhashing/SHA512Hasher.java diff --git a/core-java/src/main/java/com/baeldung/passwordhashing/SimplePBKDF2Hasher.java b/core-java-security/src/main/java/com/baeldung/passwordhashing/SimplePBKDF2Hasher.java similarity index 100% rename from core-java/src/main/java/com/baeldung/passwordhashing/SimplePBKDF2Hasher.java rename to core-java-security/src/main/java/com/baeldung/passwordhashing/SimplePBKDF2Hasher.java diff --git a/core-java/src/main/java/com/baeldung/ssl/SecureConnection.java b/core-java-security/src/main/java/com/baeldung/ssl/SecureConnection.java similarity index 100% rename from core-java/src/main/java/com/baeldung/ssl/SecureConnection.java rename to core-java-security/src/main/java/com/baeldung/ssl/SecureConnection.java diff --git a/core-java/src/main/java/com/baeldung/ssl/example/SimpleClient.java b/core-java-security/src/main/java/com/baeldung/ssl/example/SimpleClient.java similarity index 100% rename from core-java/src/main/java/com/baeldung/ssl/example/SimpleClient.java rename to core-java-security/src/main/java/com/baeldung/ssl/example/SimpleClient.java diff --git a/core-java/src/main/java/com/baeldung/ssl/example/SimpleServer.java b/core-java-security/src/main/java/com/baeldung/ssl/example/SimpleServer.java similarity index 100% rename from core-java/src/main/java/com/baeldung/ssl/example/SimpleServer.java rename to core-java-security/src/main/java/com/baeldung/ssl/example/SimpleServer.java diff --git a/core-java-security/src/main/resources/logback.xml b/core-java-security/src/main/resources/logback.xml new file mode 100644 index 0000000000..56af2d397e --- /dev/null +++ b/core-java-security/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/core-java/src/test/java/com/baeldung/cipher/EncryptorUnitTest.java b/core-java-security/src/test/java/com/baeldung/cipher/EncryptorUnitTest.java similarity index 100% rename from core-java/src/test/java/com/baeldung/cipher/EncryptorUnitTest.java rename to core-java-security/src/test/java/com/baeldung/cipher/EncryptorUnitTest.java diff --git a/core-java/src/test/java/com/baeldung/encrypt/FileEncrypterDecrypterIntegrationTest.java b/core-java-security/src/test/java/com/baeldung/encrypt/FileEncrypterDecrypterIntegrationTest.java similarity index 100% rename from core-java/src/test/java/com/baeldung/encrypt/FileEncrypterDecrypterIntegrationTest.java rename to core-java-security/src/test/java/com/baeldung/encrypt/FileEncrypterDecrypterIntegrationTest.java diff --git a/core-java/src/test/java/com/baeldung/hashing/SHA256HashingUnitTest.java b/core-java-security/src/test/java/com/baeldung/hashing/SHA256HashingUnitTest.java similarity index 100% rename from core-java/src/test/java/com/baeldung/hashing/SHA256HashingUnitTest.java rename to core-java-security/src/test/java/com/baeldung/hashing/SHA256HashingUnitTest.java diff --git a/core-java/src/test/java/com/baeldung/keystore/JavaKeyStoreUnitTest.java b/core-java-security/src/test/java/com/baeldung/keystore/JavaKeyStoreUnitTest.java similarity index 100% rename from core-java/src/test/java/com/baeldung/keystore/JavaKeyStoreUnitTest.java rename to core-java-security/src/test/java/com/baeldung/keystore/JavaKeyStoreUnitTest.java diff --git a/core-java/src/test/java/com/baeldung/passwordhashing/PBKDF2HasherUnitTest.java b/core-java-security/src/test/java/com/baeldung/passwordhashing/PBKDF2HasherUnitTest.java similarity index 100% rename from core-java/src/test/java/com/baeldung/passwordhashing/PBKDF2HasherUnitTest.java rename to core-java-security/src/test/java/com/baeldung/passwordhashing/PBKDF2HasherUnitTest.java diff --git a/core-java/src/test/java/com/baeldung/passwordhashing/SHA512HasherUnitTest.java b/core-java-security/src/test/java/com/baeldung/passwordhashing/SHA512HasherUnitTest.java similarity index 100% rename from core-java/src/test/java/com/baeldung/passwordhashing/SHA512HasherUnitTest.java rename to core-java-security/src/test/java/com/baeldung/passwordhashing/SHA512HasherUnitTest.java diff --git a/core-java/src/test/java/org/baeldung/java/md5/JavaMD5UnitTest.java b/core-java-security/src/test/java/org/baeldung/java/md5/JavaMD5UnitTest.java similarity index 100% rename from core-java/src/test/java/org/baeldung/java/md5/JavaMD5UnitTest.java rename to core-java-security/src/test/java/org/baeldung/java/md5/JavaMD5UnitTest.java diff --git a/core-java/src/test/resources/test_md5.txt b/core-java-security/src/test/resources/test_md5.txt similarity index 100% rename from core-java/src/test/resources/test_md5.txt rename to core-java-security/src/test/resources/test_md5.txt diff --git a/core-java/README.md b/core-java/README.md index 21c58bb880..5aee69d9a9 100644 --- a/core-java/README.md +++ b/core-java/README.md @@ -5,7 +5,6 @@ ### Relevant Articles: - [Java Timer](http://www.baeldung.com/java-timer-and-timertask) - [How to Run a Shell Command in Java](http://www.baeldung.com/run-shell-command-in-java) -- [MD5 Hashing in Java](http://www.baeldung.com/java-md5) - [How to Print Screen in Java](http://www.baeldung.com/print-screen-in-java) - [A Guide To Java Regular Expressions API](http://www.baeldung.com/regular-expressions-java) - [Getting Started with Java Properties](http://www.baeldung.com/java-properties) @@ -23,44 +22,27 @@ - [Difference between URL and URI](http://www.baeldung.com/java-url-vs-uri) - [Creating a Java Compiler Plugin](http://www.baeldung.com/java-build-compiler-plugin) - [Quick Guide to Java Stack](http://www.baeldung.com/java-stack) -- [Guide to java.util.Formatter](http://www.baeldung.com/java-string-formatter) -- [Guide to the Cipher Class](http://www.baeldung.com/java-cipher-class) - [Compiling Java *.class Files with javac](http://www.baeldung.com/javac) -- [A Guide to Iterator in Java](http://www.baeldung.com/java-iterator) - [Introduction to Javadoc](http://www.baeldung.com/javadoc) - [Guide to the Externalizable Interface in Java](http://www.baeldung.com/java-externalizable) -- [A Practical Guide to DecimalFormat](http://www.baeldung.com/java-decimalformat) - [How to Detect the OS Using Java](http://www.baeldung.com/java-detect-os) - [ASCII Art in Java](http://www.baeldung.com/ascii-art-in-java) - [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) -- [Introduction to SSL in Java](http://www.baeldung.com/java-ssl) -- [Java KeyStore API](http://www.baeldung.com/java-keystore) - [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) - [Importance of Main Manifest Attribute in a Self-Executing JAR](http://www.baeldung.com/java-jar-executable-manifest-main-class) -- [How to Get the File Extension of a File in Java](http://www.baeldung.com/java-file-extension) - [Java Global Exception Handler](http://www.baeldung.com/java-global-exception-handler) -- [Encrypting and Decrypting Files in Java](http://www.baeldung.com/java-cipher-input-output-stream) - [How to Get the Size of an Object in Java](http://www.baeldung.com/java-size-of-object) - [Guide to Java Instrumentation](http://www.baeldung.com/java-instrumentation) -- [Getting a File’s Mime Type in Java](http://www.baeldung.com/java-file-mime-type) - [Common Java Exceptions](http://www.baeldung.com/java-common-exceptions) - [Throw Exception in Optional in Java 8](https://www.baeldung.com/java-optional-throw-exception) -- [Add a Character to a String at a Given Position](https://www.baeldung.com/java-add-character-to-string) -- [Calculating the nth Root in Java](https://www.baeldung.com/java-nth-root) -- [Convert Double to String, Removing Decimal Places](https://www.baeldung.com/java-double-to-string) -- [ZoneOffset in Java](https://www.baeldung.com/java-zone-offset) -- [Hashing a Password in Java](https://www.baeldung.com/java-password-hashing) - [Merging java.util.Properties Objects](https://www.baeldung.com/java-merging-properties) -- [A Guide to SimpleDateFormat](https://www.baeldung.com/java-simple-date-format) -- [SSL Handshake Failures](https://www.baeldung.com/java-ssl-handshake-failures) -- [Changing the Order in a Sum Operation Can Produce Different Results?](https://www.baeldung.com/java-floating-point-sum-order) +- [Merging java.util.Properties Objects](https://www.baeldung.com/java-merging-properties) - [Java – Try with Resources](https://www.baeldung.com/java-try-with-resources) - [Abstract Classes in Java](https://www.baeldung.com/java-abstract-class) - [Guide to Character Encoding](https://www.baeldung.com/java-char-encoding) -- [Calculate the Area of a Circle in Java](https://www.baeldung.com/java-calculate-circle-area) -- [A Guide to the Java Math Class](https://www.baeldung.com/java-lang-math) - [Graphs in Java](https://www.baeldung.com/java-graphs) - [Console I/O in Java](http://www.baeldung.com/java-console-input-output) +- [Formatting with printf() in Java](https://www.baeldung.com/java-printstream-printf) diff --git a/core-java/pom.xml b/core-java/pom.xml index b4f0643aa8..6c58653d5a 100644 --- a/core-java/pom.xml +++ b/core-java/pom.xml @@ -24,11 +24,6 @@ commons-lang3 ${commons-lang3.version} - - org.bouncycastle - bcprov-jdk15on - ${bouncycastle.version} - org.unix4j unix4j-command @@ -75,12 +70,6 @@ ${assertj-core.version} test - - - commons-codec - commons-codec - ${commons-codec.version} - org.javamoney moneta @@ -126,17 +115,6 @@ h2 ${h2database.version} - - - org.apache.tika - tika-core - ${tika.version} - - - net.sf.jmimemagic - jmimemagic - ${jmime-magic.version} - org.javassist @@ -477,8 +455,6 @@ 3.5 - 1.55 - 1.10 2.5 3.6.1 1.0.3 @@ -509,9 +485,6 @@ 2.0.3.RELEASE 1.6.0 61.1 - - 1.18 - 0.1.5 3.21.0-GA diff --git a/core-java/src/main/java/com/baeldung/curltojava/JavaCurlExamples.java b/core-java/src/main/java/com/baeldung/curltojava/JavaCurlExamples.java new file mode 100644 index 0000000000..166b0ecb13 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/curltojava/JavaCurlExamples.java @@ -0,0 +1,29 @@ +package com.baeldung.curltojava; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class JavaCurlExamples { + + public static String inputStreamToString(InputStream inputStream) { + final int bufferSize = 8 * 1024; + byte[] buffer = new byte[bufferSize]; + final StringBuilder builder = new StringBuilder(); + try (BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream, bufferSize)) { + while (bufferedInputStream.read(buffer) != -1) { + builder.append(new String(buffer)); + } + } catch (IOException ex) { + Logger.getLogger(JavaCurlExamples.class.getName()).log(Level.SEVERE, null, ex); + } + return builder.toString(); + } + + public static void consumeInputStream(InputStream inputStream) { + inputStreamToString(inputStream); + } + +} diff --git a/core-java/src/test/java/com/baeldung/curltojava/JavaCurlExamplesUnitTest.java b/core-java/src/test/java/com/baeldung/curltojava/JavaCurlExamplesUnitTest.java new file mode 100644 index 0000000000..4e82059f2b --- /dev/null +++ b/core-java/src/test/java/com/baeldung/curltojava/JavaCurlExamplesUnitTest.java @@ -0,0 +1,55 @@ +package com.baeldung.curltojava; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; + +import org.junit.Assert; +import org.junit.Test; + +public class JavaCurlExamplesUnitTest { + + + @Test + public void givenCommand_whenCalled_thenProduceZeroExitCode() throws IOException { + String command = "curl --location --request GET \"https://postman-echo.com/get?foo1=bar1&foo2=bar2\""; + ProcessBuilder processBuilder = new ProcessBuilder(command.replaceAll("\"", "").split(" ")); + processBuilder.directory(new File("/home/")); + Process process = processBuilder.start(); + InputStream inputStream = process.getInputStream(); + // Consume the inputStream so the process can exit + JavaCurlExamples.consumeInputStream(inputStream); + int exitCode = process.exitValue(); + + Assert.assertEquals(0, exitCode); + } + + @Test + public void givenNewCommands_whenCalled_thenCheckIfIsAlive() throws IOException { + String command = "curl --location --request GET \"https://postman-echo.com/get?foo1=bar1&foo2=bar2\""; + ProcessBuilder processBuilder = new ProcessBuilder(command.replaceAll("\"", "").split(" ")); + processBuilder.directory(new File("/home/")); + Process process = processBuilder.start(); + + // Re-use processBuilder + processBuilder.command(new String[]{"newCommand", "arguments"}); + + Assert.assertEquals(true, process.isAlive()); + } + + @Test + public void whenRequestGet_thenReturnSuccessResponseCode() throws IOException { + String url = "https://postman-echo.com/get?foo1=bar1&foo2=bar2"; + URL urlObj = new URL(url); + HttpURLConnection connection = (HttpURLConnection) urlObj.openConnection(); + connection.setDoOutput(true); + connection.setInstanceFollowRedirects(false); + connection.setRequestMethod("GET"); + connection.connect(); + + Assert.assertEquals(HttpURLConnection.HTTP_OK, connection.getResponseCode()); + } + +} diff --git a/core-java/src/test/java/com/baeldung/string/StringReplaceAndRemoveUnitTest.java b/core-java/src/test/java/com/baeldung/string/StringReplaceAndRemoveUnitTest.java deleted file mode 100644 index d952d2383b..0000000000 --- a/core-java/src/test/java/com/baeldung/string/StringReplaceAndRemoveUnitTest.java +++ /dev/null @@ -1,83 +0,0 @@ -package com.baeldung.string; - - -import org.apache.commons.lang3.StringUtils; -import org.junit.Test; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -public class StringReplaceAndRemoveUnitTest { - - - @Test - public void givenTestStrings_whenReplace_thenProcessedString() { - - String master = "Hello World Baeldung!"; - String target = "Baeldung"; - String replacement = "Java"; - String processed = master.replace(target, replacement); - assertTrue(processed.contains(replacement)); - assertFalse(processed.contains(target)); - - } - - @Test - public void givenTestStrings_whenReplaceAll_thenProcessedString() { - - String master2 = "Welcome to Baeldung, Hello World Baeldung"; - String regexTarget= "(Baeldung)$"; - String replacement = "Java"; - String processed2 = master2.replaceAll(regexTarget, replacement); - assertTrue(processed2.endsWith("Java")); - - } - - @Test - public void givenTestStrings_whenStringBuilderMethods_thenProcessedString() { - - String master = "Hello World Baeldung!"; - String target = "Baeldung"; - String replacement = "Java"; - - int startIndex = master.indexOf(target); - int stopIndex = startIndex + target.length(); - - StringBuilder builder = new StringBuilder(master); - - - builder.delete(startIndex, stopIndex); - assertFalse(builder.toString().contains(target)); - - - builder.replace(startIndex, stopIndex, replacement); - assertTrue(builder.toString().contains(replacement)); - - - } - - - @Test - public void givenTestStrings_whenStringUtilsMethods_thenProcessedStrings() { - - String master = "Hello World Baeldung!"; - String target = "Baeldung"; - String replacement = "Java"; - - String processed = StringUtils.replace(master, target, replacement); - assertTrue(processed.contains(replacement)); - - String master2 = "Hello World Baeldung!"; - String target2 = "baeldung"; - String processed2 = StringUtils.replaceIgnoreCase(master2, target2, replacement); - assertFalse(processed2.contains(target)); - - } - - - - - - - -} diff --git a/core-kotlin/README.md b/core-kotlin/README.md index 05f07e7e7e..225ad87e87 100644 --- a/core-kotlin/README.md +++ b/core-kotlin/README.md @@ -47,3 +47,7 @@ - [Dependency Injection for Kotlin with Injekt](https://www.baeldung.com/kotlin-dependency-injection-with-injekt) - [Implementing a Binary Tree in Kotlin](https://www.baeldung.com/kotlin-binary-tree) - [Generate a Random Alphanumeric String in Kotlin](https://www.baeldung.com/kotlin-random-alphanumeric-string) +- [Kotlin Contracts](https://www.baeldung.com/kotlin-contracts) +- [Operator Overloading in Kotlin](https://www.baeldung.com/kotlin-operator-overloading) +- [Inline Classes in Kotlin](https://www.baeldung.com/kotlin-inline-classes) +- [Creating Java static final Equivalents in Kotlin](https://www.baeldung.com/kotlin-java-static-final) diff --git a/gson/README.md b/gson/README.md index e1eb155f43..4edd7158d4 100644 --- a/gson/README.md +++ b/gson/README.md @@ -9,3 +9,4 @@ - [Exclude Fields from Serialization in Gson](http://www.baeldung.com/gson-exclude-fields-serialization) - [Save Data to a JSON File with Gson](https://www.baeldung.com/gson-save-file) - [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) diff --git a/guava/README.md b/guava/README.md index 0346d34903..60754dbe57 100644 --- a/guava/README.md +++ b/guava/README.md @@ -18,4 +18,3 @@ - [Hamcrest Text Matchers](http://www.baeldung.com/hamcrest-text-matchers) - [Quick Guide to the Guava RateLimiter](http://www.baeldung.com/guava-rate-limiter) - [Hamcrest File Matchers](https://www.baeldung.com/hamcrest-file-matchers) -- [SHA-256 Hashing in Java](https://www.baeldung.com/sha-256-hashing-java) diff --git a/java-collections-maps/README.md b/java-collections-maps/README.md index a6037a3c57..b4ab270448 100644 --- a/java-collections-maps/README.md +++ b/java-collections-maps/README.md @@ -17,3 +17,5 @@ - [Finding the Highest Value in a Java Map](https://www.baeldung.com/java-find-map-max) - [Merging Two Maps with Java 8](https://www.baeldung.com/java-merge-maps) - [How to Check If a Key Exists in a Map](https://www.baeldung.com/java-map-key-exists) +- [Comparing Two HashMaps in Java](https://www.baeldung.com/java-compare-hashmaps) +- [Immutable Map Implementations in Java](https://www.baeldung.com/java-immutable-maps) diff --git a/java-dates/README.md b/java-dates/README.md index 21e54082f4..ac3166d938 100644 --- a/java-dates/README.md +++ b/java-dates/README.md @@ -26,3 +26,5 @@ - [Format ZonedDateTime to String](https://www.baeldung.com/java-format-zoned-datetime-string) - [Convert Between java.time.Instant and java.sql.Timestamp](https://www.baeldung.com/java-time-instant-to-java-sql-timestamp) - [Convert between String and Timestamp](https://www.baeldung.com/java-string-to-timestamp) +- [A Guide to SimpleDateFormat](https://www.baeldung.com/java-simple-date-format) +- [ZoneOffset in Java](https://www.baeldung.com/java-zone-offset) \ No newline at end of file diff --git a/core-java/src/main/java/com/baeldung/zoneddatetime/OffsetDateTimeExample.java b/java-dates/src/main/java/com/baeldung/zoneddatetime/OffsetDateTimeExample.java similarity index 100% rename from core-java/src/main/java/com/baeldung/zoneddatetime/OffsetDateTimeExample.java rename to java-dates/src/main/java/com/baeldung/zoneddatetime/OffsetDateTimeExample.java diff --git a/core-java/src/main/java/com/baeldung/zoneddatetime/OffsetTimeExample.java b/java-dates/src/main/java/com/baeldung/zoneddatetime/OffsetTimeExample.java similarity index 100% rename from core-java/src/main/java/com/baeldung/zoneddatetime/OffsetTimeExample.java rename to java-dates/src/main/java/com/baeldung/zoneddatetime/OffsetTimeExample.java diff --git a/core-java/src/main/java/com/baeldung/zoneddatetime/ZoneDateTimeExample.java b/java-dates/src/main/java/com/baeldung/zoneddatetime/ZoneDateTimeExample.java similarity index 100% rename from core-java/src/main/java/com/baeldung/zoneddatetime/ZoneDateTimeExample.java rename to java-dates/src/main/java/com/baeldung/zoneddatetime/ZoneDateTimeExample.java diff --git a/java-dates/src/test/java/com/baeldung/date/DateDiffUnitTest.java b/java-dates/src/test/java/com/baeldung/date/DateDiffUnitTest.java index 1234a700de..a35699e469 100644 --- a/java-dates/src/test/java/com/baeldung/date/DateDiffUnitTest.java +++ b/java-dates/src/test/java/com/baeldung/date/DateDiffUnitTest.java @@ -8,6 +8,8 @@ import java.time.Duration; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.Period; +import java.time.ZoneId; +import java.time.ZonedDateTime; import java.time.temporal.ChronoUnit; import java.util.Date; import java.util.Locale; diff --git a/core-java/src/test/java/com/baeldung/simpledateformat/SimpleDateFormatUnitTest.java b/java-dates/src/test/java/com/baeldung/simpledateformat/SimpleDateFormatUnitTest.java similarity index 100% rename from core-java/src/test/java/com/baeldung/simpledateformat/SimpleDateFormatUnitTest.java rename to java-dates/src/test/java/com/baeldung/simpledateformat/SimpleDateFormatUnitTest.java diff --git a/core-java/src/test/java/com/baeldung/zoneddatetime/OffsetDateTimeExampleUnitTest.java b/java-dates/src/test/java/com/baeldung/zoneddatetime/OffsetDateTimeExampleUnitTest.java similarity index 100% rename from core-java/src/test/java/com/baeldung/zoneddatetime/OffsetDateTimeExampleUnitTest.java rename to java-dates/src/test/java/com/baeldung/zoneddatetime/OffsetDateTimeExampleUnitTest.java diff --git a/core-java/src/test/java/com/baeldung/zoneddatetime/OffsetTimeExampleUnitTest.java b/java-dates/src/test/java/com/baeldung/zoneddatetime/OffsetTimeExampleUnitTest.java similarity index 100% rename from core-java/src/test/java/com/baeldung/zoneddatetime/OffsetTimeExampleUnitTest.java rename to java-dates/src/test/java/com/baeldung/zoneddatetime/OffsetTimeExampleUnitTest.java diff --git a/core-java/src/test/java/com/baeldung/zoneddatetime/ZoneDateTimeExampleUnitTest.java b/java-dates/src/test/java/com/baeldung/zoneddatetime/ZoneDateTimeExampleUnitTest.java similarity index 100% rename from core-java/src/test/java/com/baeldung/zoneddatetime/ZoneDateTimeExampleUnitTest.java rename to java-dates/src/test/java/com/baeldung/zoneddatetime/ZoneDateTimeExampleUnitTest.java diff --git a/java-numbers/README.md b/java-numbers/README.md index 1138d9a74c..2b1131f325 100644 --- a/java-numbers/README.md +++ b/java-numbers/README.md @@ -13,3 +13,9 @@ - [Find All Pairs of Numbers in an Array That Add Up to a Given Sum](http://www.baeldung.com/java-algorithm-number-pairs-sum) - [Java – Random Long, Float, Integer and Double](http://www.baeldung.com/java-generate-random-long-float-integer-double) - [Using Math.sin with Degrees](https://www.baeldung.com/java-math-sin-degrees) +- [A Practical Guide to DecimalFormat](http://www.baeldung.com/java-decimalformat) +- [Calculating the nth Root in Java](https://www.baeldung.com/java-nth-root) +- [Convert Double to String, Removing Decimal Places](https://www.baeldung.com/java-double-to-string) +- [Changing the Order in a Sum Operation Can Produce Different Results?](https://www.baeldung.com/java-floating-point-sum-order) +- [Calculate the Area of a Circle in Java](https://www.baeldung.com/java-calculate-circle-area) +- [A Guide to the Java Math Class](https://www.baeldung.com/java-lang-math) \ No newline at end of file diff --git a/core-java/src/main/java/com/baeldung/area/circle/Circle.java b/java-numbers/src/main/java/com/baeldung/area/circle/Circle.java similarity index 100% rename from core-java/src/main/java/com/baeldung/area/circle/Circle.java rename to java-numbers/src/main/java/com/baeldung/area/circle/Circle.java diff --git a/core-java/src/main/java/com/baeldung/area/circle/CircleArea.java b/java-numbers/src/main/java/com/baeldung/area/circle/CircleArea.java similarity index 100% rename from core-java/src/main/java/com/baeldung/area/circle/CircleArea.java rename to java-numbers/src/main/java/com/baeldung/area/circle/CircleArea.java diff --git a/core-java/src/main/java/com/baeldung/nth/root/calculator/NthRootCalculator.java b/java-numbers/src/main/java/com/baeldung/nth/root/calculator/NthRootCalculator.java similarity index 100% rename from core-java/src/main/java/com/baeldung/nth/root/calculator/NthRootCalculator.java rename to java-numbers/src/main/java/com/baeldung/nth/root/calculator/NthRootCalculator.java diff --git a/core-java/src/main/java/com/baeldung/nth/root/main/Main.java b/java-numbers/src/main/java/com/baeldung/nth/root/main/Main.java similarity index 100% rename from core-java/src/main/java/com/baeldung/nth/root/main/Main.java rename to java-numbers/src/main/java/com/baeldung/nth/root/main/Main.java diff --git a/core-java/src/test/java/com/baeldung/decimalformat/DecimalFormatExamplesUnitTest.java b/java-numbers/src/test/java/com/baeldung/decimalformat/DecimalFormatExamplesUnitTest.java similarity index 100% rename from core-java/src/test/java/com/baeldung/decimalformat/DecimalFormatExamplesUnitTest.java rename to java-numbers/src/test/java/com/baeldung/decimalformat/DecimalFormatExamplesUnitTest.java diff --git a/core-java/src/test/java/com/baeldung/java/math/MathUnitTest.java b/java-numbers/src/test/java/com/baeldung/java/math/MathUnitTest.java similarity index 100% rename from core-java/src/test/java/com/baeldung/java/math/MathUnitTest.java rename to java-numbers/src/test/java/com/baeldung/java/math/MathUnitTest.java diff --git a/core-java/src/test/java/com/baeldung/nth/root/calculator/NthRootCalculatorUnitTest.java b/java-numbers/src/test/java/com/baeldung/nth/root/calculator/NthRootCalculatorUnitTest.java similarity index 100% rename from core-java/src/test/java/com/baeldung/nth/root/calculator/NthRootCalculatorUnitTest.java rename to java-numbers/src/test/java/com/baeldung/nth/root/calculator/NthRootCalculatorUnitTest.java diff --git a/core-java/src/test/java/com/baeldung/nth/root/main/MainUnitTest.java b/java-numbers/src/test/java/com/baeldung/nth/root/main/MainUnitTest.java similarity index 100% rename from core-java/src/test/java/com/baeldung/nth/root/main/MainUnitTest.java rename to java-numbers/src/test/java/com/baeldung/nth/root/main/MainUnitTest.java diff --git a/core-java/src/test/java/com/baeldung/removingdecimals/RemovingDecimalsManualTest.java b/java-numbers/src/test/java/com/baeldung/removingdecimals/RemovingDecimalsManualTest.java similarity index 100% rename from core-java/src/test/java/com/baeldung/removingdecimals/RemovingDecimalsManualTest.java rename to java-numbers/src/test/java/com/baeldung/removingdecimals/RemovingDecimalsManualTest.java diff --git a/core-java/src/test/java/com/baeldung/removingdecimals/RemovingDecimalsUnitTest.java b/java-numbers/src/test/java/com/baeldung/removingdecimals/RemovingDecimalsUnitTest.java similarity index 100% rename from core-java/src/test/java/com/baeldung/removingdecimals/RemovingDecimalsUnitTest.java rename to java-numbers/src/test/java/com/baeldung/removingdecimals/RemovingDecimalsUnitTest.java diff --git a/java-streams/README.md b/java-streams/README.md index 2550f08650..33ca2619a8 100644 --- a/java-streams/README.md +++ b/java-streams/README.md @@ -14,3 +14,4 @@ - [Primitive Type Streams in Java 8](http://www.baeldung.com/java-8-primitive-streams) - [Stream Ordering in Java](https://www.baeldung.com/java-stream-ordering) - [Introduction to Protonpack](https://www.baeldung.com/java-protonpack) +- [Java Stream Filter with Lambda Expression](https://www.baeldung.com/java-stream-filter-lambda) diff --git a/java-strings/README.md b/java-strings/README.md index 60131e392d..08fbec35ab 100644 --- a/java-strings/README.md +++ b/java-strings/README.md @@ -45,3 +45,7 @@ - [Remove or Replace part of a String in Java](https://www.baeldung.com/java-remove-replace-string-part) - [Replace a Character at a Specific Index in a String in Java](https://www.baeldung.com/java-replace-character-at-index) - [Convert a Comma Separated String to a List in Java](https://www.baeldung.com/java-string-with-separator-to-list) +- [Guide to java.util.Formatter](http://www.baeldung.com/java-string-formatter) +- [Add a Character to a String at a Given Position](https://www.baeldung.com/java-add-character-to-string) +- [Remove Leading and Trailing Characters from a String](https://www.baeldung.com/java-remove-trailing-characters) +- [Concatenating Strings In Java](https://www.baeldung.com/java-strings-concatenation) diff --git a/core-java/src/main/java/com/baeldung/string/AppendCharAtPositionX.java b/java-strings/src/main/java/com/baeldung/string/AppendCharAtPositionX.java similarity index 100% rename from core-java/src/main/java/com/baeldung/string/AppendCharAtPositionX.java rename to java-strings/src/main/java/com/baeldung/string/AppendCharAtPositionX.java diff --git a/core-java/src/test/java/com/baeldung/string/AppendCharAtPositionXUnitTest.java b/java-strings/src/test/java/com/baeldung/string/AppendCharAtPositionXUnitTest.java similarity index 100% rename from core-java/src/test/java/com/baeldung/string/AppendCharAtPositionXUnitTest.java rename to java-strings/src/test/java/com/baeldung/string/AppendCharAtPositionXUnitTest.java diff --git a/java-strings/src/test/java/com/baeldung/string/formatter/DateToStringFormatterUnitTest.java b/java-strings/src/test/java/com/baeldung/string/formatter/DateToStringFormatterUnitTest.java index f236c641c3..d760510c73 100644 --- a/java-strings/src/test/java/com/baeldung/string/formatter/DateToStringFormatterUnitTest.java +++ b/java-strings/src/test/java/com/baeldung/string/formatter/DateToStringFormatterUnitTest.java @@ -1,7 +1,6 @@ package com.baeldung.string.formatter; -import org.junit.BeforeClass; -import org.junit.Test; +import static org.junit.Assert.assertEquals; import java.text.DateFormat; import java.text.SimpleDateFormat; @@ -11,9 +10,11 @@ import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.util.Calendar; import java.util.Date; +import java.util.Locale; import java.util.TimeZone; -import static org.junit.Assert.assertEquals; +import org.junit.BeforeClass; +import org.junit.Test; public class DateToStringFormatterUnitTest { @@ -40,7 +41,7 @@ public class DateToStringFormatterUnitTest { @Test public void whenDateConvertedUsingDateFormatToString_thenCorrect() { String formattedDate = DateFormat - .getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT) + .getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT, Locale.US) .format(date); assertEquals(EXPECTED_STRING_DATE, formattedDate); diff --git a/java-strings/src/test/java/com/baeldung/string/interview/LocaleUnitTest.java b/java-strings/src/test/java/com/baeldung/string/interview/LocaleUnitTest.java new file mode 100644 index 0000000000..1d221056fd --- /dev/null +++ b/java-strings/src/test/java/com/baeldung/string/interview/LocaleUnitTest.java @@ -0,0 +1,19 @@ +package com.baeldung.string.interview; + +import java.math.BigDecimal; +import java.text.NumberFormat; +import java.util.Locale; +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +public class LocaleUnitTest { + @Test + public void whenUsingLocal_thenCorrectResultsForDifferentLocale() { + Locale usLocale = Locale.US; + BigDecimal number = new BigDecimal(102_300.456d); + + NumberFormat usNumberFormat = NumberFormat.getCurrencyInstance(usLocale); + assertEquals(usNumberFormat.format(number), "$102,300.46"); + } +} diff --git a/java-strings/src/test/java/com/baeldung/string/interview/StringAnagramUnitTest.java b/java-strings/src/test/java/com/baeldung/string/interview/StringAnagramUnitTest.java new file mode 100644 index 0000000000..aadfade737 --- /dev/null +++ b/java-strings/src/test/java/com/baeldung/string/interview/StringAnagramUnitTest.java @@ -0,0 +1,29 @@ +package com.baeldung.string.interview; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Arrays; + +import org.junit.Test; + +public class StringAnagramUnitTest { + public boolean isAnagram(String s1, String s2) { + if(s1.length() != s2.length()) + return false; + + char[] arr1 = s1.toCharArray(); + char[] arr2 = s2.toCharArray(); + + Arrays.sort(arr1); + Arrays.sort(arr2); + + return Arrays.equals(arr1, arr2); + } + + @Test + public void whenTestAnagrams_thenTestingCorrectly() { + assertThat(isAnagram("car", "arc")).isTrue(); + assertThat(isAnagram("west", "stew")).isTrue(); + assertThat(isAnagram("west", "east")).isFalse(); + } +} diff --git a/java-strings/src/test/java/com/baeldung/string/interview/StringChangeCaseUnitTest.java b/java-strings/src/test/java/com/baeldung/string/interview/StringChangeCaseUnitTest.java new file mode 100644 index 0000000000..2c7ec500fe --- /dev/null +++ b/java-strings/src/test/java/com/baeldung/string/interview/StringChangeCaseUnitTest.java @@ -0,0 +1,20 @@ +package com.baeldung.string.interview; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +public class StringChangeCaseUnitTest { + @Test + public void givenString_whenChangingToUppercase_thenCaseChanged() { + String s = "Welcome to Baeldung!"; + assertEquals("WELCOME TO BAELDUNG!", s.toUpperCase()); + } + + + @Test + public void givenString_whenChangingToLowerrcase_thenCaseChanged() { + String s = "Welcome to Baeldung!"; + assertEquals("welcome to baeldung!", s.toLowerCase()); + } +} diff --git a/java-strings/src/test/java/com/baeldung/string/interview/StringCountOccurrencesUnitTest.java b/java-strings/src/test/java/com/baeldung/string/interview/StringCountOccurrencesUnitTest.java new file mode 100644 index 0000000000..6c17643ac8 --- /dev/null +++ b/java-strings/src/test/java/com/baeldung/string/interview/StringCountOccurrencesUnitTest.java @@ -0,0 +1,28 @@ +package com.baeldung.string.interview; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +public class StringCountOccurrencesUnitTest { + public int countOccurrences(String s, char c) { + int count = 0; + for (int i = 0; i < s.length(); i++) { + if (s.charAt(i) == c) { + count++; + } + } + return count; + } + + @Test + public void givenString_whenCountingFrequencyOfChar_thenCountCorrect() { + assertEquals(3, countOccurrences("united states", 't')); + } + + public void givenString_whenUsingJava8_thenCountingOfCharCorrect() { + String str = "united states"; + long count = str.chars().filter(ch -> (char)ch == 't').count(); + assertEquals(3, count); + } +} diff --git a/java-strings/src/test/java/com/baeldung/string/interview/StringFormatUnitTest.java b/java-strings/src/test/java/com/baeldung/string/interview/StringFormatUnitTest.java new file mode 100644 index 0000000000..787017791c --- /dev/null +++ b/java-strings/src/test/java/com/baeldung/string/interview/StringFormatUnitTest.java @@ -0,0 +1,14 @@ +package com.baeldung.string.interview; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +public class StringFormatUnitTest { + @Test + public void givenString_whenUsingStringFormat_thenStringFormatted() { + String title = "Baeldung"; + String formatted = String.format("Title is %s", title); + assertEquals(formatted, "Title is Baeldung"); + } +} diff --git a/java-strings/src/test/java/com/baeldung/string/interview/StringInternUnitTest.java b/java-strings/src/test/java/com/baeldung/string/interview/StringInternUnitTest.java new file mode 100644 index 0000000000..c5bffb7573 --- /dev/null +++ b/java-strings/src/test/java/com/baeldung/string/interview/StringInternUnitTest.java @@ -0,0 +1,17 @@ +package com.baeldung.string.interview; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.Test; + +public class StringInternUnitTest { + @Test + public void whenCallingStringIntern_thenStringsInterned() { + String s1 = "Baeldung"; + String s2 = new String("Baeldung"); + String s3 = new String("Baeldung").intern(); + + assertThat(s1 == s2).isFalse(); + assertThat(s1 == s3).isTrue(); + } +} diff --git a/java-strings/src/test/java/com/baeldung/string/interview/StringJoinerUnitTest.java b/java-strings/src/test/java/com/baeldung/string/interview/StringJoinerUnitTest.java new file mode 100644 index 0000000000..d44c7478e4 --- /dev/null +++ b/java-strings/src/test/java/com/baeldung/string/interview/StringJoinerUnitTest.java @@ -0,0 +1,18 @@ +package com.baeldung.string.interview; + +import java.util.StringJoiner; +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +public class StringJoinerUnitTest { + @Test + public void whenUsingStringJoiner_thenStringsJoined() { + StringJoiner joiner = new StringJoiner(",", "[", "]"); + joiner.add("Red") + .add("Green") + .add("Blue"); + + assertEquals(joiner.toString(), "[Red,Green,Blue]"); + } +} diff --git a/java-strings/src/test/java/com/baeldung/string/interview/StringPalindromeUnitTest.java b/java-strings/src/test/java/com/baeldung/string/interview/StringPalindromeUnitTest.java new file mode 100644 index 0000000000..79ed14cd99 --- /dev/null +++ b/java-strings/src/test/java/com/baeldung/string/interview/StringPalindromeUnitTest.java @@ -0,0 +1,29 @@ +package com.baeldung.string.interview; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.Test; + +public class StringPalindromeUnitTest { + + public boolean isPalindrome(String text) { + int forward = 0; + int backward = text.length() - 1; + while (backward > forward) { + char forwardChar = text.charAt(forward++); + char backwardChar = text.charAt(backward--); + if (forwardChar != backwardChar) + return false; + } + return true; + } + + @Test + public void givenIsPalindromeMethod_whenCheckingString_thenFindIfPalindrome() { + assertThat(isPalindrome("madam")).isTrue(); + assertThat(isPalindrome("radar")).isTrue(); + assertThat(isPalindrome("level")).isTrue(); + + assertThat(isPalindrome("baeldung")).isFalse(); + } +} diff --git a/java-strings/src/test/java/com/baeldung/string/interview/StringReverseUnitTest.java b/java-strings/src/test/java/com/baeldung/string/interview/StringReverseUnitTest.java new file mode 100644 index 0000000000..bb9b45dc97 --- /dev/null +++ b/java-strings/src/test/java/com/baeldung/string/interview/StringReverseUnitTest.java @@ -0,0 +1,13 @@ +package com.baeldung.string.interview; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +public class StringReverseUnitTest { + @Test + public void whenUsingInbuildMethods_thenStringReversed() { + String reversed = new StringBuilder("baeldung").reverse().toString(); + assertEquals("gnudleab", reversed); + } +} diff --git a/java-strings/src/test/java/com/baeldung/string/interview/StringSplitUnitTest.java b/java-strings/src/test/java/com/baeldung/string/interview/StringSplitUnitTest.java new file mode 100644 index 0000000000..e1cea62462 --- /dev/null +++ b/java-strings/src/test/java/com/baeldung/string/interview/StringSplitUnitTest.java @@ -0,0 +1,32 @@ +package com.baeldung.string.interview; + +import org.apache.commons.lang3.StringUtils; +import org.junit.Test; +import static org.junit.Assert.assertArrayEquals; + +public class StringSplitUnitTest { + @Test + public void givenCoreJava_whenSplittingStrings_thenSplitted() { + String expected[] = { + "john", + "peter", + "mary" + }; + + String[] splitted = "john,peter,mary".split(","); + assertArrayEquals( expected, splitted ); + } + + @Test + public void givenApacheCommons_whenSplittingStrings_thenSplitted() { + String expected[] = { + "john", + "peter", + "mary" + }; + String[] splitted = StringUtils.split("john peter mary"); + assertArrayEquals( expected, splitted ); + } + + +} diff --git a/java-strings/src/test/java/com/baeldung/string/interview/StringToByteArrayUnitTest.java b/java-strings/src/test/java/com/baeldung/string/interview/StringToByteArrayUnitTest.java new file mode 100644 index 0000000000..aee4eedcd6 --- /dev/null +++ b/java-strings/src/test/java/com/baeldung/string/interview/StringToByteArrayUnitTest.java @@ -0,0 +1,24 @@ +package com.baeldung.string.interview; + +import static org.junit.Assert.assertArrayEquals; + +import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; + +import org.junit.Test; + +public class StringToByteArrayUnitTest { + @Test + public void whenGetBytes_thenCorrect() throws UnsupportedEncodingException { + byte[] byteArray1 = "abcd".getBytes(); + byte[] byteArray2 = "efgh".getBytes(StandardCharsets.US_ASCII); + byte[] byteArray3 = "ijkl".getBytes("UTF-8"); + byte[] expected1 = new byte[] { 97, 98, 99, 100 }; + byte[] expected2 = new byte[] { 101, 102, 103, 104 }; + byte[] expected3 = new byte[] { 105, 106, 107, 108 }; + + assertArrayEquals(expected1, byteArray1); + assertArrayEquals(expected2, byteArray2); + assertArrayEquals(expected3, byteArray3); + } +} diff --git a/java-strings/src/test/java/com/baeldung/string/interview/StringToCharArrayUnitTest.java b/java-strings/src/test/java/com/baeldung/string/interview/StringToCharArrayUnitTest.java new file mode 100644 index 0000000000..1322d0fa82 --- /dev/null +++ b/java-strings/src/test/java/com/baeldung/string/interview/StringToCharArrayUnitTest.java @@ -0,0 +1,17 @@ +package com.baeldung.string.interview; + +import static org.junit.Assert.assertEquals; + +import java.util.Arrays; + +import org.junit.Test; + +public class StringToCharArrayUnitTest { + @Test + public void whenConvertingStringToCharArray_thenConversionSuccessful() { + String beforeConvStr = "hello"; + char[] afterConvCharArr = { 'h', 'e', 'l', 'l', 'o' }; + + assertEquals(Arrays.equals(beforeConvStr.toCharArray(), afterConvCharArr), true); + } +} diff --git a/java-strings/src/test/java/com/baeldung/string/interview/StringToIntegerUnitTest.java b/java-strings/src/test/java/com/baeldung/string/interview/StringToIntegerUnitTest.java new file mode 100644 index 0000000000..a905438a84 --- /dev/null +++ b/java-strings/src/test/java/com/baeldung/string/interview/StringToIntegerUnitTest.java @@ -0,0 +1,15 @@ +package com.baeldung.string.interview; + +import org.junit.Test; +import static org.assertj.core.api.Assertions.assertThat; + +public class StringToIntegerUnitTest { + @Test + public void givenString_whenParsingInt_shouldConvertToInt() { + String givenString = "42"; + + int result = Integer.parseInt(givenString); + + assertThat(result).isEqualTo(42); + } +} diff --git a/jee-7/README.md b/jee-7/README.md index a2493e561b..a783e7860e 100644 --- a/jee-7/README.md +++ b/jee-7/README.md @@ -5,3 +5,4 @@ - [Introduction to JAX-WS](http://www.baeldung.com/jax-ws) - [A Guide to Java EE Web-Related Annotations](http://www.baeldung.com/javaee-web-annotations) - [Introduction to Testing with Arquillian](http://www.baeldung.com/arquillian) +- [Java EE 7 Batch Processing](https://www.baeldung.com/java-ee-7-batch-processing) diff --git a/lombok-custom/README.md b/lombok-custom/README.md new file mode 100644 index 0000000000..bfc784ea7e --- /dev/null +++ b/lombok-custom/README.md @@ -0,0 +1,3 @@ +## Relevant articles: + +- [Implementing a Custom Lombok Annotation](https://www.baeldung.com/lombok-custom-annotation) diff --git a/patterns/design-patterns/src/main/java/com/baeldung/creational/abstractfactory/AbstractFactory.java b/patterns/design-patterns/src/main/java/com/baeldung/creational/abstractfactory/AbstractFactory.java index 5b4bf08006..88e819c066 100644 --- a/patterns/design-patterns/src/main/java/com/baeldung/creational/abstractfactory/AbstractFactory.java +++ b/patterns/design-patterns/src/main/java/com/baeldung/creational/abstractfactory/AbstractFactory.java @@ -1,6 +1,5 @@ package com.baeldung.creational.abstractfactory; -public interface AbstractFactory { - Animal getAnimal(String toyType) ; - Color getColor(String colorType); +public interface AbstractFactory { + T create(String type) ; } \ No newline at end of file diff --git a/patterns/design-patterns/src/main/java/com/baeldung/creational/abstractfactory/AbstractPatternDriver.java b/patterns/design-patterns/src/main/java/com/baeldung/creational/abstractfactory/AbstractPatternDriver.java index 68759d5aff..c1501091c5 100644 --- a/patterns/design-patterns/src/main/java/com/baeldung/creational/abstractfactory/AbstractPatternDriver.java +++ b/patterns/design-patterns/src/main/java/com/baeldung/creational/abstractfactory/AbstractPatternDriver.java @@ -6,10 +6,10 @@ public class AbstractPatternDriver { //creating a brown toy dog abstractFactory = FactoryProvider.getFactory("Toy"); - Animal toy = abstractFactory.getAnimal("Dog"); + Animal toy =(Animal) abstractFactory.create("Dog"); abstractFactory = FactoryProvider.getFactory("Color"); - Color color = abstractFactory.getColor("Brown"); + Color color =(Color) abstractFactory.create("Brown"); String result = "A " + toy.getType() + " with " + color.getColor() + " color " + toy.makeSound(); diff --git a/patterns/design-patterns/src/main/java/com/baeldung/creational/abstractfactory/AnimalFactory.java b/patterns/design-patterns/src/main/java/com/baeldung/creational/abstractfactory/AnimalFactory.java index bbc3eb7a82..4b46261571 100644 --- a/patterns/design-patterns/src/main/java/com/baeldung/creational/abstractfactory/AnimalFactory.java +++ b/patterns/design-patterns/src/main/java/com/baeldung/creational/abstractfactory/AnimalFactory.java @@ -1,9 +1,9 @@ package com.baeldung.creational.abstractfactory; -public class AnimalFactory implements AbstractFactory { +public class AnimalFactory implements AbstractFactory { @Override - public Animal getAnimal(String animalType) { + public Animal create(String animalType) { if ("Dog".equalsIgnoreCase(animalType)) { return new Dog(); } else if ("Duck".equalsIgnoreCase(animalType)) { @@ -13,9 +13,4 @@ public class AnimalFactory implements AbstractFactory { return null; } - @Override - public Color getColor(String color) { - throw new UnsupportedOperationException(); - } - } diff --git a/patterns/design-patterns/src/main/java/com/baeldung/creational/abstractfactory/ColorFactory.java b/patterns/design-patterns/src/main/java/com/baeldung/creational/abstractfactory/ColorFactory.java index 8b7e4f8086..3d9c5c18a3 100644 --- a/patterns/design-patterns/src/main/java/com/baeldung/creational/abstractfactory/ColorFactory.java +++ b/patterns/design-patterns/src/main/java/com/baeldung/creational/abstractfactory/ColorFactory.java @@ -1,9 +1,9 @@ package com.baeldung.creational.abstractfactory; -public class ColorFactory implements AbstractFactory { +public class ColorFactory implements AbstractFactory { @Override - public Color getColor(String colorType) { + public Color create(String colorType) { if ("Brown".equalsIgnoreCase(colorType)) { return new Brown(); } else if ("White".equalsIgnoreCase(colorType)) { @@ -13,9 +13,4 @@ public class ColorFactory implements AbstractFactory { return null; } - @Override - public Animal getAnimal(String toyType) { - throw new UnsupportedOperationException(); - } - } diff --git a/patterns/design-patterns/src/test/java/com/baeldung/creational/abstractfactory/AbstractPatternIntegrationTest.java b/patterns/design-patterns/src/test/java/com/baeldung/creational/abstractfactory/AbstractPatternIntegrationTest.java index 6d1a4ad8fd..4f02249a4b 100644 --- a/patterns/design-patterns/src/test/java/com/baeldung/creational/abstractfactory/AbstractPatternIntegrationTest.java +++ b/patterns/design-patterns/src/test/java/com/baeldung/creational/abstractfactory/AbstractPatternIntegrationTest.java @@ -11,10 +11,10 @@ public class AbstractPatternIntegrationTest { //creating a brown toy dog abstractFactory = FactoryProvider.getFactory("Toy"); - Animal toy = abstractFactory.getAnimal("Dog"); + Animal toy = (Animal) abstractFactory.create("Dog"); abstractFactory = FactoryProvider.getFactory("Color"); - Color color = abstractFactory.getColor("Brown"); + Color color =(Color) abstractFactory.create("Brown"); String result = "A " + toy.getType() + " with " + color.getColor() + " color " + toy.makeSound(); assertEquals("A Dog with brown color Barks", result); diff --git a/persistence-modules/hibernate5/README.md b/persistence-modules/hibernate5/README.md index 2b948a683a..03bdd9b759 100644 --- a/persistence-modules/hibernate5/README.md +++ b/persistence-modules/hibernate5/README.md @@ -23,3 +23,9 @@ - [Difference Between @JoinColumn and mappedBy](https://www.baeldung.com/jpa-joincolumn-vs-mappedby) - [Hibernate 5 Bootstrapping API](https://www.baeldung.com/hibernate-5-bootstrapping-api) - [Criteria Queries Using JPA Metamodel](https://www.baeldung.com/hibernate-criteria-queries-metamodel) +- [Guide to the Hibernate EntityManager](https://www.baeldung.com/hibernate-entitymanager) +- [Get All Data from a Table with Hibernate](https://www.baeldung.com/hibernate-select-all) +- [One-to-One Relationship in JPA](https://www.baeldung.com/jpa-one-to-one) +- [Hibernate Named Query](https://www.baeldung.com/hibernate-named-query) +- [Using c3p0 with Hibernate](https://www.baeldung.com/hibernate-c3p0) +- [Persist a JSON Object Using Hibernate](https://www.baeldung.com/hibernate-persist-json-object) diff --git a/persistence-modules/java-jpa/README.md b/persistence-modules/java-jpa/README.md index 9a90216519..2eea5e60b4 100644 --- a/persistence-modules/java-jpa/README.md +++ b/persistence-modules/java-jpa/README.md @@ -2,4 +2,5 @@ - [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) diff --git a/persistence-modules/spring-data-jpa/README.md b/persistence-modules/spring-data-jpa/README.md index 3c71600565..976a692699 100644 --- a/persistence-modules/spring-data-jpa/README.md +++ b/persistence-modules/spring-data-jpa/README.md @@ -18,6 +18,7 @@ - [Limiting Query Results with JPA and Spring Data JPA](https://www.baeldung.com/jpa-limit-query-results) - [Sorting Query Results with Spring Data](https://www.baeldung.com/spring-data-sorting) - [INSERT Statement in JPA](https://www.baeldung.com/jpa-insert) +- [Pagination and Sorting using Spring Data JPA](https://www.baeldung.com/spring-data-jpa-pagination-sorting) ### Eclipse Config After importing the project into Eclipse, you may see the following error: diff --git a/pom.xml b/pom.xml index 923cbab302..4dba0da173 100644 --- a/pom.xml +++ b/pom.xml @@ -383,6 +383,7 @@ core-java-concurrency-basic core-java-concurrency-collections core-java-io + core-java-security core-java-lang-syntax core-java-lang core-java-lang-oop @@ -662,6 +663,7 @@ spring-dispatcher-servlet spring-drools + spring-ehcache spring-ejb spring-exceptions @@ -881,6 +883,7 @@ spring-data-rest spring-dispatcher-servlet spring-drools + spring-ehcache spring-freemarker persistence-modules/spring-hibernate-3 persistence-modules/spring-hibernate4 @@ -1095,6 +1098,7 @@ core-java-concurrency-basic core-java-concurrency-collections core-java-io + core-java-security core-java-lang-syntax core-java-lang core-java-lang-oop @@ -1368,6 +1372,7 @@ spring-dispatcher-servlet spring-drools + spring-ehcache spring-ejb spring-exceptions diff --git a/spring-5-reactive-oauth/src/main/java/com/baeldung/reactive/oauth/Spring5ReactiveOauthApplication.java b/spring-5-reactive-oauth/src/main/java/com/baeldung/reactive/oauth/Spring5ReactiveOauthApplication.java index 602ded6b9e..b95517200e 100644 --- a/spring-5-reactive-oauth/src/main/java/com/baeldung/reactive/oauth/Spring5ReactiveOauthApplication.java +++ b/spring-5-reactive-oauth/src/main/java/com/baeldung/reactive/oauth/Spring5ReactiveOauthApplication.java @@ -3,11 +3,13 @@ package com.baeldung.reactive.oauth; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.PropertySource; import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository; import org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction; import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository; import org.springframework.web.reactive.function.client.WebClient; +@PropertySource("classpath:default-application.yml") @SpringBootApplication public class Spring5ReactiveOauthApplication { diff --git a/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodeclient/OauthClientApplication.java b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodeclient/OauthClientApplication.java new file mode 100644 index 0000000000..7bae78bb14 --- /dev/null +++ b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodeclient/OauthClientApplication.java @@ -0,0 +1,24 @@ +package com.baeldung.webclient.authorizationcodeclient; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.PropertySource; + +/** + * + * Note: This app is configured to use the authorization service and the resource service located in module spring-5-security-oauth + * + * As we usually do with other well-known auth providers (github/facebook/...) we have to log-in using user credentials (bael-user/bael-password) and client configurations (bael-client-id/bael-secret) handled by the auth server + * + * @author rozagerardo + * + */ +@PropertySource("classpath:webclient-auth-code-client-application.properties") +@SpringBootApplication +public class OauthClientApplication { + + public static void main(String[] args) { + SpringApplication.run(OauthClientApplication.class, args); + } + +} diff --git a/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodeclient/configuration/WebClientConfig.java b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodeclient/configuration/WebClientConfig.java new file mode 100644 index 0000000000..884a3c145d --- /dev/null +++ b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodeclient/configuration/WebClientConfig.java @@ -0,0 +1,20 @@ +package com.baeldung.webclient.authorizationcodeclient.configuration; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository; +import org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction; +import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository; +import org.springframework.web.reactive.function.client.WebClient; + +@Configuration +public class WebClientConfig { + + @Bean + WebClient webClientForAuthorized(ReactiveClientRegistrationRepository clientRegistrations, ServerOAuth2AuthorizedClientRepository authorizedClients) { + ServerOAuth2AuthorizedClientExchangeFilterFunction oauth = new ServerOAuth2AuthorizedClientExchangeFilterFunction(clientRegistrations, authorizedClients); + return WebClient.builder() + .filter(oauth) + .build(); + } +} diff --git a/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodeclient/configuration/WebSecurityConfig.java b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodeclient/configuration/WebSecurityConfig.java new file mode 100644 index 0000000000..4271ae96cf --- /dev/null +++ b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodeclient/configuration/WebSecurityConfig.java @@ -0,0 +1,22 @@ +package com.baeldung.webclient.authorizationcodeclient.configuration; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.web.server.ServerHttpSecurity; +import org.springframework.security.web.server.SecurityWebFilterChain; + +@Configuration +public class WebSecurityConfig { + @Bean + public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { + http.authorizeExchange() + .anyExchange() + .authenticated() + .and() + .oauth2Client() + .and() + .formLogin(); + return http.build(); + } + +} diff --git a/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodeclient/web/ClientRestController.java b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodeclient/web/ClientRestController.java new file mode 100644 index 0000000000..c36b7d1dea --- /dev/null +++ b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodeclient/web/ClientRestController.java @@ -0,0 +1,53 @@ +package com.baeldung.webclient.authorizationcodeclient.web; + +import static org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction.clientRegistrationId; +import static org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction.oauth2AuthorizedClient; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; +import org.springframework.security.oauth2.client.annotation.RegisteredOAuth2AuthorizedClient; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.reactive.function.client.WebClient; + +import reactor.core.publisher.Mono; + +@RestController +public class ClientRestController { + + private static final String RESOURCE_URI = "http://localhost:8084/retrieve-resource"; + + @Autowired + WebClient webClient; + + @GetMapping("/auth-code") + Mono useOauthWithAuthCode() { + Mono retrievedResource = webClient.get() + .uri(RESOURCE_URI) + .retrieve() + .bodyToMono(String.class); + return retrievedResource.map(string -> "We retrieved the following resource using Oauth: " + string); + } + + @GetMapping("/auth-code-annotated") + Mono useOauthWithAuthCodeAndAnnotation(@RegisteredOAuth2AuthorizedClient("bael") OAuth2AuthorizedClient authorizedClient) { + Mono retrievedResource = webClient.get() + .uri(RESOURCE_URI) + .attributes(oauth2AuthorizedClient(authorizedClient)) + .retrieve() + .bodyToMono(String.class); + return retrievedResource.map(string -> "We retrieved the following resource using Oauth: " + string + ". Principal associated: " + authorizedClient.getPrincipalName() + ". Token will expire at: " + authorizedClient.getAccessToken() + .getExpiresAt()); + } + + @GetMapping("/auth-code-explicit-client") + Mono useOauthWithExpicitClient() { + Mono retrievedResource = webClient.get() + .uri(RESOURCE_URI) + .attributes(clientRegistrationId("bael")) + .retrieve() + .bodyToMono(String.class); + return retrievedResource.map(string -> "We retrieved the following resource using Oauth: " + string); + } + +} diff --git a/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodelogin/OauthClientApplication.java b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodelogin/OauthClientApplication.java new file mode 100644 index 0000000000..9dd6dd1bde --- /dev/null +++ b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodelogin/OauthClientApplication.java @@ -0,0 +1,24 @@ +package com.baeldung.webclient.authorizationcodelogin; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.PropertySource; + +/** + * + * Note: This app is configured to use the authorization service and the resource service located in module spring-5-security-oauth + * + * As we usually do with other well-known auth providers (github/facebook/...) we have to log-in using user credentials (bael-user/bael-password) and client configurations (bael-client-id/bael-secret) handled by the auth server + * + * @author rozagerardo + * + */ +@PropertySource("classpath:webclient-auth-code-login-application.properties") +@SpringBootApplication +public class OauthClientApplication { + + public static void main(String[] args) { + SpringApplication.run(OauthClientApplication.class, args); + } + +} diff --git a/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodelogin/configuration/WebClientConfig.java b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodelogin/configuration/WebClientConfig.java new file mode 100644 index 0000000000..15458cc60a --- /dev/null +++ b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodelogin/configuration/WebClientConfig.java @@ -0,0 +1,31 @@ +package com.baeldung.webclient.authorizationcodelogin.configuration; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository; +import org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction; +import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository; +import org.springframework.web.reactive.function.client.WebClient; + +@Configuration +public class WebClientConfig { + + @Bean + @Primary + WebClient webClientForAuthorized(ReactiveClientRegistrationRepository clientRegistrations, ServerOAuth2AuthorizedClientRepository authorizedClients) { + ServerOAuth2AuthorizedClientExchangeFilterFunction oauth = new ServerOAuth2AuthorizedClientExchangeFilterFunction(clientRegistrations, authorizedClients); + oauth.setDefaultOAuth2AuthorizedClient(true); + return WebClient.builder() + .filter(oauth) + .build(); + } + + @Bean + WebClient otherWebClient(ReactiveClientRegistrationRepository clientRegistrations, ServerOAuth2AuthorizedClientRepository authorizedClients) { + ServerOAuth2AuthorizedClientExchangeFilterFunction oauth = new ServerOAuth2AuthorizedClientExchangeFilterFunction(clientRegistrations, authorizedClients); + return WebClient.builder() + .filter(oauth) + .build(); + } +} diff --git a/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodelogin/configuration/WebSecurityConfig.java b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodelogin/configuration/WebSecurityConfig.java new file mode 100644 index 0000000000..f45fc09222 --- /dev/null +++ b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodelogin/configuration/WebSecurityConfig.java @@ -0,0 +1,20 @@ +package com.baeldung.webclient.authorizationcodelogin.configuration; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.web.server.ServerHttpSecurity; +import org.springframework.security.web.server.SecurityWebFilterChain; + +@Configuration +public class WebSecurityConfig { + @Bean + public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { + http.authorizeExchange() + .anyExchange() + .authenticated() + .and() + .oauth2Login(); + return http.build(); + } + +} diff --git a/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodelogin/web/ClientRestController.java b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodelogin/web/ClientRestController.java new file mode 100644 index 0000000000..55e0096525 --- /dev/null +++ b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodelogin/web/ClientRestController.java @@ -0,0 +1,68 @@ +package com.baeldung.webclient.authorizationcodelogin.web; + +import static org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction.clientRegistrationId; +import static org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction.oauth2AuthorizedClient; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; +import org.springframework.security.oauth2.client.annotation.RegisteredOAuth2AuthorizedClient; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.reactive.function.client.WebClient; + +import reactor.core.publisher.Mono; + +@RestController +public class ClientRestController { + + private static final String RESOURCE_URI = "http://localhost:8084/retrieve-resource"; + + @Autowired + WebClient webClient; + + @Autowired + @Qualifier("otherWebClient") + WebClient otherWebClient; + + @GetMapping("/auth-code") + Mono useOauthWithAuthCode() { + Mono retrievedResource = webClient.get() + .uri(RESOURCE_URI) + .retrieve() + .bodyToMono(String.class); + return retrievedResource.map(string -> "We retrieved the following resource using Oauth: " + string); + } + + @GetMapping("/auth-code-no-client") + Mono useOauthWithNoClient() { + // This call will fail, since we don't have the client properly set for this webClient + Mono retrievedResource = otherWebClient.get() + .uri(RESOURCE_URI) + .retrieve() + .bodyToMono(String.class); + return retrievedResource.map(string -> "We retrieved the following resource using Oauth: " + string); + } + + @GetMapping("/auth-code-annotated") + Mono useOauthWithAuthCodeAndAnnotation(@RegisteredOAuth2AuthorizedClient("bael") OAuth2AuthorizedClient authorizedClient) { + Mono retrievedResource = otherWebClient.get() + .uri(RESOURCE_URI) + .attributes(oauth2AuthorizedClient(authorizedClient)) + .retrieve() + .bodyToMono(String.class); + return retrievedResource.map(string -> "We retrieved the following resource using Oauth: " + string + ". Principal associated: " + authorizedClient.getPrincipalName() + ". Token will expire at: " + authorizedClient.getAccessToken() + .getExpiresAt()); + } + + @GetMapping("/auth-code-explicit-client") + Mono useOauthWithExpicitClient() { + Mono retrievedResource = otherWebClient.get() + .uri(RESOURCE_URI) + .attributes(clientRegistrationId("bael")) + .retrieve() + .bodyToMono(String.class); + return retrievedResource.map(string -> "We retrieved the following resource using Oauth: " + string); + } + +} diff --git a/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/clientcredentials/ClientCredentialsOauthApplication.java b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/clientcredentials/ClientCredentialsOauthApplication.java new file mode 100644 index 0000000000..d1b9f7f744 --- /dev/null +++ b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/clientcredentials/ClientCredentialsOauthApplication.java @@ -0,0 +1,26 @@ +package com.baeldung.webclient.clientcredentials; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.PropertySource; +import org.springframework.scheduling.annotation.EnableScheduling; + +/** + * + * Note: This app is configured to use the authorization service and the resource service located in module spring-5-security-oauth + * + * As we usually do with other well-known auth providers (github/facebook/...) we have to log-in using credentials handled by the auth server (bael-user/bael-password) + * + * @author rozagerardo + * + */ +@PropertySource("classpath:webclient-client-credentials-oauth-application.properties") +@EnableScheduling +@SpringBootApplication +public class ClientCredentialsOauthApplication { + + public static void main(String[] args) { + SpringApplication.run(ClientCredentialsOauthApplication.class, args); + } + +} diff --git a/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/clientcredentials/configuration/WebClientConfig.java b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/clientcredentials/configuration/WebClientConfig.java new file mode 100644 index 0000000000..8ffc92b4cd --- /dev/null +++ b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/clientcredentials/configuration/WebClientConfig.java @@ -0,0 +1,22 @@ +package com.baeldung.webclient.clientcredentials.configuration; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository; +import org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction; +import org.springframework.security.oauth2.client.web.server.UnAuthenticatedServerOAuth2AuthorizedClientRepository; +import org.springframework.web.reactive.function.client.WebClient; + +@Configuration +public class WebClientConfig { + + @Bean + WebClient webClient(ReactiveClientRegistrationRepository clientRegistrations) { + ServerOAuth2AuthorizedClientExchangeFilterFunction oauth = new ServerOAuth2AuthorizedClientExchangeFilterFunction(clientRegistrations, new UnAuthenticatedServerOAuth2AuthorizedClientRepository()); + oauth.setDefaultClientRegistrationId("bael"); + return WebClient.builder() + .filter(oauth) + .build(); + } + +} diff --git a/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/clientcredentials/service/WebClientChonJob.java b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/clientcredentials/service/WebClientChonJob.java new file mode 100644 index 0000000000..dc38ce3f9e --- /dev/null +++ b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/clientcredentials/service/WebClientChonJob.java @@ -0,0 +1,33 @@ +package com.baeldung.webclient.clientcredentials.service; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; +import org.springframework.security.oauth2.client.annotation.RegisteredOAuth2AuthorizedClient; +import org.springframework.stereotype.Component; +import org.springframework.web.reactive.function.client.WebClient; + +@Component +public class WebClientChonJob { + + Logger logger = LoggerFactory.getLogger(WebClientChonJob.class); + + private static final String RESOURCE_URI = "http://localhost:8084/retrieve-resource"; + + @Autowired + private WebClient webClient; + + @Scheduled(fixedRate = 1000) + public void logResourceServiceResponse() { + + webClient.get() + .uri(RESOURCE_URI) + .retrieve() + .bodyToMono(String.class) + .map(string -> "We retrieved the following resource using Client Credentials Grant Type: " + string) + .subscribe(logger::info); + } + +} diff --git a/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/manualrequest/ManualRequestApplication.java b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/manualrequest/ManualRequestApplication.java new file mode 100644 index 0000000000..c2762ad559 --- /dev/null +++ b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/manualrequest/ManualRequestApplication.java @@ -0,0 +1,23 @@ +package com.baeldung.webclient.manualrequest; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.PropertySource; + +/** + * + * Note: This app is configured to use the authorization service and the resource service located in module spring-5-security-oauth + * + * As we usually do with other well-known auth providers (github/facebook/...) we have to log-in using user credentials (bael-user/bael-password) and client configurations (bael-client-id/bael-secret) handled by the auth server + * + * @author rozagerardo + * + */ +@SpringBootApplication +public class ManualRequestApplication { + + public static void main(String[] args) { + SpringApplication.run(ManualRequestApplication.class, args); + } + +} diff --git a/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/manualrequest/configure/WebClientConfig.java b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/manualrequest/configure/WebClientConfig.java new file mode 100644 index 0000000000..51fc60821a --- /dev/null +++ b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/manualrequest/configure/WebClientConfig.java @@ -0,0 +1,16 @@ +package com.baeldung.webclient.manualrequest.configure; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.reactive.function.client.WebClient; + +@Configuration +public class WebClientConfig { + + @Bean + public WebClient configureWebClient() { + return WebClient.builder() + .build(); + }; + +} diff --git a/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/manualrequest/configure/WebSecurityConfig.java b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/manualrequest/configure/WebSecurityConfig.java new file mode 100644 index 0000000000..1753681db8 --- /dev/null +++ b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/manualrequest/configure/WebSecurityConfig.java @@ -0,0 +1,17 @@ +package com.baeldung.webclient.manualrequest.configure; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.web.server.ServerHttpSecurity; +import org.springframework.security.web.server.SecurityWebFilterChain; + +@Configuration +public class WebSecurityConfig { + @Bean + public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { + http.authorizeExchange() + .anyExchange() + .permitAll(); + return http.build(); + } +} diff --git a/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/manualrequest/web/ManualOauthRequestController.java b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/manualrequest/web/ManualOauthRequestController.java new file mode 100644 index 0000000000..9f9d6d3167 --- /dev/null +++ b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/manualrequest/web/ManualOauthRequestController.java @@ -0,0 +1,57 @@ +package com.baeldung.webclient.manualrequest.web; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames; +import org.springframework.util.Base64Utils; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.reactive.function.BodyInserters; +import org.springframework.web.reactive.function.client.WebClient; + +import com.fasterxml.jackson.databind.JsonNode; +import com.nimbusds.oauth2.sdk.GrantType; + +import reactor.core.publisher.Mono; + +@RestController +public class ManualOauthRequestController { + + private static Logger logger = LoggerFactory.getLogger(ManualOauthRequestController.class); + + private static final String TOKEN_ENDPOINT = "localhost:8085/oauth/token"; + private static final String RESOURCE_ENDPOINT = "localhost:8084/retrieve-resource"; + private static final String CLIENT_ID = "bael-client-id"; + private static final String CLIENT_SECRET = "bael-secret"; + + @Autowired + WebClient client; + + @GetMapping("/manual-request-oauth") + public Mono obtainSecuredResource() { + logger.info("Creating web client..."); + Mono resource = client.post() + .uri(TOKEN_ENDPOINT) + .header(HttpHeaders.AUTHORIZATION, "Basic " + Base64Utils.encodeToString((CLIENT_ID + ":" + CLIENT_SECRET).getBytes())) + .body(BodyInserters.fromFormData(OAuth2ParameterNames.GRANT_TYPE, GrantType.CLIENT_CREDENTIALS.getValue())) + .retrieve() + .bodyToMono(JsonNode.class) + .flatMap(tokenResponse -> { + String accessTokenValue = tokenResponse.get("access_token") + .textValue(); + logger.info("Retrieved the following access token: {}", accessTokenValue); + return client.get() + .uri(RESOURCE_ENDPOINT) + .headers(h -> h.setBearerAuth(accessTokenValue)) + .retrieve() + .bodyToMono(String.class); + }); + logger.info("non-blocking Oauth calls registered..."); + return resource.map(res -> "Retrieved the resource using a manual approach: " + res); + + } + +} diff --git a/spring-5-reactive-oauth/src/main/resources/application.yml b/spring-5-reactive-oauth/src/main/resources/application.yml index e35e19b344..bec62fdd33 100644 --- a/spring-5-reactive-oauth/src/main/resources/application.yml +++ b/spring-5-reactive-oauth/src/main/resources/application.yml @@ -1,20 +1,3 @@ -spring: - security: - oauth2: - client: - registration: - google: - client-id: YOUR_APP_CLIENT_ID - client-secret: YOUR_APP_CLIENT_SECRET - custom: - client-id: fooClientIdPassword - client-secret: secret - scopes: read,foo - authorization-grant-type: authorization_code - redirect-uri-template: http://localhost:8080/login/oauth2/code/custom - provider: - custom: - authorization-uri: http://localhost:8081/spring-security-oauth-server/oauth/authorize - token-uri: http://localhost:8081/spring-security-oauth-server/oauth/token - user-info-uri: http://localhost:8088/spring-security-oauth-resource/users/extra - user-name-attribute: user_name \ No newline at end of file +logging: + level: + root: DEBUG \ No newline at end of file diff --git a/spring-5-reactive-oauth/src/main/resources/default-application.yml b/spring-5-reactive-oauth/src/main/resources/default-application.yml new file mode 100644 index 0000000000..e35e19b344 --- /dev/null +++ b/spring-5-reactive-oauth/src/main/resources/default-application.yml @@ -0,0 +1,20 @@ +spring: + security: + oauth2: + client: + registration: + google: + client-id: YOUR_APP_CLIENT_ID + client-secret: YOUR_APP_CLIENT_SECRET + custom: + client-id: fooClientIdPassword + client-secret: secret + scopes: read,foo + authorization-grant-type: authorization_code + redirect-uri-template: http://localhost:8080/login/oauth2/code/custom + provider: + custom: + authorization-uri: http://localhost:8081/spring-security-oauth-server/oauth/authorize + token-uri: http://localhost:8081/spring-security-oauth-server/oauth/token + user-info-uri: http://localhost:8088/spring-security-oauth-resource/users/extra + user-name-attribute: user_name \ No newline at end of file diff --git a/spring-5-reactive-oauth/src/main/resources/webclient-auth-code-client-application.properties b/spring-5-reactive-oauth/src/main/resources/webclient-auth-code-client-application.properties new file mode 100644 index 0000000000..612777a06d --- /dev/null +++ b/spring-5-reactive-oauth/src/main/resources/webclient-auth-code-client-application.properties @@ -0,0 +1,10 @@ +spring.security.oauth2.client.registration.bael.client-name=bael +spring.security.oauth2.client.registration.bael.client-id=bael-client-id +spring.security.oauth2.client.registration.bael.client-secret=bael-secret +spring.security.oauth2.client.registration.bael.authorization-grant-type=authorization_code +spring.security.oauth2.client.registration.bael.redirect-uri=http://localhost:8080/authorize/oauth2/code/bael + +spring.security.oauth2.client.provider.bael.token-uri=http://localhost:8085/oauth/token +spring.security.oauth2.client.provider.bael.authorization-uri=http://localhost:8085/oauth/authorize + +spring.security.user.password=pass diff --git a/spring-5-reactive-oauth/src/main/resources/webclient-auth-code-login-application.properties b/spring-5-reactive-oauth/src/main/resources/webclient-auth-code-login-application.properties new file mode 100644 index 0000000000..edd5b80b13 --- /dev/null +++ b/spring-5-reactive-oauth/src/main/resources/webclient-auth-code-login-application.properties @@ -0,0 +1,10 @@ +spring.security.oauth2.client.registration.bael.client-name=bael +spring.security.oauth2.client.registration.bael.client-id=bael-client-id +spring.security.oauth2.client.registration.bael.client-secret=bael-secret +spring.security.oauth2.client.registration.bael.authorization-grant-type=authorization_code +spring.security.oauth2.client.registration.bael.redirect-uri=http://localhost:8080/login/oauth2/code/bael + +spring.security.oauth2.client.provider.bael.token-uri=http://localhost:8085/oauth/token +spring.security.oauth2.client.provider.bael.authorization-uri=http://localhost:8085/oauth/authorize +spring.security.oauth2.client.provider.bael.user-info-uri=http://localhost:8084/user +spring.security.oauth2.client.provider.bael.user-name-attribute=name diff --git a/spring-5-reactive-oauth/src/main/resources/webclient-client-credentials-oauth-application.properties b/spring-5-reactive-oauth/src/main/resources/webclient-client-credentials-oauth-application.properties new file mode 100644 index 0000000000..f82f74ec48 --- /dev/null +++ b/spring-5-reactive-oauth/src/main/resources/webclient-client-credentials-oauth-application.properties @@ -0,0 +1,4 @@ +spring.security.oauth2.client.registration.bael.authorization-grant-type=client_credentials +spring.security.oauth2.client.registration.bael.client-id=bael-client-id +spring.security.oauth2.client.registration.bael.client-secret=bael-secret +spring.security.oauth2.client.provider.bael.token-uri=http://localhost:8085/oauth/token diff --git a/spring-5-reactive-oauth/src/test/java/com/baeldung/webclient/clientcredentials/OAuth2ClientCredentialsLiveTest.java b/spring-5-reactive-oauth/src/test/java/com/baeldung/webclient/clientcredentials/OAuth2ClientCredentialsLiveTest.java new file mode 100644 index 0000000000..e31815c3f8 --- /dev/null +++ b/spring-5-reactive-oauth/src/test/java/com/baeldung/webclient/clientcredentials/OAuth2ClientCredentialsLiveTest.java @@ -0,0 +1,52 @@ +package com.baeldung.webclient.clientcredentials; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Collection; +import java.util.stream.Collectors; + +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 com.baeldung.webclient.clientcredentials.service.WebClientChonJob; +import com.baeldung.webclient.utils.ListAppender; + +import ch.qos.logback.classic.spi.ILoggingEvent; + +/** + * + * Note: this Live test requires the Authorization Service and the Resource service located in the spring-5-security-oauth module + * + * @author ger + * + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = { ClientCredentialsOauthApplication.class }) +public class OAuth2ClientCredentialsLiveTest { + + @Autowired + WebClientChonJob service; + + @Before + public void clearLogList() { + ListAppender.clearEventList(); + } + + @Test + public void givenFooWithNullId_whenProcessFoo_thenLogsWithDebugTrace() throws Exception { + service.logResourceServiceResponse(); + + Thread.sleep(3000); + + Collection allLoggedEntries = ListAppender.getEvents() + .stream() + .map(ILoggingEvent::getFormattedMessage) + .collect(Collectors.toList()); + assertThat(allLoggedEntries).anyMatch(entry -> entry.contains("We retrieved the following resource using Client Credentials Grant Type: This is the resource!")); + } + +} diff --git a/spring-5-reactive-oauth/src/test/java/com/baeldung/webclient/manualrequest/OAuth2ManualRequestLiveTest.java b/spring-5-reactive-oauth/src/test/java/com/baeldung/webclient/manualrequest/OAuth2ManualRequestLiveTest.java new file mode 100644 index 0000000000..94aa580f0a --- /dev/null +++ b/spring-5-reactive-oauth/src/test/java/com/baeldung/webclient/manualrequest/OAuth2ManualRequestLiveTest.java @@ -0,0 +1,43 @@ +package com.baeldung.webclient.manualrequest; + +import org.junit.Before; +import org.junit.Test; +import org.springframework.test.web.reactive.server.WebTestClient; +import org.springframework.test.web.reactive.server.WebTestClient.ResponseSpec; + +/** + * + * Note: this Live test requires not only the corresponding application running, + * but also the Authorization Service and the Resource service located in the spring-5-security-oauth module. + * + * + * @author ger + * + */ +public class OAuth2ManualRequestLiveTest { + + private static final String BASE_URL = "http://localhost:8080"; + private static final String MANUAL_REQUEST_URI = "/manual-request-oauth"; + + private static WebTestClient client; + + @Before + public void setup() { + client = WebTestClient.bindToServer() + .baseUrl(BASE_URL) + .build(); + } + + @Test + public void whenRequestingDebugHookOn_thenObtainExpectedMessage() { + ResponseSpec response = client.get() + .uri(MANUAL_REQUEST_URI) + .exchange(); + + response.expectStatus() + .isOk() + .expectBody(String.class) + .isEqualTo("Retrieved the resource using a manual approach: This is the resource!"); + } + +} diff --git a/spring-5-reactive-oauth/src/test/java/com/baeldung/webclient/utils/ListAppender.java b/spring-5-reactive-oauth/src/test/java/com/baeldung/webclient/utils/ListAppender.java new file mode 100644 index 0000000000..6f8fbe004a --- /dev/null +++ b/spring-5-reactive-oauth/src/test/java/com/baeldung/webclient/utils/ListAppender.java @@ -0,0 +1,25 @@ +package com.baeldung.webclient.utils; + +import java.util.ArrayList; +import java.util.List; + +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.AppenderBase; + +public class ListAppender extends AppenderBase { + + static private List events = new ArrayList<>(); + + @Override + protected void append(ILoggingEvent eventObject) { + events.add(eventObject); + } + + public static List getEvents() { + return events; + } + + public static void clearEventList() { + events.clear(); + } +} \ No newline at end of file diff --git a/spring-5-reactive-oauth/src/test/resources/logback-test.xml b/spring-5-reactive-oauth/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..891c54bfd3 --- /dev/null +++ b/spring-5-reactive-oauth/src/test/resources/logback-test.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/spring-5-reactive/README.md b/spring-5-reactive/README.md index 2a4ee017f4..c39bb616f8 100644 --- a/spring-5-reactive/README.md +++ b/spring-5-reactive/README.md @@ -18,3 +18,4 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring - [Validation for Functional Endpoints in Spring 5](https://www.baeldung.com/spring-functional-endpoints-validation) - [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) diff --git a/spring-5-security-oauth/README.md b/spring-5-security-oauth/README.md index f13925992b..5a444d4784 100644 --- a/spring-5-security-oauth/README.md +++ b/spring-5-security-oauth/README.md @@ -2,3 +2,4 @@ - [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/oauth2/SpringOAuthApplication.java b/spring-5-security-oauth/src/main/java/com/baeldung/oauth2/SpringOAuthApplication.java index 557c23b368..1478b03d2e 100644 --- a/spring-5-security-oauth/src/main/java/com/baeldung/oauth2/SpringOAuthApplication.java +++ b/spring-5-security-oauth/src/main/java/com/baeldung/oauth2/SpringOAuthApplication.java @@ -2,7 +2,9 @@ package com.baeldung.oauth2; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.PropertySource; +@PropertySource("classpath:default-application.properties") @SpringBootApplication public class SpringOAuthApplication { diff --git a/spring-5-security-oauth/src/main/java/com/baeldung/oauth2extractors/ExtractorsApplication.java b/spring-5-security-oauth/src/main/java/com/baeldung/oauth2extractors/ExtractorsApplication.java index 6ab4d525bf..174e5b0fdf 100644 --- a/spring-5-security-oauth/src/main/java/com/baeldung/oauth2extractors/ExtractorsApplication.java +++ b/spring-5-security-oauth/src/main/java/com/baeldung/oauth2extractors/ExtractorsApplication.java @@ -3,10 +3,12 @@ package com.baeldung.oauth2extractors; import org.apache.logging.log4j.util.Strings; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.PropertySource; import org.springframework.core.env.AbstractEnvironment; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; +@PropertySource("classpath:default-application.properties") @SpringBootApplication @Controller public class ExtractorsApplication { diff --git a/spring-5-security-oauth/src/main/java/com/baeldung/webclient/authorizationserver/AuthorizationServerApplication.java b/spring-5-security-oauth/src/main/java/com/baeldung/webclient/authorizationserver/AuthorizationServerApplication.java new file mode 100644 index 0000000000..d72704386c --- /dev/null +++ b/spring-5-security-oauth/src/main/java/com/baeldung/webclient/authorizationserver/AuthorizationServerApplication.java @@ -0,0 +1,17 @@ +package com.baeldung.webclient.authorizationserver; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.PropertySource; +import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer; + +@EnableAuthorizationServer +@PropertySource("classpath:webclient-authorization-application.properties") +@SpringBootApplication +public class AuthorizationServerApplication { + + public static void main(String[] args) { + SpringApplication.run(AuthorizationServerApplication.class, args); + } + +} diff --git a/spring-5-security-oauth/src/main/java/com/baeldung/webclient/authorizationserver/configuration/WebSecurityConfig.java b/spring-5-security-oauth/src/main/java/com/baeldung/webclient/authorizationserver/configuration/WebSecurityConfig.java new file mode 100644 index 0000000000..5dd15f1b8c --- /dev/null +++ b/spring-5-security-oauth/src/main/java/com/baeldung/webclient/authorizationserver/configuration/WebSecurityConfig.java @@ -0,0 +1,26 @@ +package com.baeldung.webclient.authorizationserver.configuration; + +import org.springframework.context.annotation.Configuration; +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 +@Configuration +public class WebSecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http.authorizeRequests() + .antMatchers("/login", "/user") + .permitAll() + .and() + .authorizeRequests() + .anyRequest() + .authenticated() + .and() + .formLogin() + .and() + .httpBasic(); + } +} diff --git a/spring-5-security-oauth/src/main/java/com/baeldung/webclient/resourceserver/ResourceServerApplication.java b/spring-5-security-oauth/src/main/java/com/baeldung/webclient/resourceserver/ResourceServerApplication.java new file mode 100644 index 0000000000..50ad293ef8 --- /dev/null +++ b/spring-5-security-oauth/src/main/java/com/baeldung/webclient/resourceserver/ResourceServerApplication.java @@ -0,0 +1,17 @@ +package com.baeldung.webclient.resourceserver; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.PropertySource; +import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; + +@EnableResourceServer +@PropertySource("webclient-resources-application.properties") +@SpringBootApplication +public class ResourceServerApplication { + + public static void main(String[] args) { + SpringApplication.run(ResourceServerApplication.class, args); + } + +} diff --git a/spring-5-security-oauth/src/main/java/com/baeldung/webclient/resourceserver/configuration/AuthorizationConfigs.java b/spring-5-security-oauth/src/main/java/com/baeldung/webclient/resourceserver/configuration/AuthorizationConfigs.java new file mode 100644 index 0000000000..5aea1983db --- /dev/null +++ b/spring-5-security-oauth/src/main/java/com/baeldung/webclient/resourceserver/configuration/AuthorizationConfigs.java @@ -0,0 +1,29 @@ +package com.baeldung.webclient.resourceserver.configuration; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.oauth2.provider.token.RemoteTokenServices; +import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices; + +@Configuration +public class AuthorizationConfigs { + + @Value("${oauth.authserver.client-id}") + String clientId; + + @Value("${oauth.authserver.client-secret}") + String clientSecret; + + @Value("${oauth.authserver.check-token-endpoint}") + String checkTokenEndpoint; + + @Bean + public ResourceServerTokenServices tokenSvc() { + RemoteTokenServices remoteService = new RemoteTokenServices(); + remoteService.setCheckTokenEndpointUrl(checkTokenEndpoint); + remoteService.setClientId(clientId); + remoteService.setClientSecret(clientSecret); + return remoteService; + } +} diff --git a/spring-5-security-oauth/src/main/java/com/baeldung/webclient/resourceserver/web/ResourceRestController.java b/spring-5-security-oauth/src/main/java/com/baeldung/webclient/resourceserver/web/ResourceRestController.java new file mode 100644 index 0000000000..aef0fb4d7d --- /dev/null +++ b/spring-5-security-oauth/src/main/java/com/baeldung/webclient/resourceserver/web/ResourceRestController.java @@ -0,0 +1,23 @@ +package com.baeldung.webclient.resourceserver.web; + +import java.security.Principal; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class ResourceRestController { + + @GetMapping("/retrieve-resource") + public String retrieveResource() { + return "This is the resource!"; + } + + @GetMapping("/user") + @ResponseBody + public Principal user(Principal user) { + return user; + } + +} diff --git a/spring-5-security-oauth/src/main/resources/application.properties b/spring-5-security-oauth/src/main/resources/application.properties index 5912b0f755..c84e745918 100644 --- a/spring-5-security-oauth/src/main/resources/application.properties +++ b/spring-5-security-oauth/src/main/resources/application.properties @@ -1,5 +1,3 @@ -server.port=8081 - logging.level.root=INFO logging.level.com.baeldung.dsl.ClientErrorLoggingFilter=DEBUG \ No newline at end of file diff --git a/spring-5-security-oauth/src/main/resources/default-application.properties b/spring-5-security-oauth/src/main/resources/default-application.properties new file mode 100644 index 0000000000..bafddced85 --- /dev/null +++ b/spring-5-security-oauth/src/main/resources/default-application.properties @@ -0,0 +1 @@ +server.port=8081 \ No newline at end of file diff --git a/spring-5-security-oauth/src/main/resources/webclient-authorization-application.properties b/spring-5-security-oauth/src/main/resources/webclient-authorization-application.properties new file mode 100644 index 0000000000..9531045359 --- /dev/null +++ b/spring-5-security-oauth/src/main/resources/webclient-authorization-application.properties @@ -0,0 +1,13 @@ +server.port=8085 + +security.oauth2.client.client-id=bael-client-id +security.oauth2.client.client-secret=bael-secret +security.oauth2.client.scope=read,write + +security.oauth2.authorization.check-token-access=isAuthenticated() + +spring.security.user.name=bael-user +spring.security.user.password=bael-password + +security.oauth2.client.registered-redirect-uri=http://localhost:8080/login/oauth2/code/bael, http://localhost:8080/authorize/oauth2/code/bael +security.oauth2.client.use-current-uri=false \ No newline at end of file diff --git a/spring-5-security-oauth/src/main/resources/webclient-resources-application.properties b/spring-5-security-oauth/src/main/resources/webclient-resources-application.properties new file mode 100644 index 0000000000..1cfb9ca12d --- /dev/null +++ b/spring-5-security-oauth/src/main/resources/webclient-resources-application.properties @@ -0,0 +1,6 @@ +server.port=8084 + +#spring.security.oauth2.resourceserver.jwt.issuer-uri=localhost:8085 +oauth.authserver.client-id=bael-client-id +oauth.authserver.client-secret=bael-secret +oauth.authserver.check-token-endpoint=http://localhost:8085/oauth/check_token diff --git a/spring-boot-ops/README.md b/spring-boot-ops/README.md index c125c96c36..553b02ebf0 100644 --- a/spring-boot-ops/README.md +++ b/spring-boot-ops/README.md @@ -9,4 +9,4 @@ - [Shutdown a Spring Boot Application](http://www.baeldung.com/spring-boot-shutdown) - [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) diff --git a/spring-boot-security/pom.xml b/spring-boot-security/pom.xml index d5c7976ba2..b87189757a 100644 --- a/spring-boot-security/pom.xml +++ b/spring-boot-security/pom.xml @@ -66,4 +66,8 @@ + + com.baeldung.springbootsecurity.basic_auth.SpringBootSecurityApplication + + diff --git a/spring-boot-testing/README.MD b/spring-boot-testing/README.MD index a609b5bf09..144c3581f7 100644 --- a/spring-boot-testing/README.MD +++ b/spring-boot-testing/README.MD @@ -4,3 +4,4 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring ### Relevant Articles: - [Testing with Spring and Spock](https://www.baeldung.com/spring-spock-testing) +- [Exclude Auto-Configuration Classes in Spring Boot Tests](https://www.baeldung.com/spring-boot-exclude-auto-configuration-test) diff --git a/spring-boot-testing/pom.xml b/spring-boot-testing/pom.xml index 2a498e54c5..c2c886a4fe 100644 --- a/spring-boot-testing/pom.xml +++ b/spring-boot-testing/pom.xml @@ -23,6 +23,10 @@ org.springframework.boot spring-boot-starter-tomcat + + org.springframework.boot + spring-boot-starter-security + org.springframework.boot spring-boot-starter-test @@ -43,6 +47,13 @@ ${spock.version} test + + + io.rest-assured + rest-assured + test + + @@ -98,51 +109,14 @@ - + - - - autoconfiguration - - - - org.apache.maven.plugins - maven-surefire-plugin - - - integration-test - - test - - - - **/*LiveTest.java - **/*IntegrationTest.java - **/*IntTest.java - - - **/AutoconfigurationTest.java - - - - - - - json - - - - - - - - - org.baeldung.boot.Application + com.baeldung.boot.Application 2.2.4 1.2-groovy-2.4 diff --git a/spring-boot-testing/src/main/java/com/baeldung/boot/Application.java b/spring-boot-testing/src/main/java/com/baeldung/boot/Application.java index c1b6558b26..cb0d0c1532 100644 --- a/spring-boot-testing/src/main/java/com/baeldung/boot/Application.java +++ b/spring-boot-testing/src/main/java/com/baeldung/boot/Application.java @@ -1,4 +1,4 @@ -package org.baeldung.boot; +package com.baeldung.boot; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; diff --git a/spring-boot-testing/src/main/java/com/baeldung/boot/controller/rest/HomeController.java b/spring-boot-testing/src/main/java/com/baeldung/boot/controller/rest/HomeController.java new file mode 100644 index 0000000000..595c34254b --- /dev/null +++ b/spring-boot-testing/src/main/java/com/baeldung/boot/controller/rest/HomeController.java @@ -0,0 +1,14 @@ +package com.baeldung.boot.controller.rest; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class HomeController { + + @GetMapping("/") + public String salutation() { + return "Welcome !"; + } + +} \ No newline at end of file diff --git a/spring-boot-testing/src/main/java/com/baeldung/boot/controller/rest/WebController.java b/spring-boot-testing/src/main/java/com/baeldung/boot/controller/rest/WebController.java index 5b65599e00..7247ca3dfa 100644 --- a/spring-boot-testing/src/main/java/com/baeldung/boot/controller/rest/WebController.java +++ b/spring-boot-testing/src/main/java/com/baeldung/boot/controller/rest/WebController.java @@ -1,4 +1,6 @@ -package org.baeldung.boot.controller.rest; +package com.baeldung.boot.controller.rest; + +import java.util.Optional; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.DeleteMapping; @@ -9,8 +11,6 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; -import java.util.Optional; - @RestController @RequestMapping("/hello") public class WebController { diff --git a/spring-boot-testing/src/main/resources/application-test.properties b/spring-boot-testing/src/main/resources/application-test.properties new file mode 100644 index 0000000000..8d5e86ba26 --- /dev/null +++ b/spring-boot-testing/src/main/resources/application-test.properties @@ -0,0 +1,3 @@ + +# test properties +spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration \ No newline at end of file diff --git a/spring-boot-testing/src/main/resources/application.properties b/spring-boot-testing/src/main/resources/application.properties new file mode 100644 index 0000000000..e378aacdd5 --- /dev/null +++ b/spring-boot-testing/src/main/resources/application.properties @@ -0,0 +1,4 @@ + +# security +spring.security.user.name=john +spring.security.user.password=123 \ No newline at end of file diff --git a/spring-boot-testing/src/test/groovy/org/baeldung/boot/LoadContextTest.groovy b/spring-boot-testing/src/test/groovy/com/baeldung/boot/LoadContextTest.groovy similarity index 87% rename from spring-boot-testing/src/test/groovy/org/baeldung/boot/LoadContextTest.groovy rename to spring-boot-testing/src/test/groovy/com/baeldung/boot/LoadContextTest.groovy index 2d4a7ca2cf..85b0a4b89b 100644 --- a/spring-boot-testing/src/test/groovy/org/baeldung/boot/LoadContextTest.groovy +++ b/spring-boot-testing/src/test/groovy/com/baeldung/boot/LoadContextTest.groovy @@ -1,6 +1,6 @@ -package org.baeldung.boot +package com.baeldung.boot -import org.baeldung.boot.controller.rest.WebController +import com.baeldung.boot.controller.rest.WebController import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest import spock.lang.Narrative diff --git a/spring-boot-testing/src/test/groovy/org/baeldung/boot/WebControllerTest.groovy b/spring-boot-testing/src/test/groovy/com/baeldung/boot/WebControllerTest.groovy similarity index 96% rename from spring-boot-testing/src/test/groovy/org/baeldung/boot/WebControllerTest.groovy rename to spring-boot-testing/src/test/groovy/com/baeldung/boot/WebControllerTest.groovy index fe1b34ab8c..d8b4e03adc 100644 --- a/spring-boot-testing/src/test/groovy/org/baeldung/boot/WebControllerTest.groovy +++ b/spring-boot-testing/src/test/groovy/com/baeldung/boot/WebControllerTest.groovy @@ -1,4 +1,4 @@ -package org.baeldung.boot +package com.baeldung.boot import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc @@ -12,8 +12,8 @@ import spock.lang.Title @Title("WebController Specification") @Narrative("The Specification of the behaviour of the WebController. It can greet a person, change the name and reset it to 'world'") -@AutoConfigureMockMvc -@WebMvcTest +@AutoConfigureMockMvc(secure=false) +@WebMvcTest() class WebControllerTest extends Specification { @Autowired diff --git a/spring-boot-testing/src/test/groovy/com/baeldung/boot/WebControllerTest.groovy alias b/spring-boot-testing/src/test/groovy/com/baeldung/boot/WebControllerTest.groovy alias new file mode 100644 index 0000000000..f2fc2f48e2 Binary files /dev/null and b/spring-boot-testing/src/test/groovy/com/baeldung/boot/WebControllerTest.groovy alias differ diff --git a/spring-boot-testing/src/test/java/com/baeldung/autoconfig/exclude/ExcludeAutoConfig1IntegrationTest.java b/spring-boot-testing/src/test/java/com/baeldung/autoconfig/exclude/ExcludeAutoConfig1IntegrationTest.java new file mode 100644 index 0000000000..a4a29cddf3 --- /dev/null +++ b/spring-boot-testing/src/test/java/com/baeldung/autoconfig/exclude/ExcludeAutoConfig1IntegrationTest.java @@ -0,0 +1,26 @@ +package com.baeldung.autoconfig.exclude; + +import static org.junit.Assert.assertEquals; +import io.restassured.RestAssured; + +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.HttpStatus; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; + +import com.baeldung.boot.Application; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = Application.class, webEnvironment = WebEnvironment.DEFINED_PORT) +@TestPropertySource(properties = "spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration") +public class ExcludeAutoConfig1IntegrationTest { + + @Test + public void givenSecurityConfigExcluded_whenAccessHome_thenNoAuthenticationRequired() { + int statusCode = RestAssured.get("http://localhost:8080/").statusCode(); + assertEquals(HttpStatus.OK.value(), statusCode); + } +} diff --git a/spring-boot-testing/src/test/java/com/baeldung/autoconfig/exclude/ExcludeAutoConfig2IntegrationTest.java b/spring-boot-testing/src/test/java/com/baeldung/autoconfig/exclude/ExcludeAutoConfig2IntegrationTest.java new file mode 100644 index 0000000000..cdf79b159c --- /dev/null +++ b/spring-boot-testing/src/test/java/com/baeldung/autoconfig/exclude/ExcludeAutoConfig2IntegrationTest.java @@ -0,0 +1,26 @@ +package com.baeldung.autoconfig.exclude; + +import static org.junit.Assert.assertEquals; +import io.restassured.RestAssured; + +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.HttpStatus; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringRunner; + +import com.baeldung.boot.Application; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = Application.class, webEnvironment = WebEnvironment.DEFINED_PORT) +@ActiveProfiles("test") +public class ExcludeAutoConfig2IntegrationTest { + + @Test + public void givenSecurityConfigExcluded_whenAccessHome_thenNoAuthenticationRequired() { + int statusCode = RestAssured.get("http://localhost:8080/").statusCode(); + assertEquals(HttpStatus.OK.value(), statusCode); + } +} diff --git a/spring-boot-testing/src/test/java/com/baeldung/autoconfig/exclude/ExcludeAutoConfig3IntegrationTest.java b/spring-boot-testing/src/test/java/com/baeldung/autoconfig/exclude/ExcludeAutoConfig3IntegrationTest.java new file mode 100644 index 0000000000..0e45d1e9e5 --- /dev/null +++ b/spring-boot-testing/src/test/java/com/baeldung/autoconfig/exclude/ExcludeAutoConfig3IntegrationTest.java @@ -0,0 +1,27 @@ +package com.baeldung.autoconfig.exclude; + +import static org.junit.Assert.assertEquals; +import io.restassured.RestAssured; + +import org.junit.Test; +import org.junit.runner.RunWith; +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.http.HttpStatus; +import org.springframework.test.context.junit4.SpringRunner; + +import com.baeldung.boot.Application; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = Application.class, webEnvironment = WebEnvironment.DEFINED_PORT) +@EnableAutoConfiguration(exclude=SecurityAutoConfiguration.class) +public class ExcludeAutoConfig3IntegrationTest { + + @Test + public void givenSecurityConfigExcluded_whenAccessHome_thenNoAuthenticationRequired() { + int statusCode = RestAssured.get("http://localhost:8080/").statusCode(); + assertEquals(HttpStatus.OK.value(), statusCode); + } +} diff --git a/spring-boot-testing/src/test/java/com/baeldung/autoconfig/exclude/ExcludeAutoConfig4IntegrationTest.java b/spring-boot-testing/src/test/java/com/baeldung/autoconfig/exclude/ExcludeAutoConfig4IntegrationTest.java new file mode 100644 index 0000000000..8429aed6cd --- /dev/null +++ b/spring-boot-testing/src/test/java/com/baeldung/autoconfig/exclude/ExcludeAutoConfig4IntegrationTest.java @@ -0,0 +1,22 @@ +package com.baeldung.autoconfig.exclude; + +import static org.junit.Assert.assertEquals; +import io.restassured.RestAssured; + +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.HttpStatus; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = TestApplication.class, webEnvironment = WebEnvironment.DEFINED_PORT) +public class ExcludeAutoConfig4IntegrationTest { + + @Test + public void givenSecurityConfigExcluded_whenAccessHome_thenNoAuthenticationRequired() { + int statusCode = RestAssured.get("http://localhost:8080/").statusCode(); + assertEquals(HttpStatus.OK.value(), statusCode); + } +} diff --git a/spring-boot-testing/src/test/java/com/baeldung/autoconfig/exclude/TestApplication.java b/spring-boot-testing/src/test/java/com/baeldung/autoconfig/exclude/TestApplication.java new file mode 100644 index 0000000000..7c162f85ab --- /dev/null +++ b/spring-boot-testing/src/test/java/com/baeldung/autoconfig/exclude/TestApplication.java @@ -0,0 +1,13 @@ +package com.baeldung.autoconfig.exclude; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; + +@SpringBootApplication(scanBasePackages="com.baeldung.boot", exclude=SecurityAutoConfiguration.class) +public class TestApplication { + + public static void main(String[] args) { + SpringApplication.run(TestApplication.class, args); + } +} diff --git a/spring-boot-testing/src/test/java/com/baeldung/boot/SpringContextIntegrationTest.java b/spring-boot-testing/src/test/java/com/baeldung/boot/SpringContextIntegrationTest.java new file mode 100644 index 0000000000..63ab07fdb7 --- /dev/null +++ b/spring-boot-testing/src/test/java/com/baeldung/boot/SpringContextIntegrationTest.java @@ -0,0 +1,15 @@ +package com.baeldung.boot; + +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() { + } +} diff --git a/spring-boot-testing/src/test/java/com/baeldung/boot/autoconfig/AutoConfigIntegrationTest.java b/spring-boot-testing/src/test/java/com/baeldung/boot/autoconfig/AutoConfigIntegrationTest.java new file mode 100644 index 0000000000..fe71f44ddf --- /dev/null +++ b/spring-boot-testing/src/test/java/com/baeldung/boot/autoconfig/AutoConfigIntegrationTest.java @@ -0,0 +1,30 @@ +package com.baeldung.boot.autoconfig; + +import static org.junit.Assert.assertEquals; +import io.restassured.RestAssured; + +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.HttpStatus; +import org.springframework.test.context.junit4.SpringRunner; + +import com.baeldung.boot.Application; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = Application.class, webEnvironment = WebEnvironment.DEFINED_PORT) +public class AutoConfigIntegrationTest { + + @Test + public void givenNoAuthentication_whenAccessHome_thenUnauthorized() { + int statusCode = RestAssured.get("http://localhost:8080/").statusCode(); + assertEquals(HttpStatus.UNAUTHORIZED.value(), statusCode); + } + + @Test + public void givenAuthentication_whenAccessHome_thenOK() { + int statusCode = RestAssured.given().auth().basic("john", "123").get("http://localhost:8080/").statusCode(); + assertEquals(HttpStatus.OK.value(), statusCode); + } +} diff --git a/spring-cloud/spring-cloud-kubernetes/README.md b/spring-cloud/spring-cloud-kubernetes/README.md index 295ead1c2f..2387758626 100644 --- a/spring-cloud/spring-cloud-kubernetes/README.md +++ b/spring-cloud/spring-cloud-kubernetes/README.md @@ -1,3 +1,4 @@ ### Relevant Articles: - [Running Spring Boot Applications With Minikube](https://www.baeldung.com/spring-boot-minikube) +- [Self-Healing Applications with Kubernetes and Spring Boot](https://www.baeldung.com/spring-boot-kubernetes-self-healing-apps) diff --git a/spring-core/src/main/java/com/baeldung/annotation/MyBean.java b/spring-core/src/main/java/com/baeldung/annotation/MyBean.java new file mode 100644 index 0000000000..9a1fd3beec --- /dev/null +++ b/spring-core/src/main/java/com/baeldung/annotation/MyBean.java @@ -0,0 +1,26 @@ +package com.baeldung.annotation; + +import org.springframework.stereotype.Component; +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; + +@Component +public class MyBean { + + private final TestBean testBean; + + public MyBean(TestBean testBean) { + this.testBean = testBean; + System.out.println("Hello from constructor"); + } + + @PostConstruct + private void postConstruct() { + System.out.println("Hello from @PostConstruct method"); + } + + @PreDestroy + public void preDestroy() { + System.out.println("Bean is being destroyed"); + } +} \ No newline at end of file diff --git a/spring-core/src/main/java/com/baeldung/annotation/TestBean.java b/spring-core/src/main/java/com/baeldung/annotation/TestBean.java new file mode 100644 index 0000000000..0539e10751 --- /dev/null +++ b/spring-core/src/main/java/com/baeldung/annotation/TestBean.java @@ -0,0 +1,8 @@ +package com.baeldung.annotation; + +import org.springframework.stereotype.Component; + +@Component +public class TestBean { + +} \ No newline at end of file diff --git a/spring-core/src/main/java/com/baeldung/value/ValuesApp.java b/spring-core/src/main/java/com/baeldung/value/ValuesApp.java index f525dfde89..80893c1adf 100644 --- a/spring-core/src/main/java/com/baeldung/value/ValuesApp.java +++ b/spring-core/src/main/java/com/baeldung/value/ValuesApp.java @@ -2,6 +2,7 @@ package com.baeldung.value; import java.util.Arrays; import java.util.List; +import java.util.Map; import javax.annotation.PostConstruct; @@ -45,6 +46,27 @@ public class ValuesApp { @Value("#{'${listOfValues}'.split(',')}") private List valuesList; + + @Value("#{${valuesMap}}") + private Map valuesMap; + + @Value("#{${valuesMap}.key1}") + private Integer valuesMapKey1; + + @Value("#{${valuesMap}['unknownKey']}") + private Integer unknownMapKey; + + @Value("#{${unknownMap : {key1:'1', key2 : '2'}}}") + private Map unknownMap; + + @Value("#{${valuesMap}['unknownKey'] ?: 5}") + private Integer unknownMapKeyWithDefaultValue; + + @Value("#{${valuesMap}.?[value>'1']}") + private Map valuesMapFiltered; + + @Value("#{systemProperties}") + private Map systemPropertiesMap; public static void main(String[] args) { System.setProperty("systemValue", "Some system parameter value"); @@ -69,5 +91,12 @@ public class ValuesApp { System.out.println(spelSomeDefault); System.out.println(someBeanValue); System.out.println(valuesList); + System.out.println(valuesMap); + System.out.println(valuesMapKey1); + System.out.println(unknownMapKey); + System.out.println(unknownMap); + System.out.println(unknownMapKeyWithDefaultValue); + System.out.println(valuesMapFiltered); + System.out.println(systemPropertiesMap); } } diff --git a/spring-core/src/main/resources/values.properties b/spring-core/src/main/resources/values.properties index d7d61b8ee8..c6db5873fb 100644 --- a/spring-core/src/main/resources/values.properties +++ b/spring-core/src/main/resources/values.properties @@ -1,3 +1,4 @@ value.from.file=Value got from the file priority=Properties file -listOfValues=A,B,C \ No newline at end of file +listOfValues=A,B,C +valuesMap={key1:'1', key2 : '2', key3 : '3'} \ No newline at end of file diff --git a/spring-ehcache/.gitignore b/spring-ehcache/.gitignore new file mode 100644 index 0000000000..83c05e60c8 --- /dev/null +++ b/spring-ehcache/.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/spring-ehcache/README.md b/spring-ehcache/README.md new file mode 100644 index 0000000000..749441375e --- /dev/null +++ b/spring-ehcache/README.md @@ -0,0 +1,7 @@ +## Spring Ehcache Example Project + +A simple example of using ehcache with spring-boot. + +### Relevant Articles: +- [Spring Boot Ehcache Example](http://www.baeldung.com/spring-ehcache) + diff --git a/spring-ehcache/checkstyle.xml b/spring-ehcache/checkstyle.xml new file mode 100644 index 0000000000..85063a7570 --- /dev/null +++ b/spring-ehcache/checkstyle.xml @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/spring-ehcache/pom.xml b/spring-ehcache/pom.xml new file mode 100644 index 0000000000..b8378617c5 --- /dev/null +++ b/spring-ehcache/pom.xml @@ -0,0 +1,87 @@ + + 4.0.0 + spring-ehcache + 0.1-SNAPSHOT + spring-ehcache + jar + + + 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-cache + + + javax.cache + cache-api + + + org.ehcache + ehcache + + + + + spring-ehcache + + + src/main/resources + true + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + org.apache.maven.plugins + maven-checkstyle-plugin + ${checkstyle-maven-plugin.version} + + checkstyle.xml + + + + + check + + + + + + + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + ${checkstyle-maven-plugin.version} + + checkstyle.xml + + + + + + + + 3.0.0 + false + + + diff --git a/spring-ehcache/src/main/java/com/baeldung/cachetest/Application.java b/spring-ehcache/src/main/java/com/baeldung/cachetest/Application.java new file mode 100644 index 0000000000..a1ce7a5317 --- /dev/null +++ b/spring-ehcache/src/main/java/com/baeldung/cachetest/Application.java @@ -0,0 +1,13 @@ +package com.baeldung.cachetest; + +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); + } + +} \ No newline at end of file diff --git a/spring-ehcache/src/main/java/com/baeldung/cachetest/config/CacheConfig.java b/spring-ehcache/src/main/java/com/baeldung/cachetest/config/CacheConfig.java new file mode 100644 index 0000000000..3cf2309cb9 --- /dev/null +++ b/spring-ehcache/src/main/java/com/baeldung/cachetest/config/CacheConfig.java @@ -0,0 +1,57 @@ +package com.baeldung.cachetest.config; + +import java.math.BigDecimal; +import java.time.Duration; + +import javax.cache.CacheManager; + +import org.ehcache.config.CacheConfiguration; +import org.ehcache.config.ResourcePools; +import org.ehcache.config.builders.CacheConfigurationBuilder; +import org.ehcache.config.builders.CacheEventListenerConfigurationBuilder; +import org.ehcache.config.builders.ExpiryPolicyBuilder; +import org.ehcache.config.builders.ResourcePoolsBuilder; +import org.ehcache.config.units.EntryUnit; +import org.ehcache.config.units.MemoryUnit; +import org.ehcache.event.EventType; +import org.ehcache.jsr107.Eh107Configuration; +import org.springframework.boot.autoconfigure.cache.JCacheManagerCustomizer; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@EnableCaching +public class CacheConfig { + + private static final int ON_HEAP_CACHE_SIZE_ENTRIES = 2; + private static final int OFF_HEAP_CACHE_SIZE_MB = 10; + private static final int CACHE_EXPIRY_SECONDS = 30; + + @Bean + public JCacheManagerCustomizer jcacheManagerCustomizer() { + return new JCacheManagerCustomizer() { + + @Override + public void customize(CacheManager cacheManager) { + ResourcePools resourcePools = ResourcePoolsBuilder.newResourcePoolsBuilder() + .heap(ON_HEAP_CACHE_SIZE_ENTRIES, EntryUnit.ENTRIES) + .offheap(OFF_HEAP_CACHE_SIZE_MB, MemoryUnit.MB).build(); + + CacheEventListenerConfigurationBuilder eventLoggerConfig = CacheEventListenerConfigurationBuilder + .newEventListenerConfiguration(new CacheEventLogger(), EventType.CREATED, EventType.EXPIRED) + .unordered().asynchronous(); + + CacheConfiguration cacheConfiguration = CacheConfigurationBuilder + .newCacheConfigurationBuilder(Long.class, BigDecimal.class, resourcePools) + .withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofSeconds(CACHE_EXPIRY_SECONDS))) + .add(eventLoggerConfig).build(); + + cacheManager.createCache("squareCache", + Eh107Configuration.fromEhcacheCacheConfiguration(cacheConfiguration)); + + } + }; + } + +} diff --git a/spring-ehcache/src/main/java/com/baeldung/cachetest/config/CacheEventLogger.java b/spring-ehcache/src/main/java/com/baeldung/cachetest/config/CacheEventLogger.java new file mode 100644 index 0000000000..c8ead85f1e --- /dev/null +++ b/spring-ehcache/src/main/java/com/baeldung/cachetest/config/CacheEventLogger.java @@ -0,0 +1,18 @@ +package com.baeldung.cachetest.config; + +import org.ehcache.event.CacheEvent; +import org.ehcache.event.CacheEventListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class CacheEventLogger implements CacheEventListener { + + private static final Logger log = LoggerFactory.getLogger(CacheEventLogger.class); + + @Override + public void onEvent(CacheEvent cacheEvent) { + log.info("Cache event {} for item with key {}. Old value = {}, New value = {}", cacheEvent.getType(), + cacheEvent.getKey(), cacheEvent.getOldValue(), cacheEvent.getNewValue()); + } + +} diff --git a/spring-ehcache/src/main/java/com/baeldung/cachetest/rest/NumberController.java b/spring-ehcache/src/main/java/com/baeldung/cachetest/rest/NumberController.java new file mode 100644 index 0000000000..4115c34cc4 --- /dev/null +++ b/spring-ehcache/src/main/java/com/baeldung/cachetest/rest/NumberController.java @@ -0,0 +1,29 @@ +package com.baeldung.cachetest.rest; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +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 com.baeldung.cachetest.service.NumberService; + +@RestController +@RequestMapping(path = "/number", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) +public class NumberController { + + private final static Logger log = LoggerFactory.getLogger(NumberController.class); + + @Autowired + private NumberService numberService; + + @GetMapping(path = "/square/{number}") + public String getThing(@PathVariable Long number) { + log.info("call numberService to square {}", number); + return String.format("{\"square\": %s}", numberService.square(number)); + } + +} diff --git a/spring-ehcache/src/main/java/com/baeldung/cachetest/service/NumberService.java b/spring-ehcache/src/main/java/com/baeldung/cachetest/service/NumberService.java new file mode 100644 index 0000000000..bcd930f5e1 --- /dev/null +++ b/spring-ehcache/src/main/java/com/baeldung/cachetest/service/NumberService.java @@ -0,0 +1,22 @@ +package com.baeldung.cachetest.service; + +import java.math.BigDecimal; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; + +@Service +public class NumberService { + + private final static Logger log = LoggerFactory.getLogger(NumberService.class); + + @Cacheable(value = "squareCache", key = "#number", condition = "#number>10") + public BigDecimal square(Long number) { + BigDecimal square = BigDecimal.valueOf(number).multiply(BigDecimal.valueOf(number)); + log.info("square of {} is {}", number, square); + return square; + } + +}