diff --git a/.travis.yml b/.travis.yml index 502c234c72..3a953a2e7b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,16 +1,12 @@ language: java before_install: - - export MAVEN_OPTS="-Xmx2048M -Xss128M -XX:+CMSClassUnloadingEnabled -XX:+UseG1GC -XX:-UseGCOverheadLimit" - echo "MAVEN_OPTS='-Xmx2048M -Xss128M -XX:+CMSClassUnloadingEnabled -XX:+UseG1GC -XX:-UseGCOverheadLimit'" > ~/.mavenrc install: travis_wait 60 mvn -q test -fae sudo: required -before_script: - - echo "MAVEN_OPTS='-Xmx2048M -Xss128M -XX:+CMSClassUnloadingEnabled -XX:+UseG1GC -XX:-UseGCOverheadLimit'" > ~/.mavenrc - jdk: - oraclejdk8 diff --git a/core-java-9/src/test/java/com/baeldung/java9/Java9OptionalTest.java b/core-java-9/src/test/java/com/baeldung/java9/Java9OptionalTest.java new file mode 100644 index 0000000000..cd0efb028d --- /dev/null +++ b/core-java-9/src/test/java/com/baeldung/java9/Java9OptionalTest.java @@ -0,0 +1,85 @@ +package com.baeldung.java9; + +public class Java9OptionalTest { + @Test + public void givenOptionalOfSome_whenToStream_thenShouldTreatItAsOneElementStream() { + //given + Optional value = Optional.of("a"); + + //when + List collect = value.stream().map(String::toUpperCase).collect(Collectors.toList()); + + //then + assertThat(collect).hasSameElementsAs(List.of("A")); + } + + @Test + public void givenOptionalOfNone_whenToStream_thenShouldTreatItAsZeroElementStream() { + //given + Optional value = Optional.empty(); + + //when + List collect = value.stream().map(String::toUpperCase).collect(Collectors.toList()); + + //then + assertThat(collect).isEmpty(); + } + + @Test + public void givenOptional_whenPresent_thenShouldExecuteProperCallback() { + //given + Optional value = Optional.of("properValue"); + AtomicInteger successCounter = new AtomicInteger(0); + AtomicInteger onEmptyOptionalCounter = new AtomicInteger(0); + + //when + value.ifPresentOrElse((v) -> successCounter.incrementAndGet(), onEmptyOptionalCounter::incrementAndGet); + + //then + assertThat(successCounter.get()).isEqualTo(1); + assertThat(onEmptyOptionalCounter.get()).isEqualTo(0); + } + + @Test + public void givenOptional_whenNotPresent_thenShouldExecuteProperCallback() { + //given + Optional value = Optional.empty(); + AtomicInteger successCounter = new AtomicInteger(0); + AtomicInteger onEmptyOptionalCounter = new AtomicInteger(0); + + //when + value.ifPresentOrElse((v) -> successCounter.incrementAndGet(), onEmptyOptionalCounter::incrementAndGet); + + //then + assertThat(successCounter.get()).isEqualTo(0); + assertThat(onEmptyOptionalCounter.get()).isEqualTo(1); + } + + @Test + public void givenOptional_whenPresent_thenShouldTakeAValueFromIt() { + //given + String expected = "properValue"; + Optional value = Optional.of(expected); + Optional defaultValue = Optional.of("default"); + + //when + Optional result = value.or(() -> defaultValue); + + //then + assertThat(result.get()).isEqualTo(expected); + } + + @Test + public void givenOptional_whenEmpty_thenShouldTakeAValueFromOr() { + //given + String defaultString = "default"; + Optional value = Optional.empty(); + Optional defaultValue = Optional.of(defaultString); + + //when + Optional result = value.or(() -> defaultValue); + + //then + assertThat(result.get()).isEqualTo(defaultString); + } +} \ No newline at end of file diff --git a/core-java/README.md b/core-java/README.md index c17677c23c..6c671a632d 100644 --- a/core-java/README.md +++ b/core-java/README.md @@ -102,3 +102,15 @@ - [How to Perform a Simple HTTP Request in Java](http://www.baeldung.com/java-http-request) - [Call Methods at Runtime Using Java Reflection](http://www.baeldung.com/java-method-reflection) - [Guide to DelayQueue](http://www.baeldung.com/java-delay-queue) +- [Guide to UUID in JAVA] (http://www.baeldung.com/guide-to-uuid-in-java) +- [Comparing getPath(), getAbsolutePath(), and getCanonicalPath() in Java](http://www.baeldung.com/java-path) +- [How to Add a Single Element to a Stream](http://www.baeldung.com/java-stream-append-prepend) +- [Iterating Over Enum Values in Java](http://www.baeldung.com/java-enum-iteration) +- [A Guide to Java SynchronousQueue](http://www.baeldung.com/java-synchronous-queue) +- [Guide to the Java TransferQueue](http://www.baeldung.com/java-transfer-queue) +- [Kotlin Java Interoperability](http://www.baeldung.com/kotlin-java-interoperability) +- [Guide to the ConcurrentSkipListMap](http://www.baeldung.com/java-concurrent-skip-list-map) +- [Difference Between Wait and Sleep in Java](http://www.baeldung.com/java-wait-and-sleep) +- [LongAdder and LongAccumulator in Java](http://www.baeldung.com/java-longadder-and-longaccumulator) +- [Using Java MappedByteBuffer](http://www.baeldung.com/java-mapped-byte-buffer) + diff --git a/core-java/src/main/java/com/baeldung/concurrent/diningphilosophers/DiningPhilosophers.java b/core-java/src/main/java/com/baeldung/concurrent/diningphilosophers/DiningPhilosophers.java new file mode 100644 index 0000000000..7a077432f5 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/concurrent/diningphilosophers/DiningPhilosophers.java @@ -0,0 +1,29 @@ +package com.baeldung.concurrent.diningphilosophers; + +public class DiningPhilosophers { + + public static void main(String[] args) throws Exception { + + Philosopher[] philosophers = new Philosopher[5]; + Object[] forks = new Object[philosophers.length]; + + for (int i = 0; i < forks.length; i++) { + forks[i] = new Object(); + } + + for (int i = 0; i < philosophers.length; i++) { + + Object leftFork = forks[i]; + Object rightFork = forks[(i + 1) % forks.length]; + + if (i == philosophers.length - 1) { + philosophers[i] = new Philosopher(rightFork, leftFork); // The last philosopher picks up the right fork first + } else { + philosophers[i] = new Philosopher(leftFork, rightFork); + } + + Thread t = new Thread(philosophers[i], "Philosopher " + (i + 1)); + t.start(); + } + } +} diff --git a/core-java/src/main/java/com/baeldung/concurrent/diningphilosophers/Philosopher.java b/core-java/src/main/java/com/baeldung/concurrent/diningphilosophers/Philosopher.java new file mode 100644 index 0000000000..3f1eacd276 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/concurrent/diningphilosophers/Philosopher.java @@ -0,0 +1,36 @@ +package com.baeldung.concurrent.diningphilosophers; + +public class Philosopher implements Runnable { + + private final Object leftFork; + private final Object rightFork; + + public Philosopher(Object left, Object right) { + this.leftFork = left; + this.rightFork = right; + } + + private void doAction(String action) throws InterruptedException { + System.out.println(Thread.currentThread().getName() + " " + action); + Thread.sleep(((int) (Math.random() * 100))); + } + + @Override public void run() { + try { + while (true) { + doAction(System.nanoTime() + ": Thinking"); // thinking + synchronized (leftFork) { + doAction(System.nanoTime() + ": Picked up left fork"); + synchronized (rightFork) { + doAction(System.nanoTime() + ": Picked up right fork - eating"); // eating + doAction(System.nanoTime() + ": Put down right fork"); + } + doAction(System.nanoTime() + ": Put down left fork. Returning to thinking"); + } + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return; + } + } +} \ No newline at end of file diff --git a/core-java/src/main/java/com/baeldung/java/enumiteration/DaysOfWeekEnum.java b/core-java/src/main/java/com/baeldung/java/enumiteration/DaysOfWeekEnum.java new file mode 100644 index 0000000000..89e718adf3 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/java/enumiteration/DaysOfWeekEnum.java @@ -0,0 +1,31 @@ +package com.baeldung.java.enumiteration; + +import java.util.stream.Stream; + +public enum DaysOfWeekEnum { + SUNDAY("off"), + MONDAY("working"), + TUESDAY("working"), + WEDNESDAY("working"), + THURSDAY("working"), + FRIDAY("working"), + SATURDAY("off"); + + private String typeOfDay; + + DaysOfWeekEnum(String typeOfDay) { + this.typeOfDay = typeOfDay; + } + + public String getTypeOfDay() { + return typeOfDay; + } + + public void setTypeOfDay(String typeOfDay) { + this.typeOfDay = typeOfDay; + } + + public static Stream stream() { + return Stream.of(DaysOfWeekEnum.values()); + } +} diff --git a/core-java/src/main/java/com/baeldung/java/enumiteration/EnumIterationExamples.java b/core-java/src/main/java/com/baeldung/java/enumiteration/EnumIterationExamples.java new file mode 100644 index 0000000000..2d874fa650 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/java/enumiteration/EnumIterationExamples.java @@ -0,0 +1,18 @@ +package com.baeldung.java.enumiteration; + +import java.util.EnumSet; + +public class EnumIterationExamples { + public static void main(String[] args) { + System.out.println("Enum iteration using forEach:"); + EnumSet.allOf(DaysOfWeekEnum.class).forEach(day -> System.out.println(day)); + + System.out.println("Enum iteration using Stream:"); + DaysOfWeekEnum.stream().filter(d -> d.getTypeOfDay().equals("off")).forEach(System.out::println); + + System.out.println("Enum iteration using for loop:"); + for (DaysOfWeekEnum day : DaysOfWeekEnum.values()) { + System.out.println(day); + } + } +} diff --git a/core-java/src/main/java/com/baeldung/maths/Round.java b/core-java/src/main/java/com/baeldung/maths/Round.java index a38f5e2526..82eeba725c 100644 --- a/core-java/src/main/java/com/baeldung/maths/Round.java +++ b/core-java/src/main/java/com/baeldung/maths/Round.java @@ -33,7 +33,7 @@ public class Round { public static double roundNotPrecise(double value, int places) { if (places < 0) throw new IllegalArgumentException(); - + BigDecimal bd = new BigDecimal(value); bd = bd.setScale(places, RoundingMode.HALF_UP); return bd.doubleValue(); diff --git a/core-java/src/main/java/com/baeldung/noclassdeffounderror/ClassWithInitErrors.java b/core-java/src/main/java/com/baeldung/noclassdeffounderror/ClassWithInitErrors.java new file mode 100644 index 0000000000..2b19f3496d --- /dev/null +++ b/core-java/src/main/java/com/baeldung/noclassdeffounderror/ClassWithInitErrors.java @@ -0,0 +1,5 @@ +package com.baeldung.noclassdeffounderror; + +public class ClassWithInitErrors { + static int data = 1 / 0; +} diff --git a/core-java/src/main/java/com/baeldung/noclassdeffounderror/NoClassDefFoundErrorExample.java b/core-java/src/main/java/com/baeldung/noclassdeffounderror/NoClassDefFoundErrorExample.java new file mode 100644 index 0000000000..2c852b5e82 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/noclassdeffounderror/NoClassDefFoundErrorExample.java @@ -0,0 +1,14 @@ +package com.baeldung.noclassdeffounderror; + +public class NoClassDefFoundErrorExample { + public ClassWithInitErrors getClassWithInitErrors() { + ClassWithInitErrors test; + try { + test = new ClassWithInitErrors(); + } catch (Throwable t) { + System.out.println(t); + } + test = new ClassWithInitErrors(); + return test; + } +} diff --git a/core-java/src/main/java/com/baeldung/stream/StreamApi.java b/core-java/src/main/java/com/baeldung/stream/StreamApi.java new file mode 100644 index 0000000000..ec792314d2 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/stream/StreamApi.java @@ -0,0 +1,24 @@ +package com.baeldung.stream; + +import java.util.List; +import java.util.stream.Stream; + +public class StreamApi { + + public String getLastElementUsingReduce(List valueList) { + Stream stream = valueList.stream(); + return stream.reduce((first, second) -> second).orElse(null); + } + + public Integer getInfiniteStreamLastElementUsingReduce() { + Stream stream = Stream.iterate(0, i -> i + 1); + return stream.limit(20).reduce((first, second) -> second).orElse(null); + } + + public String getLastElementUsingSkip(List valueList) { + long count = valueList.stream().count(); + Stream stream = valueList.stream(); + return stream.skip(count - 1).findFirst().orElse(null); + } + +} diff --git a/core-java/src/main/java/com/baeldung/string/StringHelper.java b/core-java/src/main/java/com/baeldung/string/StringHelper.java index ad2a0b3419..dac0d1272e 100644 --- a/core-java/src/main/java/com/baeldung/string/StringHelper.java +++ b/core-java/src/main/java/com/baeldung/string/StringHelper.java @@ -2,23 +2,23 @@ package com.baeldung.string; import java.util.Optional; -public class StringHelper { - public static String removeLastChar(String s) { +class StringHelper { + static String removeLastChar(String s) { return (s == null || s.length() == 0) ? s : (s.substring(0, s.length() - 1)); } - public static String removeLastCharRegex(String s) { + static String removeLastCharRegex(String s) { return (s == null) ? s : s.replaceAll(".$", ""); } - public static String removeLastCharOptional(String s) { + static String removeLastCharOptional(String s) { return Optional.ofNullable(s) .filter(str -> str.length() != 0) .map(str -> str.substring(0, str.length() - 1)) .orElse(s); } - public static String removeLastCharRegexOptional(String s) { + static String removeLastCharRegexOptional(String s) { return Optional.ofNullable(s) .map(str -> str.replaceAll(".$", "")) .orElse(s); diff --git a/core-java/src/main/java/com/baeldung/uuid/UUIDGenerator.java b/core-java/src/main/java/com/baeldung/uuid/UUIDGenerator.java new file mode 100644 index 0000000000..23baf5d5b4 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/uuid/UUIDGenerator.java @@ -0,0 +1,118 @@ +package com.baeldung.uuid; + +import java.io.UnsupportedEncodingException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.UUID; + +public class UUIDGenerator { + + /** + * These are predefined UUID for name spaces + */ + private static final String NAMESPACE_DNS = "6ba7b810-9dad-11d1-80b4-00c04fd430c8"; + private static final String NAMESPACE_URL = "6ba7b811-9dad-11d1-80b4-00c04fd430c8"; + private static final String NAMESPACE_OID = "6ba7b812-9dad-11d1-80b4-00c04fd430c8"; + private static final String NAMESPACE_X500 = "6ba7b814-9dad-11d1-80b4-00c04fd430c8"; + + private static final char[] hexArray = "0123456789ABCDEF".toCharArray(); + + public static void main(String[] args) { + try { + System.out.println("Type 3 : " + generateType3UUID(NAMESPACE_DNS, "google.com")); + System.out.println("Type 4 : " + generateType4UUID()); + System.out.println("Type 5 : " + generateType5UUID(NAMESPACE_URL, "google.com")); + System.out.println("Unique key : " + generateUniqueKeysWithUUIDAndMessageDigest()); + } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) { + e.printStackTrace(); + } + } + + /** + * Type 4 UUID Generation + */ + public static UUID generateType4UUID() { + UUID uuid = UUID.randomUUID(); + return uuid; + } + + /** + * Type 3 UUID Generation + * + * @throws UnsupportedEncodingException + */ + public static UUID generateType3UUID(String namespace, String name) throws UnsupportedEncodingException { + String source = namespace + name; + byte[] bytes = source.getBytes("UTF-8"); + UUID uuid = UUID.nameUUIDFromBytes(bytes); + return uuid; + } + + /** + * Type 5 UUID Generation + * + * @throws UnsupportedEncodingException + */ + public static UUID generateType5UUID(String namespace, String name) throws UnsupportedEncodingException { + String source = namespace + name; + byte[] bytes = source.getBytes("UTF-8"); + UUID uuid = type5UUIDFromBytes(bytes); + return uuid; + } + + + public static UUID type5UUIDFromBytes(byte[] name) { + MessageDigest md; + try { + md = MessageDigest.getInstance("SHA-1"); + } catch (NoSuchAlgorithmException nsae) { + throw new InternalError("MD5 not supported", nsae); + } + byte[] bytes = md.digest(name); + bytes[6] &= 0x0f; /* clear version */ + bytes[6] |= 0x50; /* set to version 5 */ + bytes[8] &= 0x3f; /* clear variant */ + bytes[8] |= 0x80; /* set to IETF variant */ + return constructType5UUID(bytes); + } + + private static UUID constructType5UUID(byte[] data) { + long msb = 0; + long lsb = 0; + assert data.length == 16 : "data must be 16 bytes in length"; + + for (int i=0; i<8; i++) + msb = (msb << 8) | (data[i] & 0xff); + + for (int i=8; i<16; i++) + lsb = (lsb << 8) | (data[i] & 0xff); + return new UUID(msb, lsb); + } + + + /** + * Unique Keys Generation Using Message Digest and Type 4 UUID + * + * @throws NoSuchAlgorithmException + * @throws UnsupportedEncodingException + */ + public static String generateUniqueKeysWithUUIDAndMessageDigest() throws NoSuchAlgorithmException, UnsupportedEncodingException { + MessageDigest salt = MessageDigest.getInstance("SHA-256"); + salt.update(UUID.randomUUID() + .toString() + .getBytes("UTF-8")); + String digest = bytesToHex(salt.digest()); + return digest; + } + + public static String bytesToHex(byte[] bytes) { + char[] hexChars = new char[bytes.length * 2]; + for (int j = 0; j < bytes.length; j++) { + int v = bytes[j] & 0xFF; + hexChars[j * 2] = hexArray[v >>> 4]; + hexChars[j * 2 + 1] = hexArray[v & 0x0F]; + } + return new String(hexChars); + } + +} diff --git a/core-java/src/test/java/com/baeldung/classnotfoundexception/ClassNotFoundExceptionTest.java b/core-java/src/test/java/com/baeldung/classnotfoundexception/ClassNotFoundExceptionTest.java new file mode 100644 index 0000000000..a6104e635b --- /dev/null +++ b/core-java/src/test/java/com/baeldung/classnotfoundexception/ClassNotFoundExceptionTest.java @@ -0,0 +1,11 @@ +package com.baeldung.classnotfoundexception; + +import org.junit.Test; + +public class ClassNotFoundExceptionTest { + + @Test(expected = ClassNotFoundException.class) + public void givenNoDriversInClassPath_whenLoadDrivers_thenClassNotFoundException() throws ClassNotFoundException { + Class.forName("oracle.jdbc.driver.OracleDriver"); + } +} diff --git a/core-java/src/test/java/com/baeldung/noclassdeffounderror/NoClassDefFoundErrorTest.java b/core-java/src/test/java/com/baeldung/noclassdeffounderror/NoClassDefFoundErrorTest.java new file mode 100644 index 0000000000..bb446dc385 --- /dev/null +++ b/core-java/src/test/java/com/baeldung/noclassdeffounderror/NoClassDefFoundErrorTest.java @@ -0,0 +1,12 @@ +package com.baeldung.noclassdeffounderror; + +import org.junit.Test; + +public class NoClassDefFoundErrorTest { + + @Test(expected = NoClassDefFoundError.class) + public void givenInitErrorInClass_whenloadClass_thenNoClassDefFoundError() { + NoClassDefFoundErrorExample sample = new NoClassDefFoundErrorExample(); + sample.getClassWithInitErrors(); + } +} diff --git a/core-java/src/test/java/com/baeldung/regexp/EscapingCharsTest.java b/core-java/src/test/java/com/baeldung/regexp/EscapingCharsTest.java new file mode 100644 index 0000000000..f8dbde4c4f --- /dev/null +++ b/core-java/src/test/java/com/baeldung/regexp/EscapingCharsTest.java @@ -0,0 +1,71 @@ +package com.baeldung.regexp; + +import static junit.framework.TestCase.assertEquals; +import static org.junit.Assert.assertThat; +import static org.hamcrest.CoreMatchers.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.junit.Test; + +public class EscapingCharsTest { + @Test + public void givenRegexWithDot_whenMatchingStr_thenMatches() { + String strInput = "foof"; + String strRegex = "foo."; + + assertEquals(true, strInput.matches(strRegex)); + } + + @Test + public void givenRegexWithDotEsc_whenMatchingStr_thenNotMatching() { + String strInput = "foof"; + String strRegex = "foo\\."; + + assertEquals(false, strInput.matches(strRegex)); + } + + @Test + public void givenRegexWithPipeEscaped_whenSplitStr_thenSplits() { + String strInput = "foo|bar|hello|world"; + String strRegex = "\\Q|\\E"; + + assertEquals(4, strInput.split(strRegex).length); + } + + @Test + public void givenRegexWithPipeEscQuoteMeth_whenSplitStr_thenSplits() { + String strInput = "foo|bar|hello|world"; + String strRegex = "|"; + + assertEquals(4,strInput.split(Pattern.quote(strRegex)).length); + } + + @Test + public void givenRegexWithDollar_whenReplacing_thenNotReplace() { + String strInput = "I gave $50 to my brother." + + "He bought candy for $35. Now he has $15 left."; + String strRegex = "$"; + String strReplacement = "£"; + String output = "I gave £50 to my brother." + + "He bought candy for £35. Now he has £15 left."; + Pattern p = Pattern.compile(strRegex); + Matcher m = p.matcher(strInput); + + assertThat(output, not(equalTo(m.replaceAll(strReplacement)))); + } + + @Test + public void givenRegexWithDollarEsc_whenReplacing_thenReplace() { + String strInput = "I gave $50 to my brother." + + "He bought candy for $35. Now he has $15 left."; + String strRegex = "\\$"; + String strReplacement = "£"; + String output = "I gave £50 to my brother." + + "He bought candy for £35. Now he has £15 left."; + Pattern p = Pattern.compile(strRegex); + Matcher m = p.matcher(strInput); + + assertEquals(output,m.replaceAll(strReplacement)); + } +} diff --git a/core-java/src/test/java/com/baeldung/stream/StreamAddUnitTest.java b/core-java/src/test/java/com/baeldung/stream/StreamAddUnitTest.java new file mode 100644 index 0000000000..8176d6a60c --- /dev/null +++ b/core-java/src/test/java/com/baeldung/stream/StreamAddUnitTest.java @@ -0,0 +1,46 @@ +package com.baeldung.stream; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import static org.junit.Assert.assertEquals; +import org.junit.Test; + +public class StreamAddUnitTest { + + @Test + public void givenStream_whenAppendingObject_thenAppended() { + Stream anStream = Stream.of("a", "b", "c", "d", "e"); + + Stream newStream = Stream.concat(anStream, Stream.of("A")); + + List resultList = newStream.collect(Collectors.toList()); + assertEquals(resultList.get(resultList.size() - 1), "A"); + } + + @Test + public void givenStream_whenPrependingObject_thenPrepended() { + Stream anStream = Stream.of(1, 2, 3, 4, 5); + + Stream newStream = Stream.concat(Stream.of(99), anStream); + + assertEquals(newStream.findFirst() + .get(), (Integer) 99); + } + + @Test + public void givenStream_whenInsertingObject_thenInserted() { + Stream anStream = Stream.of(1.1, 2.2, 3.3); + + Stream newStream = insertInStream(anStream, 9.9, 3); + + List resultList = newStream.collect(Collectors.toList()); + assertEquals(resultList.get(3), (Double) 9.9); + } + + public Stream insertInStream(Stream stream, T elem, int index) { + List result = stream.collect(Collectors.toList()); + result.add(index, elem); + return result.stream(); + } +} diff --git a/core-java/src/test/java/com/baeldung/stream/StreamApiTest.java b/core-java/src/test/java/com/baeldung/stream/StreamApiTest.java new file mode 100644 index 0000000000..af52b3ee69 --- /dev/null +++ b/core-java/src/test/java/com/baeldung/stream/StreamApiTest.java @@ -0,0 +1,43 @@ +package com.baeldung.stream; + +import static org.junit.Assert.assertEquals; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Test; + +public class StreamApiTest { + private StreamApi streamApi = new StreamApi(); + + @Test + public void givenList_whenGetLastElementUsingReduce_thenReturnLastElement() { + List valueList = new ArrayList(); + valueList.add("Joe"); + valueList.add("John"); + valueList.add("Sean"); + + String last = streamApi.getLastElementUsingReduce(valueList); + + assertEquals("Sean", last); + } + + @Test + public void givenInfiniteStream_whenGetInfiniteStreamLastElementUsingReduce_thenReturnLastElement() { + Integer last = streamApi.getInfiniteStreamLastElementUsingReduce(); + assertEquals(new Integer(19), last); + } + + @Test + public void givenListAndCount_whenGetLastElementUsingSkip_thenReturnLastElement() { + List valueList = new ArrayList(); + valueList.add("Joe"); + valueList.add("John"); + valueList.add("Sean"); + + String last = streamApi.getLastElementUsingSkip(valueList); + + assertEquals("Sean", last); + } + +} diff --git a/core-java/src/test/java/org/baeldung/java/JavaRandomUnitTest.java b/core-java/src/test/java/org/baeldung/java/JavaRandomUnitTest.java index f058e5d862..a11659547e 100644 --- a/core-java/src/test/java/org/baeldung/java/JavaRandomUnitTest.java +++ b/core-java/src/test/java/org/baeldung/java/JavaRandomUnitTest.java @@ -167,9 +167,11 @@ public class JavaRandomUnitTest { final int leftLimit = 97; // letter 'a' final int rightLimit = 122; // letter 'z' final int targetStringLength = 10; + final Random random = new Random(); final StringBuilder buffer = new StringBuilder(targetStringLength); + for (int i = 0; i < targetStringLength; i++) { - final int randomLimitedInt = leftLimit + (int) (new Random().nextFloat() * (rightLimit - leftLimit + 1)); + final int randomLimitedInt = leftLimit + (int) (random.nextFloat() * (rightLimit - leftLimit + 1)); buffer.append((char) randomLimitedInt); } final String generatedString = buffer.toString(); diff --git a/ejb/ejb-session-beans/pom.xml b/ejb/ejb-session-beans/pom.xml new file mode 100644 index 0000000000..a9b667baac --- /dev/null +++ b/ejb/ejb-session-beans/pom.xml @@ -0,0 +1,106 @@ + + 4.0.0 + + com.baeldung.ejb + ejb + 1.0-SNAPSHOT + + ejb-session-beans + + + UTF-8 + 1.1.12.Final + 2.2.6 + 1.1.12.Final + 1.0.0.Final + 4.12 + 7.0 + + + + + + org.jboss.arquillian + arquillian-bom + 1.1.13.Final + import + pom + + + + + + + + javax + javaee-api + ${javaee-api.version} + provided + + + + + junit + junit + 4.12 + test + + + + + org.jboss.arquillian.junit + arquillian-junit-container + test + + + + + + + arquillian-glassfish-embedded + + true + + + + org.jboss.arquillian.container + arquillian-glassfish-embedded-3.1 + 1.0.0.CR4 + test + + + org.glassfish.main.extras + glassfish-embedded-all + 3.1.2 + test + + + + + + + + + maven-compiler-plugin + 3.1 + + 1.8 + 1.8 + + + + maven-war-plugin + 2.4 + + false + + + + maven-surefire-plugin + 2.17 + + + + + + \ No newline at end of file diff --git a/ejb/ejb-session-beans/src/main/java/com/baeldung/ejb/stateful/EJBClient1.java b/ejb/ejb-session-beans/src/main/java/com/baeldung/ejb/stateful/EJBClient1.java new file mode 100644 index 0000000000..0387beeb3c --- /dev/null +++ b/ejb/ejb-session-beans/src/main/java/com/baeldung/ejb/stateful/EJBClient1.java @@ -0,0 +1,11 @@ +package com.baeldung.ejb.stateful; + +import javax.ejb.EJB; + +public class EJBClient1 { + + @EJB + public StatefulEJB statefulEJB; + + +} \ No newline at end of file diff --git a/ejb/ejb-session-beans/src/main/java/com/baeldung/ejb/stateful/EJBClient2.java b/ejb/ejb-session-beans/src/main/java/com/baeldung/ejb/stateful/EJBClient2.java new file mode 100644 index 0000000000..54f88a993d --- /dev/null +++ b/ejb/ejb-session-beans/src/main/java/com/baeldung/ejb/stateful/EJBClient2.java @@ -0,0 +1,11 @@ +package com.baeldung.ejb.stateful; + +import javax.ejb.EJB; + +public class EJBClient2 { + + @EJB + public StatefulEJB statefulEJB; + + +} \ No newline at end of file diff --git a/ejb/ejb-session-beans/src/main/java/com/baeldung/ejb/stateful/StatefulEJB.java b/ejb/ejb-session-beans/src/main/java/com/baeldung/ejb/stateful/StatefulEJB.java new file mode 100644 index 0000000000..17bb08491a --- /dev/null +++ b/ejb/ejb-session-beans/src/main/java/com/baeldung/ejb/stateful/StatefulEJB.java @@ -0,0 +1,10 @@ +package com.baeldung.ejb.stateful; + +import javax.ejb.Stateful; + +@Stateful +public class StatefulEJB { + + public String name; + +} \ No newline at end of file diff --git a/ejb/ejb-session-beans/src/main/java/com/baeldung/ejb/stateless/EJBClient1.java b/ejb/ejb-session-beans/src/main/java/com/baeldung/ejb/stateless/EJBClient1.java new file mode 100644 index 0000000000..0d6f06449b --- /dev/null +++ b/ejb/ejb-session-beans/src/main/java/com/baeldung/ejb/stateless/EJBClient1.java @@ -0,0 +1,10 @@ +package com.baeldung.ejb.stateless; + +import javax.ejb.EJB; + +public class EJBClient1 { + + @EJB + public StatelessEJB statelessEJB; + +} \ No newline at end of file diff --git a/ejb/ejb-session-beans/src/main/java/com/baeldung/ejb/stateless/EJBClient2.java b/ejb/ejb-session-beans/src/main/java/com/baeldung/ejb/stateless/EJBClient2.java new file mode 100644 index 0000000000..a7fe650b1b --- /dev/null +++ b/ejb/ejb-session-beans/src/main/java/com/baeldung/ejb/stateless/EJBClient2.java @@ -0,0 +1,11 @@ +package com.baeldung.ejb.stateless; + +import javax.ejb.EJB; + +public class EJBClient2 { + + @EJB + public StatelessEJB statelessEJB; + + +} \ No newline at end of file diff --git a/ejb/ejb-session-beans/src/main/java/com/baeldung/ejb/stateless/StatelessEJB.java b/ejb/ejb-session-beans/src/main/java/com/baeldung/ejb/stateless/StatelessEJB.java new file mode 100644 index 0000000000..d4e9749252 --- /dev/null +++ b/ejb/ejb-session-beans/src/main/java/com/baeldung/ejb/stateless/StatelessEJB.java @@ -0,0 +1,11 @@ +package com.baeldung.ejb.stateless; + +import javax.ejb.Stateless; + + +@Stateless +public class StatelessEJB { + + public String name; + +} \ No newline at end of file diff --git a/ejb/ejb-session-beans/src/test/java/com/baeldung/ejb/test/stateful/StatefulEJBTest.java b/ejb/ejb-session-beans/src/test/java/com/baeldung/ejb/test/stateful/StatefulEJBTest.java new file mode 100644 index 0000000000..2f3e45a769 --- /dev/null +++ b/ejb/ejb-session-beans/src/test/java/com/baeldung/ejb/test/stateful/StatefulEJBTest.java @@ -0,0 +1,51 @@ +package com.baeldung.ejb.test.stateful; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.asset.EmptyAsset; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.baeldung.ejb.stateful.EJBClient1; +import com.baeldung.ejb.stateful.EJBClient2; +import com.baeldung.ejb.stateful.StatefulEJB; + +import javax.inject.Inject; + + +@RunWith(Arquillian.class) +public class StatefulEJBTest { + + @Inject + private EJBClient1 ejbClient1; + + @Inject + private EJBClient2 ejbClient2; + + @Test + public void givenOneStatefulBean_whenTwoClientsSetValueOnBean_thenClientStateIsMaintained() { + + // act + ejbClient1.statefulEJB.name = "Client 1"; + ejbClient2.statefulEJB.name = "Client 2"; + + // assert + Assert.assertNotEquals(ejbClient1.statefulEJB.name, ejbClient2.statefulEJB.name); + Assert.assertEquals("Client 1", ejbClient1.statefulEJB.name); + Assert.assertEquals("Client 2", ejbClient2.statefulEJB.name); + + } + + @Deployment + public static JavaArchive createDeployment() { + return ShrinkWrap.create(JavaArchive.class) + .addClass(StatefulEJB.class) + .addClass(EJBClient1.class) + .addClass(EJBClient2.class) + .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml"); + } + +} diff --git a/ejb/ejb-session-beans/src/test/java/com/baeldung/ejb/test/stateless/StatelessEJBTest.java b/ejb/ejb-session-beans/src/test/java/com/baeldung/ejb/test/stateless/StatelessEJBTest.java new file mode 100644 index 0000000000..9f88d478b7 --- /dev/null +++ b/ejb/ejb-session-beans/src/test/java/com/baeldung/ejb/test/stateless/StatelessEJBTest.java @@ -0,0 +1,62 @@ +package com.baeldung.ejb.test.stateless; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.asset.EmptyAsset; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.baeldung.ejb.stateless.EJBClient1; +import com.baeldung.ejb.stateless.EJBClient2; +import com.baeldung.ejb.stateless.StatelessEJB; + +import javax.inject.Inject; + + +@RunWith(Arquillian.class) +public class StatelessEJBTest { + + @Inject + private EJBClient1 ejbClient1; + + @Inject + private EJBClient2 ejbClient2; + + @Test + public void givenOneStatelessBean_whenStateIsSetInOneBean_secondBeanShouldHaveSameState() { + + // act + ejbClient1.statelessEJB.name = "Client 1"; + + // assert + Assert.assertEquals("Client 1", ejbClient1.statelessEJB.name); + Assert.assertEquals("Client 1", ejbClient2.statelessEJB.name); + + } + + + @Test + public void givenOneStatelessBean_whenStateIsSetInBothBeans_secondBeanShouldHaveSecondBeanState() { + + // act + ejbClient1.statelessEJB.name = "Client 1"; + ejbClient2.statelessEJB.name = "Client 2"; + + // assert + Assert.assertEquals("Client 2", ejbClient2.statelessEJB.name); + + } + + @Deployment + public static JavaArchive createDeployment() { + return ShrinkWrap.create(JavaArchive.class) + .addClass(StatelessEJB.class) + .addClass(EJBClient1.class) + .addClass(EJBClient2.class) + .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml"); + } + +} diff --git a/ejb/pom.xml b/ejb/pom.xml index 9495020266..b8aa32fab1 100755 --- a/ejb/pom.xml +++ b/ejb/pom.xml @@ -40,7 +40,12 @@ 1.0-SNAPSHOT ejb - + + com.baeldung.ejb + ejb-session-beans + 1.0-SNAPSHOT + ejb + javax javaee-api @@ -75,5 +80,7 @@ ejb-remote ejb-client + ejb-session-beans + ejb-session-beans-client \ No newline at end of file diff --git a/guava21/README.md b/guava21/README.md index 8725352d69..2a54416e41 100644 --- a/guava21/README.md +++ b/guava21/README.md @@ -1,2 +1,3 @@ ### Relevant articles: - [New Stream, Comparator and Collector Functionality in Guava 21](http://www.baeldung.com/guava-21-new) +- [New in Guava 21 common.util.concurrent](http://www.baeldung.com/guava-21-util-concurrent) diff --git a/guest/log4j2-example/.gitignore b/guest/log4j2-example/.gitignore new file mode 100644 index 0000000000..60be5b80aa --- /dev/null +++ b/guest/log4j2-example/.gitignore @@ -0,0 +1,4 @@ +/target/ +.settings/ +.classpath +.project diff --git a/guest/log4j2-example/java.log b/guest/log4j2-example/java.log new file mode 100644 index 0000000000..21e964d9ce --- /dev/null +++ b/guest/log4j2-example/java.log @@ -0,0 +1,3 @@ +14:00:35.258 INFO Programmatic Logger Message +14:03:51.178 INFO Programmatic Logger Message +14:04:11.753 INFO Programmatic Logger Message diff --git a/guest/log4j2-example/logs/app.log b/guest/log4j2-example/logs/app.log new file mode 100644 index 0000000000..022f6fcea9 --- /dev/null +++ b/guest/log4j2-example/logs/app.log @@ -0,0 +1,25 @@ +[ +{ + "timeMillis" : 1496315051753, + "thread" : "main", + "level" : "INFO", + "loggerName" : "RollingFileLogger", + "message" : "Json Message 1", + "endOfBatch" : false, + "loggerFqcn" : "org.apache.logging.log4j.spi.AbstractLogger", + "threadId" : 1, + "threadPriority" : 5 +} +, { + "timeMillis" : 1496315051862, + "thread" : "main", + "level" : "INFO", + "loggerName" : "RollingFileLogger", + "message" : "Json Messag 2", + "endOfBatch" : false, + "loggerFqcn" : "org.apache.logging.log4j.spi.AbstractLogger", + "threadId" : 1, + "threadPriority" : 5 +} + +] diff --git a/guest/log4j2-example/pom.xml b/guest/log4j2-example/pom.xml new file mode 100644 index 0000000000..197f3df2b9 --- /dev/null +++ b/guest/log4j2-example/pom.xml @@ -0,0 +1,56 @@ + + 4.0.0 + log4j2-example + log4j2-example + 0.0.1-SNAPSHOT + + + + + org.apache.logging.log4j + log4j-core + ${log4j-core.version} + + + + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} + + + + junit + junit + 4.12 + + + + + + + src/main/resources/ + + **/*.java + + + + + + maven-compiler-plugin + 3.5 + + 1.8 + 1.8 + + + + + + + 2.8.8.1 + 2.8.2 + + + \ No newline at end of file diff --git a/guest/log4j2-example/src/main/java/com/stackify/models/User.java b/guest/log4j2-example/src/main/java/com/stackify/models/User.java new file mode 100644 index 0000000000..1a53651292 --- /dev/null +++ b/guest/log4j2-example/src/main/java/com/stackify/models/User.java @@ -0,0 +1,43 @@ +package com.stackify.models; + +import java.time.LocalDate; + +public class User { + private String name; + private String email; + private LocalDate dateOfBirth; + + public User() { + } + + public User(String name, String email) { + super(); + this.name = name; + this.email = email; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public LocalDate getDateOfBirth() { + return dateOfBirth; + } + + public void setDateOfBirth(LocalDate dateOfBirth) { + this.dateOfBirth = dateOfBirth; + } + +} diff --git a/guest/log4j2-example/src/main/java/com/stackify/services/MyService.java b/guest/log4j2-example/src/main/java/com/stackify/services/MyService.java new file mode 100644 index 0000000000..4b1dc0bf34 --- /dev/null +++ b/guest/log4j2-example/src/main/java/com/stackify/services/MyService.java @@ -0,0 +1,14 @@ +package com.stackify.services; + +import java.time.LocalDate; +import java.time.Period; + +import com.stackify.models.User; + +public class MyService { + + public int calculateUserAge(User user) { + return Period.between(user.getDateOfBirth(), LocalDate.now()).getYears(); + } + +} diff --git a/guest/log4j2-example/src/main/resources/log4j2.xml b/guest/log4j2-example/src/main/resources/log4j2.xml new file mode 100644 index 0000000000..06f2ba5245 --- /dev/null +++ b/guest/log4j2-example/src/main/resources/log4j2.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/guest/log4j2-example/src/test/java/com/stackify/services/MyServiceTest.java b/guest/log4j2-example/src/test/java/com/stackify/services/MyServiceTest.java new file mode 100644 index 0000000000..49e367e45b --- /dev/null +++ b/guest/log4j2-example/src/test/java/com/stackify/services/MyServiceTest.java @@ -0,0 +1,81 @@ +package com.stackify.services; + +import java.time.LocalDate; +import java.time.Month; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.Appender; +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.appender.FileAppender; +import org.apache.logging.log4j.core.config.AppenderRef; +import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.config.LoggerConfig; +import org.apache.logging.log4j.core.layout.PatternLayout; +import org.junit.Test; + +import com.stackify.models.User; +import com.stackify.services.MyService; + +public class MyServiceTest { + + private static final Logger logger = LogManager.getLogger(MyServiceTest.class); + + @Test + public void testService() { + MyService myService = new MyService(); + User user = new User("John", "john@yahoo.com"); + user.setDateOfBirth(LocalDate.of(1980, Month.APRIL, 20)); + logger.info("Age of user {} is {}", () -> user.getName(), () -> myService.calculateUserAge(user)); + } + + @Test + public void testColoredLogger() { + logger.fatal("Fatal level message"); + logger.error("Error level message"); + logger.warn("Warn level message"); + logger.info("Info level message"); + logger.debug("Debug level message"); + } + + @Test + public void testRollingFileAppender() { + Logger rfLogger = LogManager.getLogger("RollingFileLogger"); + rfLogger.info("Json Message 1"); + rfLogger.info("Json Message 2"); + } + + @Test + public void testProgrammaticConfig() { + LoggerContext ctx = (LoggerContext) LogManager.getContext(false); + Configuration config = ctx.getConfiguration(); + + PatternLayout layout = PatternLayout.newBuilder().withConfiguration(config).withPattern("%d{HH:mm:ss.SSS} %level %msg%n").build(); + + Appender appender = FileAppender.newBuilder().setConfiguration(config).withName("programmaticFileAppender").withLayout(layout).withFileName("java.log").build(); + appender.start(); + config.addAppender(appender); + AppenderRef ref = AppenderRef.createAppenderRef("programmaticFileAppender", null, null); + AppenderRef[] refs = new AppenderRef[] { ref }; + + LoggerConfig loggerConfig = LoggerConfig.createLogger(false, Level.INFO, "programmaticLogger", "true", refs, null, config, null); + + loggerConfig.addAppender(appender, null, null); + config.addLogger("programmaticLogger", loggerConfig); + ctx.updateLoggers(); + + Logger pLogger = LogManager.getLogger("programmaticLogger"); + pLogger.info("Programmatic Logger Message"); + } + + @Test + public void testCustomLevel() { + Level myLevel = Level.forName("NEW_LEVEL", 350); + logger.log(myLevel, "Custom Level Message"); + + logger.log(Level.getLevel("NEW_XML_LEVEL"), "Custom XML Level Message"); + + } + +} diff --git a/hibernate5/pom.xml b/hibernate5/pom.xml index 63e0799281..c501b7f11d 100644 --- a/hibernate5/pom.xml +++ b/hibernate5/pom.xml @@ -15,6 +15,8 @@ http://maven.apache.org UTF-8 + + 3.6.0 @@ -22,6 +24,11 @@ hibernate-core 5.2.9.Final + + junit + junit + 4.12 + com.h2database h2 @@ -37,6 +44,32 @@ + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + 1.8 + 1.8 + + + + + org.apache.maven.plugins + maven-surefire-plugin + + 3 + true + + **/*IntegrationTest.java + **/*LiveTest.java + + + + + + diff --git a/hibernate5/src/main/java/com/baeldung/hibernate/HibernateMultiTenantUtil.java b/hibernate5/src/main/java/com/baeldung/hibernate/HibernateMultiTenantUtil.java index c3e7b621d0..5a10b2ba56 100644 --- a/hibernate5/src/main/java/com/baeldung/hibernate/HibernateMultiTenantUtil.java +++ b/hibernate5/src/main/java/com/baeldung/hibernate/HibernateMultiTenantUtil.java @@ -1,5 +1,9 @@ package com.baeldung.hibernate; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.net.URL; import java.util.HashMap; import java.util.Map; import java.util.Properties; @@ -20,44 +24,56 @@ import com.baeldung.hibernate.pojo.Supplier; public class HibernateMultiTenantUtil { private static SessionFactory sessionFactory; private static Map connectionProviderMap = new HashMap<>(); - private static final String[] tenantDBNames = { "mydb1","mydb2"}; + private static final String[] tenantDBNames = { "mydb1", "mydb2" }; - public static SessionFactory getSessionFactory() throws UnsupportedTenancyException { + public static SessionFactory getSessionFactory() throws UnsupportedTenancyException, IOException { if (sessionFactory == null) { - Configuration configuration = new Configuration().configure(); - ServiceRegistry serviceRegistry = configureServiceRegistry(configuration); - sessionFactory = makeSessionFactory (serviceRegistry); -// sessionFactory = configuration.buildSessionFactory(serviceRegistry); - - + // Configuration configuration = new Configuration().configure(); + ServiceRegistry serviceRegistry = configureServiceRegistry(); + sessionFactory = makeSessionFactory(serviceRegistry); + } return sessionFactory; } private static SessionFactory makeSessionFactory(ServiceRegistry serviceRegistry) { - MetadataSources metadataSources = new MetadataSources( serviceRegistry ); - for(Class annotatedClasses : getAnnotatedClasses()) { - metadataSources.addAnnotatedClass( annotatedClasses ); + MetadataSources metadataSources = new MetadataSources(serviceRegistry); + for (Class annotatedClasses : getAnnotatedClasses()) { + metadataSources.addAnnotatedClass(annotatedClasses); } Metadata metadata = metadataSources.buildMetadata(); - return metadata.getSessionFactoryBuilder().build(); - + return metadata.getSessionFactoryBuilder() + .build(); + } private static Class[] getAnnotatedClasses() { - return new Class[] { - Supplier.class - }; + return new Class[] { Supplier.class }; } - private static ServiceRegistry configureServiceRegistry(Configuration configuration) throws UnsupportedTenancyException { - Properties properties = configuration.getProperties(); + private static ServiceRegistry configureServiceRegistry() throws UnsupportedTenancyException, IOException { + + // Properties properties = configuration.getProperties(); + Properties properties = getProperties(); connectionProviderMap = setUpConnectionProviders(properties, tenantDBNames); properties.put(AvailableSettings.MULTI_TENANT_CONNECTION_PROVIDER, new ConfigurableMultiTenantConnectionProvider(connectionProviderMap)); - return new StandardServiceRegistryBuilder().applySettings(properties).build(); + return new StandardServiceRegistryBuilder().applySettings(properties) + .build(); + } + + private static Properties getProperties() throws IOException { + Properties properties = new Properties(); + URL propertiesURL = Thread.currentThread() + .getContextClassLoader() + .getResource("hibernate.properties"); + FileInputStream inputStream = new FileInputStream(propertiesURL.getFile()); + properties.load(inputStream); + System.out.println("LOADED PROPERTIES FROM hibernate.properties"); + + return properties; } private static Map setUpConnectionProviders(Properties properties, String[] tenantNames) throws UnsupportedTenancyException { @@ -66,23 +82,27 @@ public class HibernateMultiTenantUtil { DriverManagerConnectionProviderImpl connectionProvider = new DriverManagerConnectionProviderImpl(); String tenantStrategy = properties.getProperty("hibernate.multiTenancy"); - System.out.println("Strategy:"+tenantStrategy); + System.out.println("Strategy:" + tenantStrategy); properties.put(Environment.URL, tenantUrl(properties.getProperty(Environment.URL), tenant, tenantStrategy)); - System.out.println("URL:"+properties.getProperty(Environment.URL)); + System.out.println("URL:" + properties.getProperty(Environment.URL)); connectionProvider.configure(properties); - System.out.println("Tenant:"+tenant); + System.out.println("Tenant:" + tenant); providerMap.put(tenant, connectionProvider); - + } System.out.println("Added connections for:"); - providerMap.keySet().stream().forEach(System.out::println); + providerMap.keySet() + .stream() + .forEach(System.out::println); return providerMap; } private static Object tenantUrl(String originalUrl, String tenant, String tenantStrategy) throws UnsupportedTenancyException { - if (tenantStrategy.toUpperCase().equals("DATABASE")) { + if (tenantStrategy.toUpperCase() + .equals("DATABASE")) { return originalUrl.replace(DEFAULT_DB_NAME, tenant); - } else if (tenantStrategy.toUpperCase().equals("SCHEMA")) { + } else if (tenantStrategy.toUpperCase() + .equals("SCHEMA")) { return originalUrl + String.format(SCHEMA_TOKEN, tenant); } else { throw new UnsupportedTenancyException("Not yet supported"); diff --git a/hibernate5/src/main/resources/hibernate.cfg.xml b/hibernate5/src/main/resources/hibernate.cfg.xml deleted file mode 100644 index 26be05f931..0000000000 --- a/hibernate5/src/main/resources/hibernate.cfg.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - org.h2.Driver - jdbc:h2:mem:mydb1;DB_CLOSE_DELAY=-1 - sa - - org.hibernate.dialect.H2Dialect - DATABASE - - diff --git a/hibernate5/src/main/resources/hibernate.properties b/hibernate5/src/main/resources/hibernate.properties new file mode 100644 index 0000000000..a8f927a280 --- /dev/null +++ b/hibernate5/src/main/resources/hibernate.properties @@ -0,0 +1,8 @@ +hibernate.connection.driver_class=org.h2.Driver +hibernate.connection.url=jdbc:h2:mem:mydb1;DB_CLOSE_DELAY=-1 +hibernate.connection.username=sa +jdbc.password= + +hibernate.dialect=org.hibernate.dialect.H2Dialect +hibernate.show_sql=true +hibernate.multiTenancy=DATABASE diff --git a/hibernate5/src/test/java/com/baeldung/hibernate/MultiTenantHibernateIntegrationTest.java b/hibernate5/src/test/java/com/baeldung/hibernate/MultiTenantHibernateIntegrationTest.java index 8f2e88ac3d..610617cb8d 100644 --- a/hibernate5/src/test/java/com/baeldung/hibernate/MultiTenantHibernateIntegrationTest.java +++ b/hibernate5/src/test/java/com/baeldung/hibernate/MultiTenantHibernateIntegrationTest.java @@ -1,65 +1,71 @@ package com.baeldung.hibernate; -import com.baeldung.hibernate.pojo.Supplier; -import org.hibernate.Session; -import org.hibernate.SessionFactory; -import org.hibernate.Transaction; -import org.junit.Test; import static org.junit.Assert.assertNotEquals; +import java.io.IOException; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.sql.Statement; + +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.hibernate.Transaction; +import org.junit.Before; +import org.junit.Test; + +import com.baeldung.hibernate.pojo.Supplier; public class MultiTenantHibernateIntegrationTest { @Test - public void givenDBMode_whenFetchingSuppliers_thenComparingFromDbs () { - SessionFactory sessionFactory; - try { - sessionFactory = HibernateMultiTenantUtil.getSessionFactory(); - - Session db1Session = sessionFactory - .withOptions().tenantIdentifier("mydb1").openSession(); - - initDb1(db1Session); - - Transaction transaction = db1Session.getTransaction(); - transaction.begin(); - Supplier supplierFromDB1 = (Supplier)db1Session.createCriteria(Supplier.class).list().get(0); - transaction.commit(); - - Session db2Session = sessionFactory - .withOptions().tenantIdentifier("mydb2").openSession(); - - initDb2(db2Session); - db2Session.getTransaction().begin(); - Supplier supplierFromDB2 = (Supplier) db2Session.createCriteria(Supplier.class).list().get(0); - db2Session.getTransaction().commit(); - - System.out.println(supplierFromDB1); - System.out.println(supplierFromDB2); - - assertNotEquals(supplierFromDB1, supplierFromDB2); - } catch (UnsupportedTenancyException e) { - e.printStackTrace(); - } + public void givenDBMode_whenFetchingSuppliers_thenComparingFromDbs() throws UnsupportedTenancyException, IOException { + SessionFactory sessionFactory = HibernateMultiTenantUtil.getSessionFactory(); + + Session db1Session = sessionFactory.withOptions().tenantIdentifier("mydb1").openSession(); + + initDb1(db1Session); + + Transaction transaction = db1Session.getTransaction(); + transaction.begin(); + Supplier supplierFromDB1 = (Supplier) db1Session.createCriteria(Supplier.class).list().get(0); + transaction.commit(); + + Session db2Session = sessionFactory.withOptions().tenantIdentifier("mydb2").openSession(); + + initDb2(db2Session); + db2Session.getTransaction().begin(); + Supplier supplierFromDB2 = (Supplier) db2Session.createCriteria(Supplier.class).list().get(0); + db2Session.getTransaction().commit(); + + System.out.println(supplierFromDB1); + System.out.println(supplierFromDB2); + + assertNotEquals(supplierFromDB1, supplierFromDB2); + } - - private void initDb1(Session db1Session) { System.out.println("Init DB1"); Transaction transaction = db1Session.getTransaction(); transaction.begin(); db1Session.createSQLQuery("DROP ALL OBJECTS").executeUpdate(); - db1Session.createSQLQuery("create table Supplier (id integer generated by default as identity, country varchar(255), name varchar(255), primary key (id))").executeUpdate(); + db1Session + .createSQLQuery( + "create table Supplier (id integer generated by default as identity, country varchar(255), name varchar(255), primary key (id))") + .executeUpdate(); db1Session.createSQLQuery("insert into Supplier (id, country, name) values (null, 'John', 'USA')").executeUpdate(); transaction.commit(); } - + private void initDb2(Session db2Session) { System.out.println("Init DB2"); Transaction transaction = db2Session.getTransaction(); transaction.begin(); db2Session.createSQLQuery("DROP ALL OBJECTS").executeUpdate(); - db2Session.createSQLQuery("create table Supplier (id integer generated by default as identity, country varchar(255), name varchar(255), primary key (id))").executeUpdate(); + db2Session + .createSQLQuery( + "create table Supplier (id integer generated by default as identity, country varchar(255), name varchar(255), primary key (id))") + .executeUpdate(); db2Session.createSQLQuery("insert into Supplier (id, country, name) values (null, 'Miller', 'UK')").executeUpdate(); transaction.commit(); } diff --git a/hibernate5/src/test/java/hibernate.properties b/hibernate5/src/test/java/hibernate.properties new file mode 100644 index 0000000000..a8f927a280 --- /dev/null +++ b/hibernate5/src/test/java/hibernate.properties @@ -0,0 +1,8 @@ +hibernate.connection.driver_class=org.h2.Driver +hibernate.connection.url=jdbc:h2:mem:mydb1;DB_CLOSE_DELAY=-1 +hibernate.connection.username=sa +jdbc.password= + +hibernate.dialect=org.hibernate.dialect.H2Dialect +hibernate.show_sql=true +hibernate.multiTenancy=DATABASE diff --git a/image-processing/pom.xml b/image-processing/pom.xml index ccb3238a7e..2e4063964e 100644 --- a/image-processing/pom.xml +++ b/image-processing/pom.xml @@ -40,6 +40,16 @@ commons-logging + + + com.twelvemonkeys.imageio + imageio-core + 3.3.2 + + + com.twelvemonkeys.imageio + imageio-bmp + 3.3.2 diff --git a/image-processing/src/main/java/com/baeldung/imageprocessing/twelvemonkeys/TwelveMonkeysExample.java b/image-processing/src/main/java/com/baeldung/imageprocessing/twelvemonkeys/TwelveMonkeysExample.java new file mode 100644 index 0000000000..78c7b6a99b --- /dev/null +++ b/image-processing/src/main/java/com/baeldung/imageprocessing/twelvemonkeys/TwelveMonkeysExample.java @@ -0,0 +1,47 @@ +package com.baeldung.imageprocessing.twelvemonkeys; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; + +import javax.imageio.ImageIO; +import javax.swing.ImageIcon; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; + +public class TwelveMonkeysExample { + public static void main(String[] args) throws IOException { + BufferedImage image = loadImage(); + drawRectangle(image); + displayImage(image); + } + + private static BufferedImage loadImage() throws IOException { + String imagePath = TwelveMonkeysExample.class.getClassLoader().getResource("Penguin.ico").getPath(); + return ImageIO.read(new File(imagePath)); + } + + private static void drawRectangle(BufferedImage image) { + Graphics2D g = (Graphics2D) image.getGraphics(); + g.setStroke(new BasicStroke(3)); + g.setColor(Color.BLUE); + g.drawRect(10, 10, image.getWidth() - 20, image.getHeight() - 20); + } + + private static void displayImage(BufferedImage image) { + JLabel picLabel = new JLabel(new ImageIcon(image)); + + JPanel jPanel = new JPanel(); + jPanel.add(picLabel); + + JFrame f = new JFrame(); + f.setSize(new Dimension(200, 200)); + f.add(jPanel); + f.setVisible(true); + } +} diff --git a/image-processing/src/main/resources/Penguin.ico b/image-processing/src/main/resources/Penguin.ico new file mode 100644 index 0000000000..a6df5d71a8 Binary files /dev/null and b/image-processing/src/main/resources/Penguin.ico differ diff --git a/jee7/README.md b/jee7/README.md index fdd260468c..71163d6640 100644 --- a/jee7/README.md +++ b/jee7/README.md @@ -3,3 +3,4 @@ - [JSON Processing in Java EE 7](http://www.baeldung.com/jee7-json) - [Converters, Listeners and Validators in Java EE 7](http://www.baeldung.com/java-ee7-converter-listener-validator) - [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) diff --git a/jee7/pom.xml b/jee7/pom.xml index fe7c5e4c11..e633d2df3d 100644 --- a/jee7/pom.xml +++ b/jee7/pom.xml @@ -1,381 +1,381 @@ - 4.0.0 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 - com.baeldung - jee7 - 1.0-SNAPSHOT - JavaEE 7 Arquillian Archetype Sample + com.baeldung + jee7 + 1.0-SNAPSHOT + JavaEE 7 Arquillian Archetype Sample - - com.baeldung - parent-modules - 1.0.0-SNAPSHOT - + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + - - 1.8 - 3.0.0 + + 1.8 + 3.0.0 - 7.0 - 1.1.11.Final - 8.2.1.Final - 1.7.0 - 1.4.6.Final - 3.0.19.Final - 4.1.1 - 1.0.4 - 1.13 - 2.25 - 1.0.0.Final + 7.0 + 1.1.11.Final + 8.2.1.Final + 1.7.0 + 1.4.6.Final + 3.0.19.Final + 4.1.1 + 1.0.4 + 1.13 + 2.25 + 1.0.0.Final - 2.6 - + 2.6 + - - ${maven.min.version} - + + ${maven.min.version} + - - - - org.jboss.arquillian - arquillian-bom - ${arquillian_core.version} - import - pom - - - org.jboss.arquillian.extension - arquillian-drone-bom - 2.0.1.Final - pom - import - - - + + + + org.jboss.arquillian + arquillian-bom + ${arquillian_core.version} + import + pom + + + org.jboss.arquillian.extension + arquillian-drone-bom + 2.0.1.Final + pom + import + + + - - - javax - javaee-api - ${javaee_api.version} - provided - - - - org.jboss.arquillian.junit - arquillian-junit-container - test - + - org.jboss.arquillian.graphene - graphene-webdriver - 2.1.0.Final - pom - test - - - com.jayway.awaitility - awaitility - ${awaitility.version} - test - + javax + javaee-api + ${javaee_api.version} + provided + - - org.jboss.shrinkwrap.resolver - shrinkwrap-resolver-impl-maven - test - jar - - - - org.jboss.shrinkwrap.resolver - shrinkwrap-resolver-impl-maven-archive - test - - - org.apache.httpcomponents - httpclient - 4.5 - - - commons-io - commons-io - 2.4 - - - com.sun.faces - jsf-api - 2.2.14 - - - com.sun.faces - jsf-impl - 2.2.14 - - - javax.servlet - jstl - 1.2 - - - javax.servlet - javax.servlet-api - 3.1.0 - - javax.servlet.jsp - jsp-api - 2.2 - provided + org.jboss.arquillian.junit + arquillian-junit-container + test - taglibs - standard - 1.1.2 - - + org.jboss.arquillian.graphene + graphene-webdriver + 2.1.0.Final + pom + test + + + com.jayway.awaitility + awaitility + ${awaitility.version} + test + - - - - org.apache.maven.plugins - maven-war-plugin - ${maven-war-plugin.version} - - false - - - - + + org.jboss.shrinkwrap.resolver + shrinkwrap-resolver-impl-maven + test + jar + - + + org.jboss.shrinkwrap.resolver + shrinkwrap-resolver-impl-maven-archive + test + + + org.apache.httpcomponents + httpclient + 4.5 + + + commons-io + commons-io + 2.4 + + + com.sun.faces + jsf-api + 2.2.14 + + + com.sun.faces + jsf-impl + 2.2.14 + + + javax.servlet + jstl + 1.2 + + + javax.servlet + javax.servlet-api + 3.1.0 + + + javax.servlet.jsp + jsp-api + 2.2 + provided + + + taglibs + standard + 1.1.2 + + - - wildfly-managed-arquillian - - true - - - standalone-full.xml - ${project.build.directory}/wildfly-${version.wildfly} - - - - io.undertow - undertow-websockets-jsr - ${undertow-websockets-jsr.version} - test - - - org.jboss.resteasy - resteasy-client - ${resteasy.version} - test - - - org.jboss.resteasy - resteasy-jaxb-provider - ${resteasy.version} - test - - - org.jboss.resteasy - resteasy-json-p-provider - ${resteasy.version} - test - - - org.wildfly - wildfly-arquillian-container-managed - ${wildfly.version} - test - - - - - - - maven-dependency-plugin - 2.8 - - ${maven.test.skip} - - - - unpack - process-test-classes - - unpack - - - - - org.wildfly - wildfly-dist - ${wildfly.version} - zip - false - ${project.build.directory} - - - - - - - - maven-surefire-plugin - 2.17 - - - ${project.build.directory}/wildfly-${wildfly.version} - - - - - - - - - wildfly-remote-arquillian - - - io.undertow - undertow-websockets-jsr - ${undertow-websockets-jsr.version} - test - - - org.jboss.resteasy - resteasy-client - ${resteasy.version} - test - - - org.jboss.resteasy - resteasy-jaxb-provider - ${resteasy.version} - test - - - org.jboss.resteasy - resteasy-json-p-provider - ${resteasy.version} - test - - - org.wildfly - wildfly-arquillian-container-remote - ${wildfly.version} - test - - - - - glassfish-embedded-arquillian - - - org.glassfish.main.extras - glassfish-embedded-all - ${glassfish-embedded-all.version} - test - - - org.glassfish - javax.json - ${javax.json.version} - test - - - org.glassfish.tyrus - tyrus-client - ${tyrus.version} - test - - - org.glassfish.tyrus - tyrus-container-grizzly-client - ${tyrus.version} - test - - - org.glassfish.jersey.core - jersey-client - ${jersey.version} - test - - - org.jboss.arquillian.container - arquillian-glassfish-embedded-3.1 - ${arquillian-glassfish.version} - test - - - - - glassfish-remote-arquillian - - - org.glassfish - javax.json - ${javax.json.version} - test - - - org.glassfish.tyrus - tyrus-client - ${tyrus.version} - test - - - org.glassfish.tyrus - tyrus-container-grizzly-client - ${tyrus.version} - test - - - org.glassfish.jersey.core - jersey-client - ${jersey.version} - test - - - org.glassfish.jersey.media - jersey-media-json-jackson - ${jersey.version} - test - - - org.glassfish.jersey.media - jersey-media-json-processing - ${jersey.version} - test - - - org.jboss.arquillian.container - arquillian-glassfish-remote-3.1 - ${arquillian-glassfish.version} - test - - - - - webdriver-chrome - - true - - - chrome - - + + + + org.apache.maven.plugins + maven-war-plugin + ${maven-war-plugin.version} + + false + + + + - - webdriver-firefox - - firefox - + + + + wildfly-managed-arquillian + + true + + + standalone-full.xml + ${project.build.directory}/wildfly-${version.wildfly} + + + + io.undertow + undertow-websockets-jsr + ${undertow-websockets-jsr.version} + test + + + org.jboss.resteasy + resteasy-client + ${resteasy.version} + test + + + org.jboss.resteasy + resteasy-jaxb-provider + ${resteasy.version} + test + + + org.jboss.resteasy + resteasy-json-p-provider + ${resteasy.version} + test + + + org.wildfly + wildfly-arquillian-container-managed + ${wildfly.version} + test + + + + + + + maven-dependency-plugin + 2.8 + + ${maven.test.skip} + + + + unpack + process-test-classes + + unpack + + + + + org.wildfly + wildfly-dist + ${wildfly.version} + zip + false + ${project.build.directory} + + + + + + + + maven-surefire-plugin + 2.17 + + + ${project.build.directory}/wildfly-${wildfly.version} + + + + + + - + + wildfly-remote-arquillian + + + io.undertow + undertow-websockets-jsr + ${undertow-websockets-jsr.version} + test + + + org.jboss.resteasy + resteasy-client + ${resteasy.version} + test + + + org.jboss.resteasy + resteasy-jaxb-provider + ${resteasy.version} + test + + + org.jboss.resteasy + resteasy-json-p-provider + ${resteasy.version} + test + + + org.wildfly + wildfly-arquillian-container-remote + ${wildfly.version} + test + + + + + glassfish-embedded-arquillian + + + org.glassfish.main.extras + glassfish-embedded-all + ${glassfish-embedded-all.version} + test + + + org.glassfish + javax.json + ${javax.json.version} + test + + + org.glassfish.tyrus + tyrus-client + ${tyrus.version} + test + + + org.glassfish.tyrus + tyrus-container-grizzly-client + ${tyrus.version} + test + + + org.glassfish.jersey.core + jersey-client + ${jersey.version} + test + + + org.jboss.arquillian.container + arquillian-glassfish-embedded-3.1 + ${arquillian-glassfish.version} + test + + + + + glassfish-remote-arquillian + + + org.glassfish + javax.json + ${javax.json.version} + test + + + org.glassfish.tyrus + tyrus-client + ${tyrus.version} + test + + + org.glassfish.tyrus + tyrus-container-grizzly-client + ${tyrus.version} + test + + + org.glassfish.jersey.core + jersey-client + ${jersey.version} + test + + + org.glassfish.jersey.media + jersey-media-json-jackson + ${jersey.version} + test + + + org.glassfish.jersey.media + jersey-media-json-processing + ${jersey.version} + test + + + org.jboss.arquillian.container + arquillian-glassfish-remote-3.1 + ${arquillian-glassfish.version} + test + + + + + webdriver-chrome + + true + + + chrome + + + + + webdriver-firefox + + firefox + + + diff --git a/junit5/src/test/java/com/baeldung/DynamicTestsExample.java b/junit5/src/test/java/com/baeldung/DynamicTestsExample.java index ce1f8b16a7..fd6bb3e0a8 100644 --- a/junit5/src/test/java/com/baeldung/DynamicTestsExample.java +++ b/junit5/src/test/java/com/baeldung/DynamicTestsExample.java @@ -3,7 +3,6 @@ package com.baeldung; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; @@ -18,6 +17,9 @@ import org.junit.jupiter.api.DynamicTest; import org.junit.jupiter.api.TestFactory; import org.junit.jupiter.api.function.ThrowingConsumer; +import com.baeldung.helpers.Employee; +import com.baeldung.helpers.EmployeeDao; + public class DynamicTestsExample { @TestFactory @@ -53,32 +55,12 @@ public class DynamicTestsExample { // sample input and output List inputList = - new ArrayList<>(Arrays.asList("www.somedomain.com", "www.anotherdomain.com", "www.yetanotherdomain.com")); + Arrays.asList("www.somedomain.com", "www.anotherdomain.com", "www.yetanotherdomain.com"); List outputList = - new ArrayList<>(Arrays.asList("154.174.10.56", "211.152.104.132", "178.144.120.156")); + Arrays.asList("154.174.10.56", "211.152.104.132", "178.144.120.156"); // input generator that generates inputs using inputList - Iterator inputGenerator = new Iterator() { - - String current; - int size = inputList.size(); - int index = 0; - - @Override - public boolean hasNext() { - if(index == size) { - return false; - } - current = inputList.get(index); - index++; - return true; - } - - @Override - public String next() { - return current; - } - }; + Iterator inputGenerator = inputList.iterator(); // a display name generator that creates a different name based on the input Function displayNameGenerator = (input) -> "Resolving: " + input; @@ -111,6 +93,29 @@ public class DynamicTestsExample { } + @TestFactory + Stream dynamicTestsForEmployeeWorkflows() { + List inputList = + Arrays.asList(new Employee(1, "Fred"), new Employee(2), new Employee(3, "John")); + + EmployeeDao dao = new EmployeeDao(); + Stream saveEmployeeStream = inputList.stream().map(emp -> + DynamicTest.dynamicTest("saveEmployee: " + emp.toString(), () -> { + Employee returned = dao.save(emp.getId()); + assertEquals(returned.getId(), emp.getId()); + })); + + Stream saveEmployeeWithFirstNameStream + = inputList.stream().filter(emp -> !emp.getFirstName().isEmpty()) + .map(emp -> DynamicTest.dynamicTest("saveEmployeeWithName" + emp.toString(), () -> { + Employee returned = dao.save(emp.getId(), emp.getFirstName()); + assertEquals(returned.getId(), emp.getId()); + assertEquals(returned.getFirstName(), emp.getFirstName()); + })); + + return Stream.concat(saveEmployeeStream, saveEmployeeWithFirstNameStream); + } + class DomainNameResolver { private Map ipByDomainName = new HashMap<>(); diff --git a/junit5/src/test/java/com/baeldung/helpers/Employee.java b/junit5/src/test/java/com/baeldung/helpers/Employee.java new file mode 100644 index 0000000000..7fa724e4a8 --- /dev/null +++ b/junit5/src/test/java/com/baeldung/helpers/Employee.java @@ -0,0 +1,38 @@ +package com.baeldung.helpers; + +public class Employee { + + private long id; + private String firstName; + + public Employee(long id) { + this.id = id; + this.firstName = ""; + } + + public Employee(long id, String firstName) { + this.id = id; + this.firstName = firstName; + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + @Override + public String toString() { + return "Employee [id=" + id + ", firstName=" + firstName + "]"; + } +} diff --git a/junit5/src/test/java/com/baeldung/helpers/EmployeeDao.java b/junit5/src/test/java/com/baeldung/helpers/EmployeeDao.java new file mode 100644 index 0000000000..b23e5bf5e3 --- /dev/null +++ b/junit5/src/test/java/com/baeldung/helpers/EmployeeDao.java @@ -0,0 +1,16 @@ +package com.baeldung.helpers; + +public class EmployeeDao { + + public Employee save(long id) { + return new Employee(id); + } + + public Employee save(long id, String firstName) { + return new Employee(id, firstName); + } + + public Employee update(Employee employee) { + return employee; + } +} diff --git a/kotlin/README.md b/kotlin/README.md index 950f6460d5..57d16e0415 100644 --- a/kotlin/README.md +++ b/kotlin/README.md @@ -5,3 +5,4 @@ - [Comprehensive Guide to Null Safety in Kotlin](http://www.baeldung.com/kotlin-null-safety) - [Kotlin Java Interoperability](http://www.baeldung.com/kotlin-java-interoperability) - [Difference Between “==” and “===” in Kotlin]() +- [Generics in Kotlin](http://www.baeldung.com/kotlin-generics) diff --git a/libraries/README.md b/libraries/README.md index 1cfa7be86c..c405cc90d8 100644 --- a/libraries/README.md +++ b/libraries/README.md @@ -9,7 +9,8 @@ - [Introduction to Apache Flink with Java](http://www.baeldung.com/apache-flink) - [Introduction to JSONassert](http://www.baeldung.com/jsonassert) - [Intro to JaVer](http://www.baeldung.com/javers) - +- [Introduction to Apache Commons Math](http://www.baeldung.com/apache-commons-math) +- [Intro to JaVer](http://www.baeldung.com/serenity-bdd) The libraries module contains examples related to small libraries that are relatively easy to use and does not require any separate module of its own. diff --git a/libraries/pom.xml b/libraries/pom.xml index 6d41902db7..ff1997e969 100644 --- a/libraries/pom.xml +++ b/libraries/pom.xml @@ -225,12 +225,7 @@ org.datanucleus datanucleus-maven-plugin 5.0.2 - - - com.h2database - h2 - 1.4.194 - + org.datanucleus datanucleus-xml @@ -269,6 +264,28 @@ h2 1.4.195 + + pl.pragmatists + JUnitParams + ${jUnitParams.version} + test + + + org.quartz-scheduler + quartz + 2.3.0 + + + + one.util + streamex + 0.6.5 + + + org.jooq + jool + 0.9.12 + 0.7.0 @@ -292,6 +309,7 @@ 1.24.0 1.1.3-rc.5 1.4.0 + 1.1.0 diff --git a/libraries/src/main/java/com/baeldung/junitparams/SafeAdditionUtil.java b/libraries/src/main/java/com/baeldung/junitparams/SafeAdditionUtil.java new file mode 100644 index 0000000000..a2c1573dca --- /dev/null +++ b/libraries/src/main/java/com/baeldung/junitparams/SafeAdditionUtil.java @@ -0,0 +1,15 @@ +package com.baeldung.junitparams; + +public class SafeAdditionUtil { + + public int safeAdd(int a, int b) { + long result = ((long) a) + b; + if (result > Integer.MAX_VALUE) { + return Integer.MAX_VALUE; + } else if (result < Integer.MIN_VALUE) { + return Integer.MIN_VALUE; + } + return (int) result; + } + +} diff --git a/libraries/src/main/java/com/baeldung/quartz/QuartzExample.java b/libraries/src/main/java/com/baeldung/quartz/QuartzExample.java new file mode 100644 index 0000000000..1e37fc028b --- /dev/null +++ b/libraries/src/main/java/com/baeldung/quartz/QuartzExample.java @@ -0,0 +1,42 @@ +package com.baeldung.quartz; + +import org.quartz.JobBuilder; +import org.quartz.JobDetail; +import org.quartz.Scheduler; +import org.quartz.SchedulerException; +import org.quartz.SchedulerFactory; +import org.quartz.SimpleScheduleBuilder; +import org.quartz.Trigger; +import org.quartz.TriggerBuilder; +import org.quartz.impl.StdSchedulerFactory; + +public class QuartzExample { + + public static void main(String args[]) { + + SchedulerFactory schedFact = new StdSchedulerFactory(); + try { + + Scheduler sched = schedFact.getScheduler(); + + JobDetail job = JobBuilder.newJob(SimpleJob.class) + .withIdentity("myJob", "group1") + .build(); + + Trigger trigger = TriggerBuilder.newTrigger() + .withIdentity("myTrigger", "group1") + .startNow() + .withSchedule(SimpleScheduleBuilder.simpleSchedule() + .withIntervalInSeconds(40) + .repeatForever()) + .build(); + + sched.scheduleJob(job, trigger); + sched.start(); + + } catch (SchedulerException e) { + e.printStackTrace(); + } + } + +} \ No newline at end of file diff --git a/libraries/src/main/java/com/baeldung/quartz/SimpleJob.java b/libraries/src/main/java/com/baeldung/quartz/SimpleJob.java new file mode 100644 index 0000000000..370d698d13 --- /dev/null +++ b/libraries/src/main/java/com/baeldung/quartz/SimpleJob.java @@ -0,0 +1,13 @@ +package com.baeldung.quartz; + +import org.quartz.Job; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; + +public class SimpleJob implements Job { + + public void execute(JobExecutionContext arg0) throws JobExecutionException { + System.out.println("This is a quartz job!"); + } + +} \ No newline at end of file diff --git a/libraries/src/main/java/com/baeldung/serenity/spring/AdderController.java b/libraries/src/main/java/com/baeldung/serenity/spring/AdderController.java new file mode 100644 index 0000000000..b89e72d117 --- /dev/null +++ b/libraries/src/main/java/com/baeldung/serenity/spring/AdderController.java @@ -0,0 +1,29 @@ +package com.baeldung.serenity.spring; + +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.*; + +/** + * @author aiet + */ +@RequestMapping(value = "/adder", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) +@RestController +public class AdderController { + + private AdderService adderService; + + public AdderController(AdderService adderService) { + this.adderService = adderService; + } + + @GetMapping("/current") + public int currentNum() { + return adderService.currentBase(); + } + + @PostMapping + public int add(@RequestParam int num) { + return adderService.add(num); + } + +} diff --git a/libraries/src/main/java/com/baeldung/serenity/spring/AdderService.java b/libraries/src/main/java/com/baeldung/serenity/spring/AdderService.java new file mode 100644 index 0000000000..756c05bc2c --- /dev/null +++ b/libraries/src/main/java/com/baeldung/serenity/spring/AdderService.java @@ -0,0 +1,25 @@ +package com.baeldung.serenity.spring; + +import org.springframework.stereotype.Service; + +@Service +public class AdderService { + + private int num; + + public void baseNum(int base) { + this.num = base; + } + + public int currentBase() { + return num; + } + + public int add(int adder) { + return this.num + adder; + } + + public int accumulate(int adder) { + return this.num += adder; + } +} diff --git a/libraries/src/main/java/com/baeldung/serenity/spring/KonamiCodeController.java b/libraries/src/main/java/com/baeldung/serenity/spring/KonamiCodeController.java deleted file mode 100644 index f8ae66c229..0000000000 --- a/libraries/src/main/java/com/baeldung/serenity/spring/KonamiCodeController.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.baeldung.serenity.spring; - -import org.springframework.http.MediaType; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -/** - * @author aiet - */ -@RequestMapping(value = "/konamicode", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) -@RestController -public class KonamiCodeController { - - private final String classicCode = "↑↑↓↓←→←→BA"; - - @GetMapping("/classic") - public String classicCode() { - return classicCode; - } - - @GetMapping("/cheatable") - public boolean cheatCheck(@RequestParam String cheatcode){ - return classicCode.equals(cheatcode); - } - -} diff --git a/libraries/src/main/java/com/baeldung/serenity/spring/KonamiCodeService.java b/libraries/src/main/java/com/baeldung/serenity/spring/KonamiCodeService.java deleted file mode 100644 index 2aa1804ba5..0000000000 --- a/libraries/src/main/java/com/baeldung/serenity/spring/KonamiCodeService.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.baeldung.serenity.spring; - -import org.springframework.stereotype.Service; - -/** - * refer to Konami Code - */ -@Service -public class KonamiCodeService { - - private String classicCode = "↑↑↓↓←→←→BA"; - - public String getClassicCode() { - return classicCode; - } - - public void alterClassicCode(String newCode) { - classicCode = newCode; - } - - public boolean cheatWith(String cheatcode) { - if ("↑↑↓↓←→←→BA".equals(cheatcode)) { - stageLeft++; - return true; - } - return false; - } - - private int stageLeft = 1; - - public void clearStage() { - stageLeft = 0; - } - - public int stageLeft() { - return stageLeft; - } - -} diff --git a/libraries/src/main/java/com/baeldung/serenity/spring/KonamiCodeServiceInjectionController.java b/libraries/src/main/java/com/baeldung/serenity/spring/KonamiCodeServiceInjectionController.java deleted file mode 100644 index bb80963aa3..0000000000 --- a/libraries/src/main/java/com/baeldung/serenity/spring/KonamiCodeServiceInjectionController.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.baeldung.serenity.spring; - -import org.springframework.http.MediaType; -import org.springframework.web.bind.annotation.*; - -/** - * @author aiet - */ -@RequestMapping(value = "/konamicode", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) -@RestController -public class KonamiCodeServiceInjectionController { - - private KonamiCodeService konamiCodeService; - - public KonamiCodeServiceInjectionController(KonamiCodeService konamiCodeService) { - this.konamiCodeService = konamiCodeService; - } - - @PutMapping("/stages") - public void clearStage(@RequestParam String action) { - if ("clear".equals(action)) { - konamiCodeService.clearStage(); - } - } - - @GetMapping("/classic") - public String classicCode() { - return konamiCodeService.getClassicCode(); - } - - @GetMapping("/cheatable") - public boolean cheatCheck(@RequestParam String cheatcode) { - return konamiCodeService.cheatWith(cheatcode); - } - - @GetMapping("/stages") - public int stageLeft() { - return konamiCodeService.stageLeft(); - } - -} diff --git a/libraries/src/main/java/com/baeldung/serenity/spring/PlainAdderController.java b/libraries/src/main/java/com/baeldung/serenity/spring/PlainAdderController.java new file mode 100644 index 0000000000..888ebaf8bf --- /dev/null +++ b/libraries/src/main/java/com/baeldung/serenity/spring/PlainAdderController.java @@ -0,0 +1,26 @@ +package com.baeldung.serenity.spring; + +import org.apache.commons.lang3.RandomUtils; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.*; + +/** + * @author aiet + */ +@RequestMapping(value = "/adder", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) +@RestController +public class PlainAdderController { + + private final int currentNumber = RandomUtils.nextInt(); + + @GetMapping("/current") + public int currentNum() { + return currentNumber; + } + + @PostMapping + public int add(@RequestParam int num) { + return currentNumber + num; + } + +} diff --git a/libraries/src/test/java/com/baeldung/junitparams/SafeAdditionUtilTest.java b/libraries/src/test/java/com/baeldung/junitparams/SafeAdditionUtilTest.java new file mode 100644 index 0000000000..c9141a6e57 --- /dev/null +++ b/libraries/src/test/java/com/baeldung/junitparams/SafeAdditionUtilTest.java @@ -0,0 +1,55 @@ +package com.baeldung.junitparams; + +import static org.junit.Assert.*; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import junitparams.FileParameters; +import junitparams.JUnitParamsRunner; +import junitparams.Parameters; + +@RunWith(JUnitParamsRunner.class) +public class SafeAdditionUtilTest { + + private SafeAdditionUtil serviceUnderTest = new SafeAdditionUtil(); + + @Test + @Parameters({ "1, 2, 3", "-10, 30, 20", "15, -5, 10", "-5, -10, -15" }) + public void whenCalledWithAnnotationProvidedParams_thenSafeAddAndReturn(int a, int b, int expectedValue) { + assertEquals(expectedValue, serviceUnderTest.safeAdd(a, b)); + } + + @Test + @Parameters(method = "parametersToTestAdd") + public void whenCalledWithNamedMethod_thendSafeAddAndReturn(int a, int b, int expectedValue) { + assertEquals(expectedValue, serviceUnderTest.safeAdd(a, b)); + } + + private Object[] parametersToTestAdd() { + return new Object[] { new Object[] { 1, 2, 3 }, new Object[] { -10, 30, 20 }, new Object[] { Integer.MAX_VALUE, 2, Integer.MAX_VALUE }, new Object[] { Integer.MIN_VALUE, -8, Integer.MIN_VALUE } }; + } + + @Test + @Parameters + public void whenCalledWithnoParam_thenLoadByNameSafeAddAndReturn(int a, int b, int expectedValue) { + assertEquals(expectedValue, serviceUnderTest.safeAdd(a, b)); + } + + private Object[] parametersForWhenCalledWithnoParam_thenLoadByNameSafeAddAndReturn() { + return new Object[] { new Object[] { 1, 2, 3 }, new Object[] { -10, 30, 20 }, new Object[] { Integer.MAX_VALUE, 2, Integer.MAX_VALUE }, new Object[] { Integer.MIN_VALUE, -8, Integer.MIN_VALUE } }; + } + + @Test + @Parameters(source = TestDataProvider.class) + public void whenCalledWithNamedClass_thenSafeAddAndReturn(int a, int b, int expectedValue) { + assertEquals(expectedValue, serviceUnderTest.safeAdd(a, b)); + } + + @Test + @FileParameters("src/test/resources/JunitParamsTestParameters.csv") + public void whenCalledWithCsvFile_thenSafeAddAndReturn(int a, int b, int expectedValue) { + assertEquals(expectedValue, serviceUnderTest.safeAdd(a, b)); + } + +} diff --git a/libraries/src/test/java/com/baeldung/junitparams/TestDataProvider.java b/libraries/src/test/java/com/baeldung/junitparams/TestDataProvider.java new file mode 100644 index 0000000000..d318345a56 --- /dev/null +++ b/libraries/src/test/java/com/baeldung/junitparams/TestDataProvider.java @@ -0,0 +1,13 @@ +package com.baeldung.junitparams; + +public class TestDataProvider { + + public static Object[] provideBasicData() { + return new Object[] { new Object[] { 1, 2, 3 }, new Object[] { -10, 30, 20 }, new Object[] { 15, -5, 10 }, new Object[] { -5, -10, -15 } }; + } + + public static Object[] provideEdgeCaseData() { + return new Object[] { new Object[] { Integer.MAX_VALUE, 2, Integer.MAX_VALUE }, new Object[] { Integer.MIN_VALUE, -2, Integer.MIN_VALUE }, }; + } + +} diff --git a/libraries/src/test/java/com/baeldung/serenity/spring/AdderClassDirtiesContextIntegrationTest.java b/libraries/src/test/java/com/baeldung/serenity/spring/AdderClassDirtiesContextIntegrationTest.java new file mode 100644 index 0000000000..bb25186cee --- /dev/null +++ b/libraries/src/test/java/com/baeldung/serenity/spring/AdderClassDirtiesContextIntegrationTest.java @@ -0,0 +1,76 @@ +package com.baeldung.serenity.spring; + +import com.baeldung.serenity.spring.steps.AdderServiceSteps; +import net.serenitybdd.junit.runners.SerenityRunner; +import net.serenitybdd.junit.spring.integration.SpringIntegrationClassRule; +import net.thucydides.core.annotations.Steps; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ContextConfiguration; + +import static com.baeldung.serenity.spring.RandomNumberUtil.randomInt; +import static org.springframework.test.annotation.DirtiesContext.ClassMode.AFTER_CLASS; + +/** + * @author aiet + */ + +@RunWith(Suite.class) +@Suite.SuiteClasses({ + AdderClassDirtiesContextIntegrationTest.DirtiesContextTest.class, AdderClassDirtiesContextIntegrationTest.AnotherDirtiesContextTest.class + }) +public class AdderClassDirtiesContextIntegrationTest { + + @RunWith(SerenityRunner.class) + @ContextConfiguration(classes = AdderService.class) + public static abstract class Base { + + @Steps AdderServiceSteps adderServiceSteps; + + @ClassRule public static SpringIntegrationClassRule springIntegrationClassRule = new SpringIntegrationClassRule(); + + void whenAccumulate_thenSummedUp() { + adderServiceSteps.whenAccumulate(); + adderServiceSteps.summedUp(); + } + + void whenAdd_thenSumWrong() { + adderServiceSteps.whenAdd(); + adderServiceSteps.sumWrong(); + } + + void whenAdd_thenSummedUp() { + adderServiceSteps.whenAdd(); + adderServiceSteps.summedUp(); + } + + } + + @DirtiesContext(classMode = AFTER_CLASS) + public static class AnotherDirtiesContextTest extends Base { + + @Test + public void givenNumber_whenAdd_thenSumWrong() { + super.whenAdd_thenSummedUp(); //expecting zero + adderServiceSteps.givenBaseAndAdder(randomInt(), randomInt()); + super.whenAccumulate_thenSummedUp(); + super.whenAdd_thenSumWrong(); + } + } + + @DirtiesContext(classMode = AFTER_CLASS) + public static class DirtiesContextTest extends Base { + + @Test + public void givenNumber_whenAdd_thenSumWrong() { + super.whenAdd_thenSummedUp(); //expecting zero + adderServiceSteps.givenBaseAndAdder(randomInt(), randomInt()); + super.whenAccumulate_thenSummedUp(); + super.whenAdd_thenSumWrong(); + } + } + +} diff --git a/libraries/src/test/java/com/baeldung/serenity/spring/AdderMethodDirtiesContextDependencyWorkaroundIntegrationTest.java b/libraries/src/test/java/com/baeldung/serenity/spring/AdderMethodDirtiesContextDependencyWorkaroundIntegrationTest.java new file mode 100644 index 0000000000..6524ade190 --- /dev/null +++ b/libraries/src/test/java/com/baeldung/serenity/spring/AdderMethodDirtiesContextDependencyWorkaroundIntegrationTest.java @@ -0,0 +1,54 @@ +package com.baeldung.serenity.spring; + +import com.baeldung.serenity.spring.steps.AdderConstructorDependencySteps; +import net.serenitybdd.junit.runners.SerenityRunner; +import net.serenitybdd.junit.spring.integration.SpringIntegrationMethodRule; +import org.junit.Before; +import org.junit.FixMethodOrder; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.MethodSorters; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ContextConfiguration; + +import static com.baeldung.serenity.spring.RandomNumberUtil.randomInt; + +/** + * @author aiet + */ +@RunWith(SerenityRunner.class) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@ContextConfiguration(classes = AdderService.class) +public class AdderMethodDirtiesContextDependencyWorkaroundIntegrationTest { + + private AdderConstructorDependencySteps adderSteps; + + @Autowired private AdderService adderService; + + @Before + public void init() { + adderSteps = new AdderConstructorDependencySteps(adderService); + } + + @Test + public void _1_givenNumber_whenAdd_thenSumWrong() { + adderSteps.whenAdd(); + adderSteps.summedUp(); + } + + @Rule public SpringIntegrationMethodRule springIntegration = new SpringIntegrationMethodRule(); + + @DirtiesContext + @Test + public void _0_givenNumber_whenAddAndAccumulate_thenSummedUp() { + adderSteps.givenBaseAndAdder(randomInt(), randomInt()); + adderSteps.whenAccumulate(); + adderSteps.summedUp(); + + adderSteps.whenAdd(); + adderSteps.sumWrong(); + } + +} diff --git a/libraries/src/test/java/com/baeldung/serenity/spring/AdderMethodDirtiesContextInitWorkaroundIntegrationTest.java b/libraries/src/test/java/com/baeldung/serenity/spring/AdderMethodDirtiesContextInitWorkaroundIntegrationTest.java new file mode 100644 index 0000000000..87c66f03d9 --- /dev/null +++ b/libraries/src/test/java/com/baeldung/serenity/spring/AdderMethodDirtiesContextInitWorkaroundIntegrationTest.java @@ -0,0 +1,51 @@ +package com.baeldung.serenity.spring; + +import com.baeldung.serenity.spring.steps.AdderServiceSteps; +import net.serenitybdd.junit.runners.SerenityRunner; +import net.serenitybdd.junit.spring.integration.SpringIntegrationMethodRule; +import net.thucydides.core.annotations.Steps; +import org.junit.Before; +import org.junit.FixMethodOrder; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.MethodSorters; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ContextConfiguration; + +import static com.baeldung.serenity.spring.RandomNumberUtil.randomInt; + +/** + * @author aiet + */ +@RunWith(SerenityRunner.class) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@ContextConfiguration(classes = AdderService.class) +public class AdderMethodDirtiesContextInitWorkaroundIntegrationTest { + + @Steps private AdderServiceSteps adderServiceSteps; + + @Before + public void init() { + adderServiceSteps.givenBaseAndAdder(randomInt(), randomInt()); + } + + @Test + public void _1_givenNumber_whenAdd_thenSumWrong() { + adderServiceSteps.whenAdd(); + adderServiceSteps.summedUp(); + } + + @Rule public SpringIntegrationMethodRule springIntegration = new SpringIntegrationMethodRule(); + + @DirtiesContext + @Test + public void _0_givenNumber_whenAddAndAccumulate_thenSummedUp() { + adderServiceSteps.whenAccumulate(); + adderServiceSteps.summedUp(); + + adderServiceSteps.whenAdd(); + adderServiceSteps.sumWrong(); + } + +} diff --git a/libraries/src/test/java/com/baeldung/serenity/spring/AdderMethodDirtiesContextIntegrationTest.java b/libraries/src/test/java/com/baeldung/serenity/spring/AdderMethodDirtiesContextIntegrationTest.java new file mode 100644 index 0000000000..263ffc9854 --- /dev/null +++ b/libraries/src/test/java/com/baeldung/serenity/spring/AdderMethodDirtiesContextIntegrationTest.java @@ -0,0 +1,46 @@ +package com.baeldung.serenity.spring; + +import com.baeldung.serenity.spring.steps.AdderServiceSteps; +import net.serenitybdd.junit.runners.SerenityRunner; +import net.serenitybdd.junit.spring.integration.SpringIntegrationMethodRule; +import net.thucydides.core.annotations.Steps; +import org.junit.FixMethodOrder; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.MethodSorters; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ContextConfiguration; + +import static com.baeldung.serenity.spring.RandomNumberUtil.randomInt; + +/** + * @author aiet + */ +@RunWith(SerenityRunner.class) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@ContextConfiguration(classes = AdderService.class) +public class AdderMethodDirtiesContextIntegrationTest { + + @Steps private AdderServiceSteps adderServiceSteps; + + @Test + public void _1_givenNumber_whenAdd_thenSumWrong() { + adderServiceSteps.whenAdd(); + adderServiceSteps.sumWrong(); + } + + @Rule public SpringIntegrationMethodRule springIntegration = new SpringIntegrationMethodRule(); + + @DirtiesContext + @Test + public void _0_givenNumber_whenAddAndAccumulate_thenSummedUp() { + adderServiceSteps.givenBaseAndAdder(randomInt(), randomInt()); + adderServiceSteps.whenAccumulate(); + adderServiceSteps.summedUp(); + + adderServiceSteps.whenAdd(); + adderServiceSteps.sumWrong(); + } + +} diff --git a/libraries/src/test/java/com/baeldung/serenity/spring/AdderMethodRuleIntegrationTest.java b/libraries/src/test/java/com/baeldung/serenity/spring/AdderMethodRuleIntegrationTest.java new file mode 100644 index 0000000000..bbf07a2b95 --- /dev/null +++ b/libraries/src/test/java/com/baeldung/serenity/spring/AdderMethodRuleIntegrationTest.java @@ -0,0 +1,59 @@ +package com.baeldung.serenity.spring; + +import com.baeldung.serenity.spring.steps.AdderSteps; +import net.serenitybdd.junit.runners.SerenityRunner; +import net.serenitybdd.junit.spring.integration.SpringIntegrationMethodRule; +import net.thucydides.core.annotations.Steps; +import org.junit.*; +import org.junit.runner.RunWith; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.test.context.ContextConfiguration; + +/** + * Unit test for simple App. + */ +@RunWith(SerenityRunner.class) +@ContextConfiguration(locations = "classpath:adder-beans.xml") +public class AdderMethodRuleIntegrationTest { + + private static Logger LOG = LoggerFactory.getLogger(AdderMethodRuleIntegrationTest.class); + + @BeforeClass + public static void initClass() { + LOG.info("static adder before test class: {}", staticAdder); + } + + @AfterClass + public static void destroyClass() { + LOG.info("static adder after test class: {}", staticAdder); + } + + @Before + public void init() { + LOG.info("adder before test: {}", adder); + staticAdder = adder; + } + + @After + public void destroy() { + LOG.info("adder after test: {}", adder); + } + + @Rule public SpringIntegrationMethodRule springMethodIntegration = new SpringIntegrationMethodRule(); + + @Steps private AdderSteps adderSteps; + + @Value("#{props['adder']}") private int adder; + + private static int staticAdder; + + @Test + public void givenNumber_whenAdd_thenSummedUp() { + adderSteps.givenNumber(); + adderSteps.whenAdd(adder); + adderSteps.thenSummedUp(); + } + +} diff --git a/libraries/src/test/java/com/baeldung/serenity/spring/AdderMockMvcIntegrationTest.java b/libraries/src/test/java/com/baeldung/serenity/spring/AdderMockMvcIntegrationTest.java new file mode 100644 index 0000000000..2b2777f0ed --- /dev/null +++ b/libraries/src/test/java/com/baeldung/serenity/spring/AdderMockMvcIntegrationTest.java @@ -0,0 +1,33 @@ +package com.baeldung.serenity.spring; + +import com.baeldung.serenity.spring.steps.AdderRestSteps; +import io.restassured.module.mockmvc.RestAssuredMockMvc; +import net.serenitybdd.junit.runners.SerenityRunner; +import net.thucydides.core.annotations.Steps; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static com.baeldung.serenity.spring.RandomNumberUtil.randomInt; + +/** + * @author aiet + */ +@RunWith(SerenityRunner.class) +public class AdderMockMvcIntegrationTest { + + @Before + public void init() { + RestAssuredMockMvc.standaloneSetup(new PlainAdderController()); + } + + @Steps AdderRestSteps steps; + + @Test + public void givenNumber_whenAdd_thenSummedUp() throws Exception { + steps.givenCurrentNumber(); + steps.whenAddNumber(randomInt()); + steps.thenSummedUp(); + } + +} diff --git a/libraries/src/test/java/com/baeldung/serenity/spring/AdderServiceIntegrationTest.java b/libraries/src/test/java/com/baeldung/serenity/spring/AdderServiceIntegrationTest.java new file mode 100644 index 0000000000..5f2aae8e3f --- /dev/null +++ b/libraries/src/test/java/com/baeldung/serenity/spring/AdderServiceIntegrationTest.java @@ -0,0 +1,26 @@ +package com.baeldung.serenity.spring; + +import com.baeldung.serenity.spring.steps.AdderServiceSteps; +import net.serenitybdd.junit.runners.SerenityRunner; +import net.thucydides.core.annotations.Steps; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static com.baeldung.serenity.spring.RandomNumberUtil.randomInt; + +/** + * @author aiet + */ +@RunWith(SerenityRunner.class) +public class AdderServiceIntegrationTest { + + @Steps private AdderServiceSteps adderServiceSteps; + + @Test + public void givenNumber_whenAdd_thenSummedUp() { + adderServiceSteps.givenBaseAndAdder(randomInt(), randomInt()); + adderServiceSteps.whenAdd(); + adderServiceSteps.summedUp(); + } + +} diff --git a/libraries/src/test/java/com/baeldung/serenity/spring/AdderSpringSerenityRunnerIntegrationTest.java b/libraries/src/test/java/com/baeldung/serenity/spring/AdderSpringSerenityRunnerIntegrationTest.java new file mode 100644 index 0000000000..cdabc17980 --- /dev/null +++ b/libraries/src/test/java/com/baeldung/serenity/spring/AdderSpringSerenityRunnerIntegrationTest.java @@ -0,0 +1,29 @@ +package com.baeldung.serenity.spring; + +import com.baeldung.serenity.spring.steps.AdderSteps; +import net.serenitybdd.junit.spring.integration.SpringIntegrationSerenityRunner; +import net.thucydides.core.annotations.Steps; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.test.context.ContextConfiguration; + +/** + * Unit test for simple App. + */ +@RunWith(SpringIntegrationSerenityRunner.class) +@ContextConfiguration(locations = "classpath:adder-beans.xml") +public class AdderSpringSerenityRunnerIntegrationTest { + + @Steps private AdderSteps adderSteps; + + @Value("#{props['adder']}") private int adder; + + @Test + public void givenNumber_whenAdd_thenSummedUp() { + adderSteps.givenNumber(); + adderSteps.whenAdd(adder); + adderSteps.thenSummedUp(); + } + +} diff --git a/libraries/src/test/java/com/baeldung/serenity/spring/KonamiCodeTest.java b/libraries/src/test/java/com/baeldung/serenity/spring/AdderTest.java similarity index 55% rename from libraries/src/test/java/com/baeldung/serenity/spring/KonamiCodeTest.java rename to libraries/src/test/java/com/baeldung/serenity/spring/AdderTest.java index d2e5fd30f6..a57b924211 100644 --- a/libraries/src/test/java/com/baeldung/serenity/spring/KonamiCodeTest.java +++ b/libraries/src/test/java/com/baeldung/serenity/spring/AdderTest.java @@ -9,14 +9,14 @@ import org.springframework.test.context.ContextConfiguration; /** * @author aiet */ -@ContextConfiguration(classes = { KonamiCodeServiceInjectionController.class, KonamiCodeService.class }) -public class KonamiCodeTest extends SerenityStory { +@ContextConfiguration(classes = { AdderController.class, AdderService.class }) +public class AdderTest extends SerenityStory { - @Autowired private KonamiCodeService konamiCodeService; + @Autowired private AdderService adderService; @BeforeStory public void init() { - RestAssuredMockMvc.standaloneSetup(new KonamiCodeServiceInjectionController(konamiCodeService)); + RestAssuredMockMvc.standaloneSetup(new AdderController(adderService)); } } diff --git a/libraries/src/test/java/com/baeldung/serenity/spring/KonamCheatClassDirtiesContextIntegrationTest.java b/libraries/src/test/java/com/baeldung/serenity/spring/KonamCheatClassDirtiesContextIntegrationTest.java deleted file mode 100644 index 2e2fcd676f..0000000000 --- a/libraries/src/test/java/com/baeldung/serenity/spring/KonamCheatClassDirtiesContextIntegrationTest.java +++ /dev/null @@ -1,74 +0,0 @@ -package com.baeldung.serenity.spring; - -import com.baeldung.serenity.spring.steps.KonamiCodeServiceInjectionSteps; -import net.serenitybdd.junit.runners.SerenityRunner; -import net.serenitybdd.junit.spring.integration.SpringIntegrationClassRule; -import net.thucydides.core.annotations.Steps; -import net.thucydides.core.annotations.Title; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Suite; -import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.context.ContextConfiguration; - -import static org.springframework.test.annotation.DirtiesContext.ClassMode.AFTER_CLASS; - -/** - * @author aiet - */ - -@RunWith(Suite.class) -@Suite.SuiteClasses({ - KonamCheatClassDirtiesContextIntegrationTest.DirtiesContextTest.class, KonamCheatClassDirtiesContextIntegrationTest.AnotherDirtiesContextTest.class - }) -public class KonamCheatClassDirtiesContextIntegrationTest { - - @RunWith(SerenityRunner.class) - @ContextConfiguration(classes = KonamiCodeService.class) - public static abstract class Base { - - @Steps KonamiCodeServiceInjectionSteps cheatSteps; - - @ClassRule public static SpringIntegrationClassRule springIntegrationClassRule = new SpringIntegrationClassRule(); - - void hiddenStageShouldBeUnlockedAfterCheating() { - fetchAndCheat(); - cheatSteps.aStageRemains(); - - cheatSteps.letsHack(); - - fetchAndCheat(); - cheatSteps.noStageRemains(); - } - - private void fetchAndCheat() { - cheatSteps.gameStageCleared(); - cheatSteps.fetchLatestCheatcode(); - cheatSteps.cheatWithLatestcode(); - } - - } - - @DirtiesContext(classMode = AFTER_CLASS) - public static class AnotherDirtiesContextTest extends Base { - - @Test - @Title("altering the cheatcode after unlocking would stop others from cheating, not affected by other tests (another)") - public void givenGameStageCleared_whenCheat_thenHiddenStageUnlocked() { - super.hiddenStageShouldBeUnlockedAfterCheating(); - } - } - - @DirtiesContext(classMode = AFTER_CLASS) - public static class DirtiesContextTest extends Base { - - @Test - @Title("altering the cheatcode after unlocking would stop others from cheating, not affected by other tests") - public void givenGameStageCleared_whenCheat_thenHiddenStageUnlocked() { - super.hiddenStageShouldBeUnlockedAfterCheating(); - } - } - - -} diff --git a/libraries/src/test/java/com/baeldung/serenity/spring/KonamCheatWithDirtyActionIntegrationTest.java b/libraries/src/test/java/com/baeldung/serenity/spring/KonamCheatWithDirtyActionIntegrationTest.java deleted file mode 100644 index bbda1566af..0000000000 --- a/libraries/src/test/java/com/baeldung/serenity/spring/KonamCheatWithDirtyActionIntegrationTest.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.baeldung.serenity.spring; - -import com.baeldung.serenity.spring.steps.KonamiCodeConstructorDependencySteps; -import net.serenitybdd.junit.runners.SerenityRunner; -import net.serenitybdd.junit.spring.integration.SpringIntegrationMethodRule; -import net.thucydides.core.annotations.Title; -import org.junit.Before; -import org.junit.FixMethodOrder; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.MethodSorters; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.context.ContextConfiguration; - -/** - * @author aiet - */ -@RunWith(SerenityRunner.class) -@FixMethodOrder(MethodSorters.NAME_ASCENDING) -@ContextConfiguration(classes = KonamiCodeService.class) -public class KonamCheatWithDirtyActionIntegrationTest { - - private KonamiCodeConstructorDependencySteps cheatSteps; - - @Autowired private KonamiCodeService codeService; - - @Before - public void init() { - cheatSteps = new KonamiCodeConstructorDependencySteps(codeService); - } - - @Test - @Title("hidden stage should be unlocked after cheating (run in service with dirty action)") - public void givenGameStageCleared_whenCheat_thenHiddenStageUnlocked() { - fetchCodeAndCheat(); - cheatSteps.aStageRemains(); - } - - @Rule public SpringIntegrationMethodRule springIntegration = new SpringIntegrationMethodRule(); - - @DirtiesContext - @Test - @Title("altering the cheatcode after unlocking would stop others from cheating") - public void givenGameStageCleared_whenCheatAndHack_thenAnotherCheatFail() { - fetchCodeAndCheat(); - cheatSteps.aStageRemains(); - - cheatSteps.letsHack(); - - fetchCodeAndCheat(); - cheatSteps.noStageRemains(); - } - - private void fetchCodeAndCheat() { - cheatSteps.gameStageCleared(); - cheatSteps.fetchLatestCheatcode(); - cheatSteps.cheatWithLatestcode(); - } - -} diff --git a/libraries/src/test/java/com/baeldung/serenity/spring/KonamCheatWithDirtyActionWithImplicitInjectionIntegrationTest.java b/libraries/src/test/java/com/baeldung/serenity/spring/KonamCheatWithDirtyActionWithImplicitInjectionIntegrationTest.java deleted file mode 100644 index d9b8bd2cc7..0000000000 --- a/libraries/src/test/java/com/baeldung/serenity/spring/KonamCheatWithDirtyActionWithImplicitInjectionIntegrationTest.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.baeldung.serenity.spring; - -import com.baeldung.serenity.spring.steps.KonamiCodeServiceInjectionSteps; -import net.serenitybdd.junit.runners.SerenityRunner; -import net.serenitybdd.junit.spring.integration.SpringIntegrationMethodRule; -import net.thucydides.core.annotations.Steps; -import net.thucydides.core.annotations.Title; -import org.junit.FixMethodOrder; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.MethodSorters; -import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.context.ContextConfiguration; - -/** - * @author aiet - */ -@RunWith(SerenityRunner.class) -@FixMethodOrder(MethodSorters.NAME_ASCENDING) -@ContextConfiguration(classes = KonamiCodeService.class) -public class KonamCheatWithDirtyActionWithImplicitInjectionIntegrationTest { - - @Steps private KonamiCodeServiceInjectionSteps cheatSteps; - - @Test - @Title("hidden stage is not unlocked after cheating (cheatcode hacked)") - public void givenGameStageCleared_whenCheat_thenCheatFail() { - fetchCodeAndCheat(); - cheatSteps.noStageRemains(); - } - - private void fetchCodeAndCheat() { - cheatSteps.gameStageCleared(); - cheatSteps.fetchLatestCheatcode(); - cheatSteps.cheatWithLatestcode(); - } - - @Rule public SpringIntegrationMethodRule springIntegration = new SpringIntegrationMethodRule(); - - @DirtiesContext - @Test - @Title("altering the cheatcode after unlocking would stop others from cheating") - public void givenGameStageCleared_whenCheatAndHack_thenAnotherCheatFail() { - fetchCodeAndCheat(); - cheatSteps.aStageRemains(); - - cheatSteps.letsHack(); - - fetchCodeAndCheat(); - cheatSteps.noStageRemains(); - } - -} diff --git a/libraries/src/test/java/com/baeldung/serenity/spring/KonamCheatWithServiceIntegrationTest.java b/libraries/src/test/java/com/baeldung/serenity/spring/KonamCheatWithServiceIntegrationTest.java deleted file mode 100644 index ad8a00ec90..0000000000 --- a/libraries/src/test/java/com/baeldung/serenity/spring/KonamCheatWithServiceIntegrationTest.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.baeldung.serenity.spring; - -import com.baeldung.serenity.spring.steps.KonamiCodeServiceInjectionSteps; -import net.serenitybdd.junit.runners.SerenityRunner; -import net.thucydides.core.annotations.Steps; -import net.thucydides.core.annotations.Title; -import org.junit.Test; -import org.junit.runner.RunWith; - -/** - * @author aiet - */ -@RunWith(SerenityRunner.class) -public class KonamCheatWithServiceIntegrationTest { - - @Steps private KonamiCodeServiceInjectionSteps cheatSteps; - - @Test - @Title("hidden stage should be unlocked after cheating (mockmvc)") - public void givenGameStageCleared_whenCheat_thenHiddenStageUnlocked() { - cheatSteps.gameStageCleared(); - cheatSteps.fetchLatestCheatcode(); - cheatSteps.cheatWithLatestcode(); - cheatSteps.aStageRemains(); - } - -} diff --git a/libraries/src/test/java/com/baeldung/serenity/spring/KonamiCheatWithIntegrationMethodRulesIntegrationTest.java b/libraries/src/test/java/com/baeldung/serenity/spring/KonamiCheatWithIntegrationMethodRulesIntegrationTest.java deleted file mode 100644 index 634ac92fd9..0000000000 --- a/libraries/src/test/java/com/baeldung/serenity/spring/KonamiCheatWithIntegrationMethodRulesIntegrationTest.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.baeldung.serenity.spring; - -import com.baeldung.serenity.spring.steps.KonamiCheatSteps; -import net.serenitybdd.junit.runners.SerenityRunner; -import net.serenitybdd.junit.spring.integration.SpringIntegrationMethodRule; -import net.thucydides.core.annotations.Steps; -import net.thucydides.core.annotations.Title; -import org.junit.*; -import org.junit.runner.RunWith; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.test.context.ContextConfiguration; - -/** - * Unit test for simple App. - */ -@RunWith(SerenityRunner.class) -@ContextConfiguration(locations = "classpath:konami-cheat-beans.xml") -public class KonamiCheatWithIntegrationMethodRulesIntegrationTest { - - private static Logger LOG = LoggerFactory.getLogger(KonamiCheatWithIntegrationMethodRulesIntegrationTest.class); - - @BeforeClass - public static void initClass() { - LOG.info("static chaincode before test class: {}", staticCheatCode); - } - - @AfterClass - public static void destroyClass() { - LOG.info("static chaincode after test class: {}", staticCheatCode); - } - - @Before - public void init() { - staticCheatCode = cheatCode; - LOG.info("cheatcode before test: {}", cheatCode); - } - - @After - public void destroy() { - LOG.info("cheatcode after test: {}", cheatCode); - } - - @Rule public SpringIntegrationMethodRule springMethodIntegration = new SpringIntegrationMethodRule(); - - @Steps private KonamiCheatSteps konamiCheatSteps; - - @Value("#{konami_props['code']}") private String cheatCode; - - private static String staticCheatCode; - - @Test - @Title("hidden stage should be unlocked after cheating (rule integration)") - public void givenGameStageCleared_whenCheat_thenHiddenStageUnlocked() { - konamiCheatSteps.gameStageCleared(); - konamiCheatSteps.cheatWith(cheatCode); - konamiCheatSteps.aStageRemains(); - } - -} diff --git a/libraries/src/test/java/com/baeldung/serenity/spring/KonamiCheatWithIntegrationRunnerIntegrationTest.java b/libraries/src/test/java/com/baeldung/serenity/spring/KonamiCheatWithIntegrationRunnerIntegrationTest.java deleted file mode 100644 index 81c1571cc5..0000000000 --- a/libraries/src/test/java/com/baeldung/serenity/spring/KonamiCheatWithIntegrationRunnerIntegrationTest.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.baeldung.serenity.spring; - -import com.baeldung.serenity.spring.steps.KonamiCheatSteps; -import net.serenitybdd.junit.spring.integration.SpringIntegrationSerenityRunner; -import net.thucydides.core.annotations.Steps; -import net.thucydides.core.annotations.Title; -import org.junit.*; -import org.junit.runner.RunWith; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.test.context.ContextConfiguration; - -/** - * Unit test for simple App. - */ -@RunWith(SpringIntegrationSerenityRunner.class) -@ContextConfiguration(locations = "classpath:konami-cheat-beans.xml") -public class KonamiCheatWithIntegrationRunnerIntegrationTest { - - private static Logger LOG = LoggerFactory.getLogger(KonamiCheatWithIntegrationRunnerIntegrationTest.class); - - @BeforeClass - public static void initClass() { - LOG.info("static chaincode before test class: {}", staticCheatCode); - } - - @AfterClass - public static void destroyClass() { - LOG.info("static chaincode after test class: {}", staticCheatCode); - } - - @Before - public void init() { - staticCheatCode = cheatCode; - LOG.info("cheatcode before test: {}", cheatCode); - } - - @After - public void destroy() { - LOG.info("cheatcode after test: {}", cheatCode); - } - - @Steps private KonamiCheatSteps konamiCheatSteps; - - @Value("#{konami_props['code']}") private String cheatCode; - - private static String staticCheatCode; - - @Test - @Title("hidden stage should be unlocked after cheating (with integration runner)") - public void givenGameStageCleared_whenCheat_thenHiddenStageUnlocked() { - konamiCheatSteps.gameStageCleared(); - konamiCheatSteps.cheatWith(cheatCode); - konamiCheatSteps.aStageRemains(); - } - -} diff --git a/libraries/src/test/java/com/baeldung/serenity/spring/KonamiCodeMockMvcIntegrationTest.java b/libraries/src/test/java/com/baeldung/serenity/spring/KonamiCodeMockMvcIntegrationTest.java deleted file mode 100644 index 12514f8d4a..0000000000 --- a/libraries/src/test/java/com/baeldung/serenity/spring/KonamiCodeMockMvcIntegrationTest.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.baeldung.serenity.spring; - -import com.baeldung.serenity.spring.steps.KonamiCodeRestSteps; -import io.restassured.module.mockmvc.RestAssuredMockMvc; -import net.serenitybdd.junit.runners.SerenityRunner; -import net.thucydides.core.annotations.Steps; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -/** - * @author aiet - */ -@RunWith(SerenityRunner.class) -public class KonamiCodeMockMvcIntegrationTest { - - @Before - public void init() { - RestAssuredMockMvc.standaloneSetup(new KonamiCodeController()); - } - - @Steps KonamiCodeRestSteps steps; - - @Test - public void givenOfficialClassicCheatcode_whenCheat_ThenTheCodeShouldDoTheTrick() throws Exception { - steps.givenClassicCheatCode(); - steps.whenCheat(); - steps.thenClassicCodeCanDoTheTrick(); - } - -} diff --git a/libraries/src/test/java/com/baeldung/serenity/spring/RandomNumberUtil.java b/libraries/src/test/java/com/baeldung/serenity/spring/RandomNumberUtil.java new file mode 100644 index 0000000000..42a532da42 --- /dev/null +++ b/libraries/src/test/java/com/baeldung/serenity/spring/RandomNumberUtil.java @@ -0,0 +1,13 @@ +package com.baeldung.serenity.spring; + +import org.apache.commons.lang3.RandomUtils; + +/** + * @author aiet + */ +public class RandomNumberUtil { + + public static int randomInt() { + return RandomUtils.nextInt(1, 10); + } +} diff --git a/libraries/src/test/java/com/baeldung/serenity/spring/steps/AdderConstructorDependencySteps.java b/libraries/src/test/java/com/baeldung/serenity/spring/steps/AdderConstructorDependencySteps.java new file mode 100644 index 0000000000..2bf6b0e6d6 --- /dev/null +++ b/libraries/src/test/java/com/baeldung/serenity/spring/steps/AdderConstructorDependencySteps.java @@ -0,0 +1,44 @@ +package com.baeldung.serenity.spring.steps; + +import com.baeldung.serenity.spring.AdderService; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; + +/** + * @author aiet + */ +public class AdderConstructorDependencySteps { + + private AdderService adderService; + + public AdderConstructorDependencySteps(AdderService adderService) { + this.adderService = adderService; + } + + private int givenNumber; + private int base; + private int sum; + + public void givenBaseAndAdder(int base, int adder) { + this.base = base; + adderService.baseNum(base); + this.givenNumber = adder; + } + + public void whenAdd() { + sum = adderService.add(givenNumber); + } + + public void summedUp() { + assertEquals(base + givenNumber, sum); + } + + public void sumWrong() { + assertNotEquals(base + givenNumber, sum); + } + + public void whenAccumulate() { + sum = adderService.accumulate(givenNumber); + } +} diff --git a/libraries/src/test/java/com/baeldung/serenity/spring/steps/AdderRestSteps.java b/libraries/src/test/java/com/baeldung/serenity/spring/steps/AdderRestSteps.java new file mode 100644 index 0000000000..0d77ed0849 --- /dev/null +++ b/libraries/src/test/java/com/baeldung/serenity/spring/steps/AdderRestSteps.java @@ -0,0 +1,46 @@ +package com.baeldung.serenity.spring.steps; + +import io.restassured.module.mockmvc.response.MockMvcResponse; +import net.thucydides.core.annotations.Step; + +import java.io.UnsupportedEncodingException; + +import static io.restassured.module.mockmvc.RestAssuredMockMvc.given; +import static org.hamcrest.core.IsEqual.equalTo; + +/** + * @author aiet + */ +public class AdderRestSteps { + + private MockMvcResponse mockMvcResponse; + private int currentNum; + + @Step("get the current number") + public void givenCurrentNumber() throws UnsupportedEncodingException { + currentNum = Integer.valueOf(given() + .when() + .get("/adder/current") + .mvcResult() + .getResponse() + .getContentAsString()); + } + + @Step("adding {0}") + public void whenAddNumber(int num) { + mockMvcResponse = given() + .queryParam("num", num) + .when() + .post("/adder"); + currentNum += num; + } + + @Step("got the sum") + public void thenSummedUp() { + mockMvcResponse + .then() + .statusCode(200) + .body(equalTo(currentNum + "")); + } + +} diff --git a/libraries/src/test/java/com/baeldung/serenity/spring/steps/AdderServiceSteps.java b/libraries/src/test/java/com/baeldung/serenity/spring/steps/AdderServiceSteps.java new file mode 100644 index 0000000000..b8c2854bf0 --- /dev/null +++ b/libraries/src/test/java/com/baeldung/serenity/spring/steps/AdderServiceSteps.java @@ -0,0 +1,44 @@ +package com.baeldung.serenity.spring.steps; + +import com.baeldung.serenity.spring.AdderService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; + +/** + * @author aiet + */ +@ContextConfiguration(classes = AdderService.class) +public class AdderServiceSteps { + + @Autowired private AdderService adderService; + + private int givenNumber; + private int base; + private int sum; + + public void givenBaseAndAdder(int base, int adder) { + this.base = base; + adderService.baseNum(base); + this.givenNumber = adder; + } + + public void whenAdd() { + sum = adderService.add(givenNumber); + } + + public void summedUp() { + assertEquals(base + givenNumber, sum); + } + + public void sumWrong() { + assertNotEquals(base + givenNumber, sum); + } + + public void whenAccumulate() { + sum = adderService.accumulate(givenNumber); + } + +} diff --git a/libraries/src/test/java/com/baeldung/serenity/spring/steps/AdderSteps.java b/libraries/src/test/java/com/baeldung/serenity/spring/steps/AdderSteps.java new file mode 100644 index 0000000000..6d8d26673b --- /dev/null +++ b/libraries/src/test/java/com/baeldung/serenity/spring/steps/AdderSteps.java @@ -0,0 +1,29 @@ +package com.baeldung.serenity.spring.steps; + +import net.thucydides.core.annotations.Step; + +import static com.baeldung.serenity.spring.RandomNumberUtil.randomInt; + +/** + * @author aiet + */ +public class AdderSteps { + + int currentNumber; + int sum; + + @Step("given current number") + public void givenNumber() { + currentNumber = randomInt(); + } + + @Step("add up {0}") + public void whenAdd(int adder) { + sum = currentNumber + adder; + } + + @Step("summed up") + public void thenSummedUp() { + } + +} diff --git a/libraries/src/test/java/com/baeldung/serenity/spring/steps/KonamiCheatSteps.java b/libraries/src/test/java/com/baeldung/serenity/spring/steps/KonamiCheatSteps.java deleted file mode 100644 index 0bb408bda0..0000000000 --- a/libraries/src/test/java/com/baeldung/serenity/spring/steps/KonamiCheatSteps.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.baeldung.serenity.spring.steps; - -import net.thucydides.core.annotations.Step; - -import static org.junit.Assert.assertEquals; - -/** - * @author aiet - */ -public class KonamiCheatSteps { - - @Step("all stages of the game are cleared") - public void gameStageCleared() { - } - - @Step("input the classic 'Konami Code': {0} ") - public void cheatWith(String cheatcode) { - assertEquals("cheatcode wrong", "↑↑↓↓←→←→BA", cheatcode); - } - - @Step("there is still a stage left") - public void aStageRemains() { - } - -} diff --git a/libraries/src/test/java/com/baeldung/serenity/spring/steps/KonamiCodeConstructorDependencySteps.java b/libraries/src/test/java/com/baeldung/serenity/spring/steps/KonamiCodeConstructorDependencySteps.java deleted file mode 100644 index 2bec25b58f..0000000000 --- a/libraries/src/test/java/com/baeldung/serenity/spring/steps/KonamiCodeConstructorDependencySteps.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.baeldung.serenity.spring.steps; - -import com.baeldung.serenity.spring.KonamiCodeService; -import net.thucydides.core.annotations.Step; -import org.apache.commons.lang3.RandomStringUtils; - -import static org.hamcrest.core.IsEqual.equalTo; -import static org.junit.Assert.*; - -/** - * @author aiet - */ -public class KonamiCodeConstructorDependencySteps { - - private String latestCheatcode; - private boolean cheatSuccess; - - private KonamiCodeService konamiCodeService; - - public KonamiCodeConstructorDependencySteps(KonamiCodeService konamiCodeService) { - this.konamiCodeService = konamiCodeService; - } - - @Step("fetch latest cheat code") - public void fetchLatestCheatcode() { - latestCheatcode = konamiCodeService.getClassicCode(); - } - - @Step("cheat with latest code") - public void cheatWithLatestcode() { - cheatSuccess = konamiCodeService.cheatWith(latestCheatcode); - } - - @Step("all stages of the game are cleared") - public void gameStageCleared() { - konamiCodeService.clearStage(); - } - - @Step("there is still a stage left") - public void aStageRemains() { - assertTrue("cheatcode wrong", cheatSuccess); - assertThat(konamiCodeService.stageLeft(), equalTo(1)); - } - - // @Rule public SpringIntegrationMethodRule methodRule = new SpringIntegrationMethodRule(); - - // @DirtiesContext - @Step - public void letsHack() { - konamiCodeService.alterClassicCode(RandomStringUtils.random(4)); - } - - @Step("there is no stage left") - public void noStageRemains() { - assertFalse(cheatSuccess); - assertThat(konamiCodeService.stageLeft(), equalTo(0)); - } -} diff --git a/libraries/src/test/java/com/baeldung/serenity/spring/steps/KonamiCodeRestSteps.java b/libraries/src/test/java/com/baeldung/serenity/spring/steps/KonamiCodeRestSteps.java deleted file mode 100644 index 3f06d42414..0000000000 --- a/libraries/src/test/java/com/baeldung/serenity/spring/steps/KonamiCodeRestSteps.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.baeldung.serenity.spring.steps; - -import io.restassured.module.mockmvc.response.MockMvcResponse; -import net.thucydides.core.annotations.Step; - -import java.io.UnsupportedEncodingException; - -import static io.restassured.module.mockmvc.RestAssuredMockMvc.given; -import static org.hamcrest.core.IsEqual.equalTo; - -/** - * @author aiet - */ -public class KonamiCodeRestSteps { - - MockMvcResponse mockMvcResponse; - String cheatcode; - - @Step("get the classic cheat code") - public void givenClassicCheatCode() throws UnsupportedEncodingException { - cheatcode = given() - .when() - .get("/konamicode/classic") - .mvcResult() - .getResponse() - .getContentAsString(); - } - - @Step("check if the cheat code works") - public void whenCheat() { - mockMvcResponse = given() - .queryParam("cheatcode", cheatcode) - .when() - .get("/konamicode/cheatable"); - } - - @Step("classic cheat code matches") - public void thenClassicCodeCanDoTheTrick() { - mockMvcResponse - .then() - .statusCode(200) - .body(equalTo("true")); - } - - @Step("all stage cleared") - public void stageCleared() { - given() - .queryParam("action", "clear") - .when() - .put("/konamicode/stages"); - given() - .when() - .get("/konamicode/stages") - .then() - .body(equalTo("0")); - } - - @Step("one more stage to play") - public void thenMoreStages() { - given() - .when() - .get("/konamicode/stages") - .then() - .body(equalTo("1")); - } - -} - diff --git a/libraries/src/test/java/com/baeldung/serenity/spring/steps/KonamiCodeServiceInjectionSteps.java b/libraries/src/test/java/com/baeldung/serenity/spring/steps/KonamiCodeServiceInjectionSteps.java deleted file mode 100644 index b57186ba14..0000000000 --- a/libraries/src/test/java/com/baeldung/serenity/spring/steps/KonamiCodeServiceInjectionSteps.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.baeldung.serenity.spring.steps; - -import com.baeldung.serenity.spring.KonamiCodeService; -import net.thucydides.core.annotations.Step; -import org.apache.commons.lang3.RandomStringUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.context.ContextConfiguration; - -import static org.hamcrest.core.IsEqual.equalTo; -import static org.junit.Assert.*; - -/** - * @author aiet - */ -@ContextConfiguration(classes = KonamiCodeService.class) -public class KonamiCodeServiceInjectionSteps { - - private String latestCheatcode; - private boolean cheatSuccess; - - @Autowired private KonamiCodeService konamiCodeService; - - @Step("fetch latest cheat code") - public void fetchLatestCheatcode() { - latestCheatcode = konamiCodeService.getClassicCode(); - } - - @Step("cheat with latest code") - public void cheatWithLatestcode() { - cheatSuccess = konamiCodeService.cheatWith(latestCheatcode); - } - - @Step("all stages of the game are cleared") - public void gameStageCleared() { - konamiCodeService.clearStage(); - } - - @Step("there is still a stage left") - public void aStageRemains() { - assertTrue("cheatcode wrong", cheatSuccess); - assertThat(konamiCodeService.stageLeft(), equalTo(1)); - } - - @Step("altering default cheat code") - public void letsHack() { - konamiCodeService.alterClassicCode(RandomStringUtils.random(4)); - } - - @Step("there is no stage left") - public void noStageRemains() { - assertFalse(cheatSuccess); - assertThat(konamiCodeService.stageLeft(), equalTo(0)); - } - -} diff --git a/libraries/src/test/java/com/baeldung/serenity/spring/stories/AdderStory.java b/libraries/src/test/java/com/baeldung/serenity/spring/stories/AdderStory.java new file mode 100644 index 0000000000..b9fa8f1ae0 --- /dev/null +++ b/libraries/src/test/java/com/baeldung/serenity/spring/stories/AdderStory.java @@ -0,0 +1,31 @@ +package com.baeldung.serenity.spring.stories; + +import com.baeldung.serenity.spring.steps.AdderRestSteps; +import net.thucydides.core.annotations.Steps; +import org.jbehave.core.annotations.Given; +import org.jbehave.core.annotations.Then; +import org.jbehave.core.annotations.When; + +/** + * @author aiet + */ +public class AdderStory { + + @Steps AdderRestSteps restSteps; + + @Given("a number") + public void givenANumber() throws Exception { + restSteps.givenCurrentNumber(); + } + + @When("I submit another number $num to adder") + public void whenISubmitToAdderWithNumber(int num) { + restSteps.whenAddNumber(num); + } + + @Then("I get a sum of the numbers") + public void thenIGetTheSum() { + restSteps.thenSummedUp(); + } + +} diff --git a/libraries/src/test/java/com/baeldung/serenity/spring/stories/KonamiCodeStory.java b/libraries/src/test/java/com/baeldung/serenity/spring/stories/KonamiCodeStory.java deleted file mode 100644 index 090eb63215..0000000000 --- a/libraries/src/test/java/com/baeldung/serenity/spring/stories/KonamiCodeStory.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.baeldung.serenity.spring.stories; - -import com.baeldung.serenity.spring.steps.KonamiCodeRestSteps; -import net.thucydides.core.annotations.Steps; -import org.jbehave.core.annotations.Given; -import org.jbehave.core.annotations.Then; -import org.jbehave.core.annotations.When; - -/** - * @author aiet - */ -public class KonamiCodeStory { - - @Steps KonamiCodeRestSteps restSteps; - - @Given("game stage cleared") - public void givenStageCleared(){ - restSteps.stageCleared(); - } - - @Given("KONAMI cheat code") - public void givenKONAMICheatCode() throws Exception{ - restSteps.givenClassicCheatCode(); - } - - @When("I input the cheat code") - public void whenIInputTheCheatCode() { - restSteps.whenCheat(); - } - - @Then("a hidden stage will be unlocked") - public void thenAHiddenStageWillBeUnlocked() { - restSteps.thenClassicCodeCanDoTheTrick(); - restSteps.thenMoreStages(); - } - -} diff --git a/libraries/src/test/java/com/baeldung/stream/JoolMergeStreamsTest.java b/libraries/src/test/java/com/baeldung/stream/JoolMergeStreamsTest.java new file mode 100644 index 0000000000..e73861d8af --- /dev/null +++ b/libraries/src/test/java/com/baeldung/stream/JoolMergeStreamsTest.java @@ -0,0 +1,35 @@ +package com.baeldung.stream; + +import org.jooq.lambda.Seq; +import org.junit.Assert; +import org.junit.Test; + +import java.util.Arrays; + +import static junit.framework.TestCase.assertEquals; + +public class JoolMergeStreamsTest { + @Test + public void givenTwoStreams_whenMergingStreams_thenResultingStreamContainsElementsFromBothStreams() { + Seq seq1 = Seq.of(1, 3, 5); + Seq seq2 = Seq.of(2, 4, 6); + + Seq resultingSeq = seq1.append(seq2); + + assertEquals(Arrays.asList(1, 3, 5, 2, 4, 6), + resultingSeq.toList()); + } + + @Test + public void givenThreeStreams_whenAppendingAndPrependingStreams_thenResultingStreamContainsElementsFromAllStreams() { + Seq seq = Seq.of("foo", "bar"); + Seq openingBracketSeq = Seq.of("["); + Seq closingBracketSeq = Seq.of("]"); + + Seq resultingStream = seq.append(closingBracketSeq) + .prepend(openingBracketSeq); + + Assert.assertEquals(Arrays.asList("[", "foo", "bar", "]"), + resultingStream.toList()); + } +} \ No newline at end of file diff --git a/libraries/src/test/java/com/baeldung/stream/MergeStreamsTest.java b/libraries/src/test/java/com/baeldung/stream/MergeStreamsTest.java new file mode 100644 index 0000000000..217d2b5b64 --- /dev/null +++ b/libraries/src/test/java/com/baeldung/stream/MergeStreamsTest.java @@ -0,0 +1,53 @@ +package com.baeldung.stream; + +import org.junit.Test; + +import java.util.Arrays; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static org.junit.Assert.assertEquals; + +public class MergeStreamsTest { + + @Test + public void givenTwoStreams_whenMergingStreams_thenResultingStreamContainsElementsFromBothStreams() { + Stream stream1 = Stream.of(1, 3, 5); + Stream stream2 = Stream.of(2, 4, 6); + + Stream resultingStream = Stream.concat(stream1, + stream2); + + assertEquals(Arrays.asList(1, 3, 5, 2, 4, 6), + resultingStream.collect(Collectors.toList())); + } + + @Test + public void givenThreeStreams_whenMergingStreams_thenResultingStreamContainsElementsFromAllStreams() { + Stream stream1 = Stream.of(1, 3, 5); + Stream stream2 = Stream.of(2, 4, 6); + Stream stream3 = Stream.of(18, 15, 36); + + Stream resultingStream = Stream.concat(Stream.concat(stream1, + stream2), + stream3); + + assertEquals(Arrays.asList(1, 3, 5, 2, 4, 6, 18, 15, 36), + resultingStream.collect(Collectors.toList())); + } + + @Test + public void givenFourStreams_whenMergingStreams_thenResultingStreamContainsElementsFromAllStreams() { + Stream stream1 = Stream.of(1, 3, 5); + Stream stream2 = Stream.of(2, 4, 6); + Stream stream3 = Stream.of(18, 15, 36); + Stream stream4 = Stream.of(99); + + Stream resultingStream = Stream.of(stream1, stream2, stream3, stream4).flatMap(Function.identity()); + + assertEquals(Arrays.asList(1, 3, 5, 2, 4, 6, 18, 15, 36, 99), + resultingStream.collect(Collectors.toList())); + + } +} \ No newline at end of file diff --git a/libraries/src/test/java/com/baeldung/stream/StreamExMergeStreamsTest.java b/libraries/src/test/java/com/baeldung/stream/StreamExMergeStreamsTest.java new file mode 100644 index 0000000000..a964d76e8a --- /dev/null +++ b/libraries/src/test/java/com/baeldung/stream/StreamExMergeStreamsTest.java @@ -0,0 +1,51 @@ +package com.baeldung.stream; + +import one.util.streamex.StreamEx; +import org.junit.Test; + +import java.util.Arrays; + +import static org.junit.Assert.assertEquals; + +public class StreamExMergeStreamsTest { + + @Test + public void givenTwoStreams_whenMergingStreams_thenResultingStreamContainsElementsFromBothStreams() { + StreamEx stream1 = StreamEx.of(1, 3, 5); + StreamEx stream2 = StreamEx.of(2, 4, 6); + + StreamEx resultingStream = stream1.append(stream2); + + assertEquals(Arrays.asList(1, 3, 5, 2, 4, 6), + resultingStream.toList()); + } + + @Test + public void givenFourStreams_whenMergingStreams_thenResultingStreamContainsElementsFromAllStreams() { + StreamEx stream1 = StreamEx.of(1, 3, 5); + StreamEx stream2 = StreamEx.of(2, 4, 6); + StreamEx stream3 = StreamEx.of(18, 15, 36); + StreamEx stream4 = StreamEx.of(99); + + StreamEx resultingStream = stream1.append(stream2) + .append(stream3) + .append(stream4); + + assertEquals(Arrays.asList(1, 3, 5, 2, 4, 6, 18, 15, 36, 99), + resultingStream.toList()); + + } + + @Test + public void givenThreeStreams_whenAppendingAndPrependingStreams_thenResultingStreamContainsElementsFromAllStreams() { + StreamEx stream1 = StreamEx.of("foo", "bar"); + StreamEx openingBracketStream = StreamEx.of("["); + StreamEx closingBracketStream = StreamEx.of("]"); + + StreamEx resultingStream = stream1.append(closingBracketStream) + .prepend(openingBracketStream); + + assertEquals(Arrays.asList("[", "foo", "bar", "]"), + resultingStream.toList()); + } +} diff --git a/libraries/src/test/resources/JunitParamsTestParameters.csv b/libraries/src/test/resources/JunitParamsTestParameters.csv new file mode 100644 index 0000000000..84eb5a0b23 --- /dev/null +++ b/libraries/src/test/resources/JunitParamsTestParameters.csv @@ -0,0 +1,4 @@ +1,2,3 +-10, 30, 20 +15, -5, 10 +-5, -10, -15 \ No newline at end of file diff --git a/libraries/src/test/resources/konami-cheat-beans.xml b/libraries/src/test/resources/adder-beans.xml similarity index 82% rename from libraries/src/test/resources/konami-cheat-beans.xml rename to libraries/src/test/resources/adder-beans.xml index 221d058337..2fbdbd378f 100644 --- a/libraries/src/test/resources/konami-cheat-beans.xml +++ b/libraries/src/test/resources/adder-beans.xml @@ -3,11 +3,11 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> - - - ↑↑↓↓←→←→BA + + + 4 - + diff --git a/libraries/src/test/resources/stories/spring/adder_test.story b/libraries/src/test/resources/stories/spring/adder_test.story new file mode 100644 index 0000000000..e8de2cf076 --- /dev/null +++ b/libraries/src/test/resources/stories/spring/adder_test.story @@ -0,0 +1,11 @@ +Meta: + +Narrative: +As user +I want to add a number +So that I can have the sum + +Scenario: A user can submit a number to adder and get current sum +Given a number +When I submit another number 5 to adder +Then I get a sum of the numbers \ No newline at end of file diff --git a/libraries/src/test/resources/stories/spring/konami_code_test.story b/libraries/src/test/resources/stories/spring/konami_code_test.story deleted file mode 100644 index bba8ad7ade..0000000000 --- a/libraries/src/test/resources/stories/spring/konami_code_test.story +++ /dev/null @@ -1,12 +0,0 @@ -Meta: - -Narrative: -As a KONAMI player -I want to cheat -So that I can unlock hidden stages of the game - -Scenario: A KONAMI player can use the cheatcode to unlock hidden stages -Given game stage cleared -And KONAMI cheat code -When I input the cheat code -Then a hidden stage will be unlocked \ No newline at end of file diff --git a/mustache/pom.xml b/mustache/pom.xml new file mode 100644 index 0000000000..d5d80b58e9 --- /dev/null +++ b/mustache/pom.xml @@ -0,0 +1,57 @@ + + + 4.0.0 + mustache + 0.0.1-SNAPSHOT + jar + mustache + + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + + + + + com.github.spullara.mustache.java + compiler + ${mustache.compiler.api.version} + + + + org.assertj + assertj-core + ${assertj.version} + + + + + log4j + log4j + ${log4j.version} + + + junit + junit + ${junit.version} + test + + + + + + 0.9.2 + 3.7.0 + 1.2.16 + 4.12 + + UTF-8 + + + 3.6.0 + 2.19.1 + + + \ No newline at end of file diff --git a/mustache/src/main/java/com/baeldung/mustache/MustacheUtil.java b/mustache/src/main/java/com/baeldung/mustache/MustacheUtil.java new file mode 100644 index 0000000000..a30bb23adb --- /dev/null +++ b/mustache/src/main/java/com/baeldung/mustache/MustacheUtil.java @@ -0,0 +1,15 @@ +package com.baeldung.mustache; + +import com.github.mustachejava.DefaultMustacheFactory; +import com.github.mustachejava.MustacheFactory; + +public class MustacheUtil { + + private static final MustacheFactory mf = new DefaultMustacheFactory(); + + public static MustacheFactory getMustacheFactory(){ + return mf; + } + + +} diff --git a/mustache/src/main/java/com/baeldung/mustache/model/Todo.java b/mustache/src/main/java/com/baeldung/mustache/model/Todo.java new file mode 100644 index 0000000000..cf845a3227 --- /dev/null +++ b/mustache/src/main/java/com/baeldung/mustache/model/Todo.java @@ -0,0 +1,77 @@ +package com.baeldung.mustache.model; + +import java.time.Duration; +import java.util.Date; +import java.util.function.Function; + +public class Todo { + + public Todo() { + } + + public Todo(String title, String text) { + this.title = title; + this.text = text; + createdOn = new Date(); + } + + private String title; + private String text; + private boolean done = false; + + private Date createdOn; + private Date completedOn; + + public void markAsDone() { + done = true; + completedOn = new Date(); + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } + + public boolean getDone() { + return done; + } + + public Date getCreatedOn() { + return createdOn; + } + + public Date getCompletedOn() { + return completedOn; + } + + public void setDone(boolean done) { + this.done = done; + } + + public void setCompletedOn(Date completedOn) { + this.completedOn = completedOn; + } + + public long doneSince() { + return done ? Duration + .between(createdOn.toInstant(), completedOn.toInstant()) + .toMinutes() : 0; + } + + public Function handleDone() { + return (obj) -> done ? String.format("Done %s minutes ago", obj) : ""; + + } + +} diff --git a/mustache/src/main/resources/todo-section.mustache b/mustache/src/main/resources/todo-section.mustache new file mode 100644 index 0000000000..f05be6f553 --- /dev/null +++ b/mustache/src/main/resources/todo-section.mustache @@ -0,0 +1,5 @@ +{{#todo}} +

{{title}}

+Created on {{createdOn}} +

{{text}}

+{{/todo}} diff --git a/mustache/src/main/resources/todo.mustache b/mustache/src/main/resources/todo.mustache new file mode 100644 index 0000000000..5cd7a99ff5 --- /dev/null +++ b/mustache/src/main/resources/todo.mustache @@ -0,0 +1,3 @@ +

{{title}}

+Created on {{createdOn}} +

{{text}}

\ No newline at end of file diff --git a/mustache/src/main/resources/todos-inverted-section.mustache b/mustache/src/main/resources/todos-inverted-section.mustache new file mode 100644 index 0000000000..5d3cd16c73 --- /dev/null +++ b/mustache/src/main/resources/todos-inverted-section.mustache @@ -0,0 +1,6 @@ +{{#todos}} +

{{title}}

+{{/todos}} +{{^todos}} +

No todos!

+{{/todos}} \ No newline at end of file diff --git a/mustache/src/main/resources/todos-lambda.mustache b/mustache/src/main/resources/todos-lambda.mustache new file mode 100644 index 0000000000..c89a7bc4c5 --- /dev/null +++ b/mustache/src/main/resources/todos-lambda.mustache @@ -0,0 +1,3 @@ +{{#todos}} +

{{title}}{{#handleDone}}{{doneSince}}{{/handleDone}}

+{{/todos}} \ No newline at end of file diff --git a/mustache/src/main/resources/todos.mustache b/mustache/src/main/resources/todos.mustache new file mode 100644 index 0000000000..90722e74bb --- /dev/null +++ b/mustache/src/main/resources/todos.mustache @@ -0,0 +1,3 @@ +{{#todos}} +

{{title}}

+{{/todos}} \ No newline at end of file diff --git a/mustache/src/test/java/com/baeldung/mustache/TodoMustacheServiceTest.java b/mustache/src/test/java/com/baeldung/mustache/TodoMustacheServiceTest.java new file mode 100644 index 0000000000..17a59aa6a1 --- /dev/null +++ b/mustache/src/test/java/com/baeldung/mustache/TodoMustacheServiceTest.java @@ -0,0 +1,102 @@ +package com.baeldung.mustache; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.IOException; +import java.io.StringWriter; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.temporal.TemporalUnit; +import java.util.Arrays; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +import org.junit.Test; + +import com.baeldung.mustache.model.Todo; +import com.github.mustachejava.Mustache; +public class TodoMustacheServiceTest { + + private String executeTemplate(Mustache m, Map context) throws IOException{ + StringWriter writer = new StringWriter(); + m.execute(writer, context).flush(); + return writer.toString(); + } + + private String executeTemplate(Mustache m, Todo todo) throws IOException{ + StringWriter writer = new StringWriter(); + m.execute(writer, todo).flush(); + return writer.toString(); + } + + @Test + public void givenTodoObject_whenGetHtml_thenSuccess() throws IOException{ + Todo todo = new Todo("Todo 1", "Todo description"); + Mustache m = MustacheUtil.getMustacheFactory().compile("todo.mustache"); + Map context = new HashMap<>(); + context.put("todo", todo); + + String expected = "

Todo 1

"; + assertThat(executeTemplate(m, todo)).contains(expected); + } + + @Test + public void givenNullTodoObject_whenGetHtml_thenEmptyHtml() throws IOException{ + Mustache m = MustacheUtil.getMustacheFactory().compile("todo-section.mustache"); + Map context = new HashMap<>(); + assertThat(executeTemplate(m, context)).isEmpty(); + } + + @Test + public void givenTodoList_whenGetHtml_thenSuccess() throws IOException{ + Mustache m = MustacheUtil.getMustacheFactory().compile("todos.mustache"); + + List todos = Arrays.asList( + new Todo("Todo 1", "Todo description"), + new Todo("Todo 2", "Todo description another"), + new Todo("Todo 3", "Todo description another") + ); + Map context = new HashMap<>(); + context.put("todos", todos); + + assertThat(executeTemplate(m, context)) + .contains("

Todo 1

") + .contains("

Todo 2

") + .contains("

Todo 3

"); + } + + @Test + public void givenEmptyList_whenGetHtml_thenEmptyHtml() throws IOException{ + Mustache m = MustacheUtil.getMustacheFactory().compile("todos.mustache"); + + Map context = new HashMap<>(); + assertThat(executeTemplate(m, context)).isEmpty();; + } + + @Test + public void givenEmptyList_whenGetHtmlUsingInvertedSection_thenHtml() throws IOException{ + Mustache m = MustacheUtil.getMustacheFactory().compile("todos-inverted-section.mustache"); + + Map context = new HashMap<>(); + assertThat(executeTemplate(m, context).trim()).isEqualTo("

No todos!

"); + } + + @Test + public void givenTodoList_whenGetHtmlUsingLamdba_thenHtml() throws IOException{ + Mustache m = MustacheUtil.getMustacheFactory().compile("todos-lambda.mustache"); + List todos = Arrays.asList( + new Todo("Todo 1", "Todo description"), + new Todo("Todo 2", "Todo description another"), + new Todo("Todo 3", "Todo description another") + ); + todos.get(2).setDone(true); + todos.get(2).setCompletedOn(Date.from(Instant.now().plusSeconds(300))); + + Map context = new HashMap<>(); + context.put("todos", todos); + assertThat(executeTemplate(m, context).trim()).contains("Done 5 minutes ago"); + } +} diff --git a/mybatis/README.md b/mybatis/README.md new file mode 100644 index 0000000000..7c366aeab6 --- /dev/null +++ b/mybatis/README.md @@ -0,0 +1,2 @@ +### Relevant Articles: +- [Quick Guide to MyBatis](http://www.baeldung.com/mybatis) diff --git a/pom.xml b/pom.xml index 609d69c3ea..e6e11326d7 100644 --- a/pom.xml +++ b/pom.xml @@ -100,6 +100,7 @@ mockito mockito2 mocks + mustache orika @@ -120,7 +121,8 @@ selenium-junit-testng solr spark-java - spring-5 + spring-5 + spring-5-mvc spring-akka spring-amqp spring-all @@ -128,6 +130,7 @@ spring-apache-camel spring-batch spring-boot + spring-boot-kotlin spring-cloud-data-flow spring-cloud spring-core diff --git a/spring-5-mvc/.gitignore b/spring-5-mvc/.gitignore new file mode 100644 index 0000000000..b7b5c734f2 --- /dev/null +++ b/spring-5-mvc/.gitignore @@ -0,0 +1,20 @@ +*.class + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +.settings/ +.classpath +.project +target/ + +*.iml +.idea + +# Package Files # +*.jar +*.war +*.ear + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* diff --git a/spring-5-mvc/pom.xml b/spring-5-mvc/pom.xml new file mode 100644 index 0000000000..b8c341afde --- /dev/null +++ b/spring-5-mvc/pom.xml @@ -0,0 +1,154 @@ + + + 4.0.0 + + com.baeldung + spring-5-mvc + 0.0.1-SNAPSHOT + jar + + spring-5-mvc + spring 5 MVC sample project about new features + + + org.springframework.boot + spring-boot-starter-parent + 2.0.0.M1 + + + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.boot + spring-boot-starter-validation + + + org.springframework.boot + spring-boot-starter-web + + + + + + org.apache.commons + commons-lang3 + + + org.slf4j + slf4j-api + + + org.slf4j + jcl-over-slf4j + + + + + + org.springframework.boot + spring-boot-devtools + runtime + + + com.h2database + h2 + runtime + + + + org.springframework + spring-test + + + org.springframework.boot + spring-boot-starter-test + test + + + + junit + junit + test + + + + com.jayway.restassured + rest-assured + ${rest-assured.version} + test + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + true + false + + **/*IntegrationTest.java + **/*LiveTest.java + + + + + + + + + + spring-snapshots + Spring Snapshots + https://repo.spring.io/snapshot + + true + + + + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + + false + + + + + + spring-snapshots + Spring Snapshots + https://repo.spring.io/snapshot + + true + + + + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + + false + + + + + + 2.9.0 + UTF-8 + UTF-8 + 1.8 + + + diff --git a/spring-5-mvc/src/main/java/com/baeldung/Spring5Application.java b/spring-5-mvc/src/main/java/com/baeldung/Spring5Application.java new file mode 100644 index 0000000000..41b5c1eed1 --- /dev/null +++ b/spring-5-mvc/src/main/java/com/baeldung/Spring5Application.java @@ -0,0 +1,13 @@ +package com.baeldung; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Spring5Application { + + public static void main(String[] args) { + SpringApplication.run(Spring5Application.class, args); + } + +} diff --git a/spring-5-mvc/src/main/java/com/baeldung/model/Foo.java b/spring-5-mvc/src/main/java/com/baeldung/model/Foo.java new file mode 100644 index 0000000000..a9ffee14da --- /dev/null +++ b/spring-5-mvc/src/main/java/com/baeldung/model/Foo.java @@ -0,0 +1,84 @@ +package com.baeldung.model; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; + +@Entity +public class Foo { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private Long id; + + private String name; + + public Foo() { + super(); + } + + public Foo(final String name) { + super(); + + this.name = name; + } + + public Foo(final long id, final String name) { + super(); + + this.id = id; + this.name = name; + } + + // API + + public String getName() { + return name; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public void setName(final String name) { + this.name = name; + } + + // + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((name == null) ? 0 : name.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Foo other = (Foo) obj; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + return true; + } + + @Override + public String toString() { + return "Foo [name=" + name + "]"; + } + +} \ No newline at end of file diff --git a/spring-5-mvc/src/main/java/com/baeldung/persistence/DataSetupBean.java b/spring-5-mvc/src/main/java/com/baeldung/persistence/DataSetupBean.java new file mode 100644 index 0000000000..cf78977961 --- /dev/null +++ b/spring-5-mvc/src/main/java/com/baeldung/persistence/DataSetupBean.java @@ -0,0 +1,26 @@ +package com.baeldung.persistence; + +import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic; + +import java.util.stream.IntStream; + +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.baeldung.model.Foo; + +@Component +public class DataSetupBean implements InitializingBean { + + @Autowired + private FooRepository repo; + + // + + @Override + public void afterPropertiesSet() throws Exception { + IntStream.range(1, 5).forEach(i -> repo.save(new Foo(randomAlphabetic(8)))); + } + +} diff --git a/spring-5-mvc/src/main/java/com/baeldung/persistence/FooRepository.java b/spring-5-mvc/src/main/java/com/baeldung/persistence/FooRepository.java new file mode 100644 index 0000000000..3c70f38fce --- /dev/null +++ b/spring-5-mvc/src/main/java/com/baeldung/persistence/FooRepository.java @@ -0,0 +1,10 @@ +package com.baeldung.persistence; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +import com.baeldung.model.Foo; + +public interface FooRepository extends JpaRepository, JpaSpecificationExecutor { + +} diff --git a/spring-5-mvc/src/main/java/com/baeldung/web/FooController.java b/spring-5-mvc/src/main/java/com/baeldung/web/FooController.java new file mode 100644 index 0000000000..137864cddd --- /dev/null +++ b/spring-5-mvc/src/main/java/com/baeldung/web/FooController.java @@ -0,0 +1,66 @@ +package com.baeldung.web; + +import java.util.List; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.PageRequest; +import org.springframework.http.HttpStatus; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.server.ResponseStatusException; + +import com.baeldung.model.Foo; +import com.baeldung.persistence.FooRepository; + +@RestController +public class FooController { + + @Autowired + private FooRepository repo; + + // API - read + + @GetMapping("/foos/{id}") + @Validated + public Foo findById(@PathVariable @Min(0) final long id) { + return repo.findById(id).orElse(null); + } + + @GetMapping("/foos") + public List findAll() { + return repo.findAll(); + } + + @GetMapping( value="/foos", params = { "page", "size" }) + @Validated + public List findPaginated(@RequestParam("page") @Min(0) final int page, @Max(100) @RequestParam("size") final int size) { + return repo.findAll(PageRequest.of(page, size)).getContent(); + } + + // API - write + + @PutMapping("/foos/{id}") + @ResponseStatus(HttpStatus.OK) + public Foo update(@PathVariable("id") final String id, @RequestBody final Foo foo) { + return foo; + } + + @PostMapping("/foos") + @ResponseStatus(HttpStatus.CREATED) + public void create( @RequestBody final Foo foo) { + if (null == foo || null == foo.getName()) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST," 'name' is required"); + } + repo.save(foo); + } +} \ No newline at end of file diff --git a/spring-5-mvc/src/main/resources/application.properties b/spring-5-mvc/src/main/resources/application.properties new file mode 100644 index 0000000000..886ea1978b --- /dev/null +++ b/spring-5-mvc/src/main/resources/application.properties @@ -0,0 +1,6 @@ +server.port=8081 + +security.user.name=user +security.user.password=pass + +logging.level.root=INFO \ No newline at end of file diff --git a/spring-5-mvc/src/main/webapp/WEB-INF/web.xml b/spring-5-mvc/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000000..bfcf43dad2 --- /dev/null +++ b/spring-5-mvc/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,21 @@ + + + + Spring Functional Application + + + functional + com.baeldung.functional.RootServlet + 1 + true + + + functional + / + + + + \ No newline at end of file diff --git a/spring-5-mvc/src/test/java/com/baeldung/test/LiveTest.java b/spring-5-mvc/src/test/java/com/baeldung/test/LiveTest.java new file mode 100644 index 0000000000..f6dd921b25 --- /dev/null +++ b/spring-5-mvc/src/test/java/com/baeldung/test/LiveTest.java @@ -0,0 +1,54 @@ +package com.baeldung.test; + +import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic; +import static org.junit.Assert.assertEquals; + +import org.junit.Test; +import org.springframework.http.MediaType; + +import com.jayway.restassured.RestAssured; +import com.jayway.restassured.response.Response; +import com.jayway.restassured.specification.RequestSpecification; + +public class LiveTest { + + private static String APP_ROOT = "http://localhost:8081"; + + + @Test + public void givenUser_whenResourceCreatedWithNullName_then400BadRequest() { + final Response response = givenAuth("user", "pass").contentType(MediaType.APPLICATION_JSON.toString()).body(resourceWithNullName()).post(APP_ROOT + "/foos"); + assertEquals(400, response.getStatusCode()); + } + + @Test + public void givenUser_whenResourceCreated_then201Created() { + final Response response = givenAuth("user", "pass").contentType(MediaType.APPLICATION_JSON.toString()).body(resourceString()).post(APP_ROOT + "/foos"); + assertEquals(201, response.getStatusCode()); + } + + /*@Test + public void givenUser_whenGetAllFoos_thenOK() { + final Response response = givenAuth("user", "pass").get(APP_ROOT + "/foos"); + assertEquals(200, response.getStatusCode()); + }*/ + + + + // + + private final String resourceWithNullName() { + final String roleData = "{\"name\":null}"; + return roleData; + } + + private final String resourceString() { + final String roleData = "{\"name\":\"" + randomAlphabetic(8) + "\"}"; + return roleData; + } + + private final RequestSpecification givenAuth(String username, String password) { + return RestAssured.given().auth().preemptive().basic(username, password); + } + +} \ No newline at end of file diff --git a/spring-5-mvc/src/test/java/com/baeldung/test/Spring5ApplicationIntegrationTest.java b/spring-5-mvc/src/test/java/com/baeldung/test/Spring5ApplicationIntegrationTest.java new file mode 100644 index 0000000000..c3790333ff --- /dev/null +++ b/spring-5-mvc/src/test/java/com/baeldung/test/Spring5ApplicationIntegrationTest.java @@ -0,0 +1,18 @@ +package com.baeldung.test; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import com.baeldung.Spring5Application; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = Spring5Application.class) +public class Spring5ApplicationIntegrationTest { + + @Test + public void contextLoads() { + } + +} diff --git a/spring-5/pom.xml b/spring-5/pom.xml index 63014d6e51..605dbe39e1 100644 --- a/spring-5/pom.xml +++ b/spring-5/pom.xml @@ -14,7 +14,7 @@ org.springframework.boot spring-boot-starter-parent - 2.0.0.BUILD-SNAPSHOT + 2.0.0.M1 diff --git a/spring-amqp-simple/README.md b/spring-amqp-simple/README.md new file mode 100644 index 0000000000..a176247d4c --- /dev/null +++ b/spring-amqp-simple/README.md @@ -0,0 +1,2 @@ +### Relevant Articles: +- [RabbitMQ Message Dispatching with Spring AMQP](http://www.baeldung.com/rabbitmq-spring-amqp) diff --git a/spring-boot-custom-starter/README.md b/spring-boot-custom-starter/README.md new file mode 100644 index 0000000000..5b05394d6e --- /dev/null +++ b/spring-boot-custom-starter/README.md @@ -0,0 +1,2 @@ +### Relevant Articles: +- [Creating a Custom Starter with Spring Boot](http://www.baeldung.com/spring-boot-custom-starter) diff --git a/spring-boot-kotlin/pom.xml b/spring-boot-kotlin/pom.xml new file mode 100644 index 0000000000..c882daa816 --- /dev/null +++ b/spring-boot-kotlin/pom.xml @@ -0,0 +1,137 @@ + + + 4.0.0 + + + org.springframework.boot + spring-boot-starter-parent + 2.0.0.BUILD-SNAPSHOT + + + +spring-boot-kotlin +1.0.0-SNAPSHOT + + + true + UTF-8 + UTF-8 + 1.8 + 1.1.2 + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.jetbrains.kotlin + kotlin-stdlib-jre8 + ${kotlin.version} + + + org.jetbrains.kotlin + kotlin-reflect + ${kotlin.version} + + + com.fasterxml.jackson.module + jackson-module-kotlin + 2.8.7 + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + ${project.basedir}/src/main/kotlin + ${project.basedir}/src/test/kotlin + + + org.springframework.boot + spring-boot-maven-plugin + + + kotlin-maven-plugin + org.jetbrains.kotlin + ${kotlin.version} + + + spring + + 1.8 + + + + compile + compile + + compile + + + + test-compile + test-compile + + test-compile + + + + + + org.jetbrains.kotlin + kotlin-maven-allopen + ${kotlin.version} + + + + + + + + + spring-snapshots + Spring Snapshots + https://repo.spring.io/snapshot + + true + + + + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + + false + + + + + + + spring-snapshots + Spring Snapshots + https://repo.spring.io/snapshot + + true + + + + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + + false + + + + + \ No newline at end of file diff --git a/spring-boot-kotlin/src/main/kotlin/com/baeldung/springbootkotlin/HelloController.kt b/spring-boot-kotlin/src/main/kotlin/com/baeldung/springbootkotlin/HelloController.kt new file mode 100644 index 0000000000..02b57bac5f --- /dev/null +++ b/spring-boot-kotlin/src/main/kotlin/com/baeldung/springbootkotlin/HelloController.kt @@ -0,0 +1,23 @@ +package com.baeldung.springbootkotlin + +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.RestController + +@RestController +class HelloController constructor(val helloService: HelloService) { + + @GetMapping("/hello") + fun helloKotlin(): String { + return "hello world" + } + + @GetMapping("/hello-service") + fun helloKotlinService(): String { + return helloService.getHello() + } + + @GetMapping("/hello-dto") + fun helloDto(): HelloDto { + return HelloDto("Hello from the dto") + } +} \ No newline at end of file diff --git a/spring-boot-kotlin/src/main/kotlin/com/baeldung/springbootkotlin/HelloDto.kt b/spring-boot-kotlin/src/main/kotlin/com/baeldung/springbootkotlin/HelloDto.kt new file mode 100644 index 0000000000..3f0139b5a9 --- /dev/null +++ b/spring-boot-kotlin/src/main/kotlin/com/baeldung/springbootkotlin/HelloDto.kt @@ -0,0 +1,3 @@ +package com.baeldung.springbootkotlin + +data class HelloDto constructor(val greeting: String) diff --git a/spring-boot-kotlin/src/main/kotlin/com/baeldung/springbootkotlin/HelloService.kt b/spring-boot-kotlin/src/main/kotlin/com/baeldung/springbootkotlin/HelloService.kt new file mode 100644 index 0000000000..c988b64e05 --- /dev/null +++ b/spring-boot-kotlin/src/main/kotlin/com/baeldung/springbootkotlin/HelloService.kt @@ -0,0 +1,10 @@ +package com.baeldung.springbootkotlin + +import org.springframework.stereotype.Service + +@Service +class HelloService { + fun getHello(): String { + return "hello service" + } +} \ No newline at end of file diff --git a/spring-boot-kotlin/src/main/kotlin/com/baeldung/springbootkotlin/KotlinDemoApplication.kt b/spring-boot-kotlin/src/main/kotlin/com/baeldung/springbootkotlin/KotlinDemoApplication.kt new file mode 100644 index 0000000000..dbe5694b6d --- /dev/null +++ b/spring-boot-kotlin/src/main/kotlin/com/baeldung/springbootkotlin/KotlinDemoApplication.kt @@ -0,0 +1,11 @@ +package com.baeldung.springbootkotlin + +import org.springframework.boot.SpringApplication +import org.springframework.boot.autoconfigure.SpringBootApplication + +@SpringBootApplication +class KotlinDemoApplication + +fun main(args: Array) { + SpringApplication.run(KotlinDemoApplication::class.java, *args) +} diff --git a/spring-boot-kotlin/src/main/resource/application.properties b/spring-boot-kotlin/src/main/resource/application.properties new file mode 100644 index 0000000000..e69de29bb2 diff --git a/spring-boot-kotlin/src/test/kotlin/springbootkotlin/KotlinDemoApplicationTests.kt b/spring-boot-kotlin/src/test/kotlin/springbootkotlin/KotlinDemoApplicationTests.kt new file mode 100644 index 0000000000..15ddc916e2 --- /dev/null +++ b/spring-boot-kotlin/src/test/kotlin/springbootkotlin/KotlinDemoApplicationTests.kt @@ -0,0 +1,52 @@ +package com.example.kotlindemo + +import com.baeldung.springbootkotlin.HelloDto +import com.baeldung.springbootkotlin.KotlinDemoApplication +import org.junit.Assert +import org.junit.Test +import org.junit.runner.RunWith +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.boot.test.web.client.TestRestTemplate +import org.springframework.http.HttpStatus +import org.springframework.test.context.junit4.SpringRunner + +@RunWith(SpringRunner::class) +@SpringBootTest(classes = arrayOf(KotlinDemoApplication::class), webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +class KotlinDemoApplicationTests { + + @Autowired + val testRestTemplate: TestRestTemplate? = null + + @Test + fun contextLoads() { + } + + @Test + fun testHelloController() { + var result = testRestTemplate?.getForEntity("/hello", String::class.java) + + Assert.assertNotNull(result) + Assert.assertEquals(result?.statusCode, HttpStatus.OK) + Assert.assertEquals(result?.body, "hello world") + } + + @Test + fun testHelloService() { + var result = testRestTemplate?.getForEntity("/hello-service", String::class.java) + + Assert.assertNotNull(result) + Assert.assertEquals(result?.statusCode, HttpStatus.OK) + Assert.assertEquals(result?.body, "hello service") + } + + @Test + fun testHelloDto() { + var result = testRestTemplate?.getForEntity("/hello-dto", HelloDto::class.java) + + Assert.assertNotNull(result) + Assert.assertEquals(result?.statusCode, HttpStatus.OK) + Assert.assertEquals(result?.body, HelloDto("Hello from the dto")) + } + +} diff --git a/spring-boot/README.MD b/spring-boot/README.MD index a1168106cb..4199b43e9a 100644 --- a/spring-boot/README.MD +++ b/spring-boot/README.MD @@ -21,3 +21,5 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring - [Custom Information in Spring Boot Info Endpoint](http://www.baeldung.com/spring-boot-info-actuator-custom) - [Using @JsonComponent in Spring Boot](http://www.baeldung.com/spring-boot-jsoncomponent) - [Create a Custom Auto-Configuration with Spring Boot](http://www.baeldung.com/spring-boot-custom-auto-configuration) +- [Testing in Spring Boot](http://www.baeldung.com/spring-boot-testing) +- [Guide to @ConfigurationProperties in Spring Boot](http://www.baeldung.com/configuration-properties-in-spring-boot) diff --git a/spring-cloud/README.md b/spring-cloud/README.md index 2ffb3a86d0..1b793144b1 100644 --- a/spring-cloud/README.md +++ b/spring-cloud/README.md @@ -18,3 +18,4 @@ ### Relevant Articles: - [Introduction to Spring Cloud Rest Client with Netflix Ribbon](http://www.baeldung.com/spring-cloud-rest-client-with-netflix-ribbon) + [An Introduction to Spring Cloud Zookeeper](http://www.baeldung.com/spring-cloud-zookeeper) diff --git a/spring-core/pom.xml b/spring-core/pom.xml index 16984a387b..70002bf3c1 100644 --- a/spring-core/pom.xml +++ b/spring-core/pom.xml @@ -58,6 +58,12 @@ lombok ${lombok.version} + + org.springframework.boot + spring-boot-test + ${mockito.spring.boot.version} + test + @@ -112,6 +118,7 @@ 1.10.19 + 1.4.4.RELEASE 4.3.4.RELEASE 1 20.0 diff --git a/spring-core/src/main/java/com/baeldung/beaninjection/FileReader.java b/spring-core/src/main/java/com/baeldung/beaninjection/FileReader.java new file mode 100644 index 0000000000..7ea64e2ce6 --- /dev/null +++ b/spring-core/src/main/java/com/baeldung/beaninjection/FileReader.java @@ -0,0 +1,19 @@ +package com.baeldung.beaninjection; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class FileReader { + + @Autowired + private Location location; + + public Location getLocation() { + return location; + } + + public void setLocation(Location location) { + this.location = location; + } +} diff --git a/spring-core/src/main/java/com/baeldung/beaninjection/FtpReader.java b/spring-core/src/main/java/com/baeldung/beaninjection/FtpReader.java new file mode 100644 index 0000000000..259710ce94 --- /dev/null +++ b/spring-core/src/main/java/com/baeldung/beaninjection/FtpReader.java @@ -0,0 +1,28 @@ +package com.baeldung.beaninjection; + +public class FtpReader { + private String ftpHost = null; + private Integer ftpPort = null; + + // Constructor with arguments + public FtpReader(String host, Integer port) { + this.ftpHost = host; + this.ftpPort = port; + } + + public String getFtpHost() { + return ftpHost; + } + + public void setFtpHost(String ftpHost) { + this.ftpHost = ftpHost; + } + + public Integer getFtpPort() { + return ftpPort; + } + + public void setFtpPort(Integer ftpPort) { + this.ftpPort = ftpPort; + } +} diff --git a/spring-core/src/main/java/com/baeldung/beaninjection/Location.java b/spring-core/src/main/java/com/baeldung/beaninjection/Location.java new file mode 100644 index 0000000000..9ecab83ef6 --- /dev/null +++ b/spring-core/src/main/java/com/baeldung/beaninjection/Location.java @@ -0,0 +1,17 @@ +package com.baeldung.beaninjection; + +import org.springframework.stereotype.Component; + +@Component +public class Location { + private String filePath; + + public String getFilePath() { + return filePath; + } + + public void setFilePath(String filePath) { + this.filePath = filePath; + } + +} diff --git a/spring-core/src/main/java/com/baeldung/beaninjection/ReaderApplicationConfig.java b/spring-core/src/main/java/com/baeldung/beaninjection/ReaderApplicationConfig.java new file mode 100644 index 0000000000..cf4d91b1f5 --- /dev/null +++ b/spring-core/src/main/java/com/baeldung/beaninjection/ReaderApplicationConfig.java @@ -0,0 +1,15 @@ +package com.baeldung.beaninjection; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ComponentScan(basePackages = { "com.baeldung.beaninjection" }) +public class ReaderApplicationConfig { + + @Bean + public FtpReader exampleDAO() { + return new FtpReader("localhost", 21); + } +} diff --git a/spring-core/src/main/java/com/baeldung/beaninjection/ReaderManager.java b/spring-core/src/main/java/com/baeldung/beaninjection/ReaderManager.java new file mode 100644 index 0000000000..155f2d6eea --- /dev/null +++ b/spring-core/src/main/java/com/baeldung/beaninjection/ReaderManager.java @@ -0,0 +1,33 @@ +package com.baeldung.beaninjection; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class ReaderManager { + private FileReader fileReader; + private FtpReader ftpReader; + + @Autowired + public ReaderManager(FtpReader ftpReader) { + this.ftpReader = ftpReader; + } + + @Autowired + public void setFileReader(FileReader fileReader) { + this.fileReader = fileReader; + } + + public FileReader getFileReader() { + return fileReader; + } + + public void setFtpReader(FtpReader ftpReader) { + this.ftpReader = ftpReader; + } + + public FtpReader getFtpReader() { + return ftpReader; + } + +} diff --git a/spring-core/src/main/java/com/baeldung/beaninjection/ReaderService.java b/spring-core/src/main/java/com/baeldung/beaninjection/ReaderService.java new file mode 100644 index 0000000000..60bdac61e5 --- /dev/null +++ b/spring-core/src/main/java/com/baeldung/beaninjection/ReaderService.java @@ -0,0 +1,14 @@ +package com.baeldung.beaninjection; + +public class ReaderService { + private FtpReader ftpReader; + + public void setFtpReader(FtpReader reader) { + this.ftpReader = reader; + } + + public FtpReader getFtpReader() { + return ftpReader; + } + +} diff --git a/spring-core/src/main/java/com/baeldung/value/ClassNotManagedBySpring.java b/spring-core/src/main/java/com/baeldung/value/ClassNotManagedBySpring.java new file mode 100644 index 0000000000..0329769d3c --- /dev/null +++ b/spring-core/src/main/java/com/baeldung/value/ClassNotManagedBySpring.java @@ -0,0 +1,28 @@ +package com.baeldung.value; + +public class ClassNotManagedBySpring { + + private String customVariable; + private String anotherCustomVariable; + + public ClassNotManagedBySpring(String someInitialValue, String anotherManagedValue) { + this.customVariable = someInitialValue; + this.anotherCustomVariable = anotherManagedValue; + } + + public String getCustomVariable() { + return customVariable; + } + + public void setCustomVariable(String customVariable) { + this.customVariable = customVariable; + } + + public String getAnotherCustomVariable() { + return anotherCustomVariable; + } + + public void setAnotherCustomVariable(String anotherCustomVariable) { + this.anotherCustomVariable = anotherCustomVariable; + } +} diff --git a/spring-core/src/main/java/com/baeldung/value/InitializerBean.java b/spring-core/src/main/java/com/baeldung/value/InitializerBean.java new file mode 100644 index 0000000000..8c8634c767 --- /dev/null +++ b/spring-core/src/main/java/com/baeldung/value/InitializerBean.java @@ -0,0 +1,21 @@ +package com.baeldung.value; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class InitializerBean { + + private String someInitialValue; + private String anotherManagedValue; + + public InitializerBean(@Value("someInitialValue") String someInitialValue, @Value("anotherValue") String anotherManagedValue) { + this.someInitialValue = someInitialValue; + this.anotherManagedValue = anotherManagedValue; + } + + public ClassNotManagedBySpring initClass() { + return new ClassNotManagedBySpring(this.someInitialValue, this.anotherManagedValue); + } + +} diff --git a/spring-core/src/main/resources/application.properties b/spring-core/src/main/resources/application.properties new file mode 100644 index 0000000000..fdc6536237 --- /dev/null +++ b/spring-core/src/main/resources/application.properties @@ -0,0 +1,2 @@ +someInitialValue=This is only sample value +anotherValue=Another configured value \ No newline at end of file diff --git a/spring-core/src/main/resources/injectiontypes.xml b/spring-core/src/main/resources/injectiontypes.xml new file mode 100644 index 0000000000..9dad1e300a --- /dev/null +++ b/spring-core/src/main/resources/injectiontypes.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/spring-core/src/test/java/com/baeldung/beaninjection/FileReaderTest.java b/spring-core/src/test/java/com/baeldung/beaninjection/FileReaderTest.java new file mode 100644 index 0000000000..f843fddd4d --- /dev/null +++ b/spring-core/src/test/java/com/baeldung/beaninjection/FileReaderTest.java @@ -0,0 +1,24 @@ +package com.baeldung.beaninjection; + +import static org.junit.Assert.assertNotNull; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = ReaderApplicationConfig.class) +public class FileReaderTest { + + @Autowired + private ApplicationContext context; + + @Test + public void testAutowiredAnnotation_WhenField_ThenInjected() { + FileReader service = context.getBean(FileReader.class); + assertNotNull(service.getLocation()); + } +} diff --git a/spring-core/src/test/java/com/baeldung/beaninjection/FtpReaderTest.java b/spring-core/src/test/java/com/baeldung/beaninjection/FtpReaderTest.java new file mode 100644 index 0000000000..a11afff9ea --- /dev/null +++ b/spring-core/src/test/java/com/baeldung/beaninjection/FtpReaderTest.java @@ -0,0 +1,25 @@ +package com.baeldung.beaninjection; + +import static org.junit.Assert.assertNotNull; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = "classpath:injectiontypes.xml") +public class FtpReaderTest { + + @Autowired + private ApplicationContext context; + + @Test + public void testXMLBeanConfig_WhenConstructorArguments_ThenInjected() { + FtpReader service = context.getBean(FtpReader.class); + assertNotNull(service.getFtpHost()); + assertNotNull(service.getFtpPort()); + } +} diff --git a/spring-core/src/test/java/com/baeldung/beaninjection/ReaderManagerTest.java b/spring-core/src/test/java/com/baeldung/beaninjection/ReaderManagerTest.java new file mode 100644 index 0000000000..7d85c0bf07 --- /dev/null +++ b/spring-core/src/test/java/com/baeldung/beaninjection/ReaderManagerTest.java @@ -0,0 +1,25 @@ +package com.baeldung.beaninjection; + +import static org.junit.Assert.assertNotNull; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = ReaderApplicationConfig.class) +public class ReaderManagerTest { + + @Autowired + private ApplicationContext context; + + @Test + public void testAutowiredAnnotation_WhenConstructorAndSetter_ThenInjected() { + ReaderManager service = context.getBean(ReaderManager.class); + assertNotNull(service.getFtpReader()); + assertNotNull(service.getFileReader()); + } +} diff --git a/spring-core/src/test/java/com/baeldung/beaninjection/ReaderServiceTest.java b/spring-core/src/test/java/com/baeldung/beaninjection/ReaderServiceTest.java new file mode 100644 index 0000000000..da4684ad4e --- /dev/null +++ b/spring-core/src/test/java/com/baeldung/beaninjection/ReaderServiceTest.java @@ -0,0 +1,24 @@ +package com.baeldung.beaninjection; + +import static org.junit.Assert.assertNotNull; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = "classpath:injectiontypes.xml") +public class ReaderServiceTest { + + @Autowired + private ApplicationContext context; + + @Test + public void testXMLBeanConfig_WhenSetter_ThenInjected() { + ReaderService service = context.getBean(ReaderService.class); + assertNotNull(service.getFtpReader()); + } +} diff --git a/spring-core/src/test/java/com/baeldung/value/ClassNotManagedBySpringTest.java b/spring-core/src/test/java/com/baeldung/value/ClassNotManagedBySpringTest.java new file mode 100644 index 0000000000..d07d490642 --- /dev/null +++ b/spring-core/src/test/java/com/baeldung/value/ClassNotManagedBySpringTest.java @@ -0,0 +1,40 @@ +package com.baeldung.value; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.context.junit4.SpringRunner; + +import static junit.framework.TestCase.assertEquals; +import static org.mockito.Mockito.when; + +@RunWith(SpringRunner.class) +public class ClassNotManagedBySpringTest { + + @MockBean + private InitializerBean initializerBean; + + @Before + public void init() { + when(initializerBean.initClass()) + .thenReturn(new ClassNotManagedBySpring("This is only sample value", "Another configured value")); + } + + @Test + public void givenInitializerBean_whenInvokedInitClass_shouldInitialize() throws Exception { + + //given + ClassNotManagedBySpring classNotManagedBySpring = initializerBean.initClass(); + + //when + String initializedValue = classNotManagedBySpring.getCustomVariable(); + String anotherCustomVariable = classNotManagedBySpring.getAnotherCustomVariable(); + + //then + assertEquals("This is only sample value", initializedValue); + assertEquals("Another configured value", anotherCustomVariable); + + } + +} \ No newline at end of file diff --git a/spring-remoting/pom.xml b/spring-remoting/pom.xml index 8acb38bd44..0b751d1fc9 100644 --- a/spring-remoting/pom.xml +++ b/spring-remoting/pom.xml @@ -32,6 +32,7 @@ remoting-http remoting-hessian-burlap remoting-amqp + remoting-jms \ No newline at end of file diff --git a/spring-remoting/remoting-jms/pom.xml b/spring-remoting/remoting-jms/pom.xml new file mode 100644 index 0000000000..fe36431423 --- /dev/null +++ b/spring-remoting/remoting-jms/pom.xml @@ -0,0 +1,19 @@ + + + + spring-remoting + com.baeldung + 1.0-SNAPSHOT + + 4.0.0 + pom + + remoting-jms-client + remoting-jms-server + + remoting-jms + + + \ No newline at end of file diff --git a/spring-remoting/remoting-jms/remoting-jms-client/pom.xml b/spring-remoting/remoting-jms/remoting-jms-client/pom.xml new file mode 100644 index 0000000000..01b7bea657 --- /dev/null +++ b/spring-remoting/remoting-jms/remoting-jms-client/pom.xml @@ -0,0 +1,35 @@ + + + + remoting-jms + com.baeldung + 1.0-SNAPSHOT + + 4.0.0 + + remoting-jms-client + + + UTF-8 + + + + + org.springframework.boot + spring-boot-starter-activemq + + + org.springframework.boot + spring-boot-starter-tomcat + + + + + com.baeldung + api + + + + \ No newline at end of file diff --git a/spring-remoting/remoting-jms/remoting-jms-client/src/main/java/com/baeldung/client/JmsClient.java b/spring-remoting/remoting-jms/remoting-jms-client/src/main/java/com/baeldung/client/JmsClient.java new file mode 100644 index 0000000000..0c5d728f07 --- /dev/null +++ b/spring-remoting/remoting-jms/remoting-jms-client/src/main/java/com/baeldung/client/JmsClient.java @@ -0,0 +1,39 @@ +package com.baeldung.client; + +import com.baeldung.api.Booking; +import com.baeldung.api.BookingException; +import com.baeldung.api.CabBookingService; +import org.apache.activemq.command.ActiveMQQueue; +import org.springframework.beans.factory.FactoryBean; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.jms.remoting.JmsInvokerProxyFactoryBean; + +import javax.jms.ConnectionFactory; +import javax.jms.Queue; + +@SpringBootApplication +public class JmsClient { + + @Bean Queue queue() { + return new ActiveMQQueue("remotingQueue"); +} + + @Bean FactoryBean invoker(ConnectionFactory factory, Queue queue) { + JmsInvokerProxyFactoryBean factoryBean = new JmsInvokerProxyFactoryBean(); + factoryBean.setConnectionFactory(factory); + factoryBean.setServiceInterface(CabBookingService.class); + factoryBean.setQueue(queue); + return factoryBean; + } + + public static void main(String[] args) throws BookingException { + CabBookingService service = SpringApplication.run(JmsClient.class, args).getBean(CabBookingService.class); + System.out.println("here"); + Booking bookingOutcome = service.bookRide("13 Seagate Blvd, Key Largo, FL 33037"); + System.out.println("there"); + System.out.println(bookingOutcome); + } + +} diff --git a/spring-remoting/remoting-jms/remoting-jms-client/src/main/resources/application.properties b/spring-remoting/remoting-jms/remoting-jms-client/src/main/resources/application.properties new file mode 100644 index 0000000000..738b030a59 --- /dev/null +++ b/spring-remoting/remoting-jms/remoting-jms-client/src/main/resources/application.properties @@ -0,0 +1,10 @@ +spring.activemq.broker-url=tcp://127.0.0.1:61616 +spring.activemq.packages.trusted=org.springframework.remoting.support,java.lang,com.baeldung.api + +# Logging +logging.pattern.console=%d{mm:ss.SSS} %-5p [%-31t] [%-54logger{0}] %marker%m%ex{full} - %logger - %F:%L%n +logging.level.root=WARN +logging.level.org.apache.activemq=DEBUG +logging.level.org.springframework.jms=DEBUG +logging.level.org.springframework=WARN + diff --git a/spring-remoting/remoting-jms/remoting-jms-server/pom.xml b/spring-remoting/remoting-jms/remoting-jms-server/pom.xml new file mode 100644 index 0000000000..8feac4df57 --- /dev/null +++ b/spring-remoting/remoting-jms/remoting-jms-server/pom.xml @@ -0,0 +1,40 @@ + + + + remoting-jms + com.baeldung + 1.0-SNAPSHOT + + 4.0.0 + + remoting-jms-server + + + UTF-8 + + + + + org.springframework.boot + spring-boot-starter-activemq + + + org.springframework.boot + spring-boot-starter-tomcat + + + + + com.baeldung + api + + + com.baeldung + api + ${project.version} + + + + \ No newline at end of file diff --git a/spring-remoting/remoting-jms/remoting-jms-server/src/main/java/com/baeldung/server/CabBookingServiceImpl.java b/spring-remoting/remoting-jms/remoting-jms-server/src/main/java/com/baeldung/server/CabBookingServiceImpl.java new file mode 100644 index 0000000000..55ec9c5733 --- /dev/null +++ b/spring-remoting/remoting-jms/remoting-jms-server/src/main/java/com/baeldung/server/CabBookingServiceImpl.java @@ -0,0 +1,16 @@ +package com.baeldung.server; + +import com.baeldung.api.Booking; +import com.baeldung.api.BookingException; +import com.baeldung.api.CabBookingService; + +import static java.lang.Math.random; +import static java.util.UUID.randomUUID; + +public class CabBookingServiceImpl implements CabBookingService { + + @Override public Booking bookRide(String pickUpLocation) throws BookingException { + if (random() < 0.3) throw new BookingException("Cab unavailable"); + return new Booking(randomUUID().toString()); + } +} diff --git a/spring-remoting/remoting-jms/remoting-jms-server/src/main/java/com/baeldung/server/JmsServer.java b/spring-remoting/remoting-jms/remoting-jms-server/src/main/java/com/baeldung/server/JmsServer.java new file mode 100644 index 0000000000..8572718042 --- /dev/null +++ b/spring-remoting/remoting-jms/remoting-jms-server/src/main/java/com/baeldung/server/JmsServer.java @@ -0,0 +1,51 @@ +package com.baeldung.server; + +import com.baeldung.api.CabBookingService; +import org.apache.activemq.command.ActiveMQQueue; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.jms.listener.SimpleMessageListenerContainer; +import org.springframework.jms.remoting.JmsInvokerServiceExporter; + +import javax.jms.ConnectionFactory; +import javax.jms.Queue; + +@SpringBootApplication public class JmsServer { + + /* + This server needs to be connected to an ActiveMQ server. + To quickly spin up an ActiveMQ server, you can use Docker. + + docker run -p 61616:61616 -p 8161:8161 rmohr/activemq:5.14.3 + */ + + @Bean CabBookingService bookingService() { + return new CabBookingServiceImpl(); + } + + @Bean Queue queue() { + return new ActiveMQQueue("remotingQueue"); +} + + @Bean JmsInvokerServiceExporter exporter(CabBookingService implementation) { + JmsInvokerServiceExporter exporter = new JmsInvokerServiceExporter(); + exporter.setServiceInterface(CabBookingService.class); + exporter.setService(implementation); + return exporter; + } + + @Bean SimpleMessageListenerContainer listener(ConnectionFactory factory, JmsInvokerServiceExporter exporter) { + SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(); + container.setConnectionFactory(factory); + container.setDestinationName("remotingQueue"); + container.setConcurrentConsumers(1); + container.setMessageListener(exporter); + return container; + } + + public static void main(String[] args) { + SpringApplication.run(JmsServer.class, args); + } + +} diff --git a/spring-remoting/remoting-jms/remoting-jms-server/src/main/resources/application.properties b/spring-remoting/remoting-jms/remoting-jms-server/src/main/resources/application.properties new file mode 100644 index 0000000000..738b030a59 --- /dev/null +++ b/spring-remoting/remoting-jms/remoting-jms-server/src/main/resources/application.properties @@ -0,0 +1,10 @@ +spring.activemq.broker-url=tcp://127.0.0.1:61616 +spring.activemq.packages.trusted=org.springframework.remoting.support,java.lang,com.baeldung.api + +# Logging +logging.pattern.console=%d{mm:ss.SSS} %-5p [%-31t] [%-54logger{0}] %marker%m%ex{full} - %logger - %F:%L%n +logging.level.root=WARN +logging.level.org.apache.activemq=DEBUG +logging.level.org.springframework.jms=DEBUG +logging.level.org.springframework=WARN + diff --git a/spring-security-mvc-boot/README.MD b/spring-security-mvc-boot/README.MD index 70b0f23cbb..feda6efcd7 100644 --- a/spring-security-mvc-boot/README.MD +++ b/spring-security-mvc-boot/README.MD @@ -7,3 +7,4 @@ The "REST With Spring" Classes: http://github.learnspringsecurity.com - [Spring Security: Authentication with a Database-backed UserDetailsService](http://www.baeldung.com/spring-security-authentication-with-a-database) - [Two Login Pages with Spring Security](http://www.baeldung.com/spring-security-two-login-pages) - [Multiple Entry Points in Spring Security](http://www.baeldung.com/spring-security-multiple-entry-points) +- [Multiple Authentication Providers in Spring Security](http://www.baeldung.com/spring-security-multiple-auth-providers) diff --git a/spring-security-mvc-boot/src/main/java/org/baeldung/multipleauthproviders/CustomAuthenticationProvider.java b/spring-security-mvc-boot/src/main/java/org/baeldung/multipleauthproviders/CustomAuthenticationProvider.java new file mode 100644 index 0000000000..1a89c362cd --- /dev/null +++ b/spring-security-mvc-boot/src/main/java/org/baeldung/multipleauthproviders/CustomAuthenticationProvider.java @@ -0,0 +1,31 @@ +package org.baeldung.multipleauthproviders; + +import java.util.Collections; + +import org.springframework.security.authentication.AuthenticationProvider; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.stereotype.Component; + +@Component +public class CustomAuthenticationProvider implements AuthenticationProvider { + @Override + public Authentication authenticate(Authentication auth) throws AuthenticationException { + final String username = auth.getName(); + final String password = auth.getCredentials() + .toString(); + + if ("externaluser".equals(username) && "pass".equals(password)) { + return new UsernamePasswordAuthenticationToken(username, password, Collections.emptyList()); + } else { + throw new BadCredentialsException("External system authentication failed"); + } + } + + @Override + public boolean supports(Class auth) { + return auth.equals(UsernamePasswordAuthenticationToken.class); + } +} diff --git a/spring-security-mvc-boot/src/main/java/org/baeldung/multipleauthproviders/MultipleAuthController.java b/spring-security-mvc-boot/src/main/java/org/baeldung/multipleauthproviders/MultipleAuthController.java new file mode 100644 index 0000000000..80573c1c7d --- /dev/null +++ b/spring-security-mvc-boot/src/main/java/org/baeldung/multipleauthproviders/MultipleAuthController.java @@ -0,0 +1,13 @@ +package org.baeldung.multipleauthproviders; + +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class MultipleAuthController { + + @RequestMapping("/api/ping") + public String getPing() { + return "OK"; + } +} \ No newline at end of file diff --git a/spring-security-mvc-boot/src/main/java/org/baeldung/multipleauthproviders/MultipleAuthProvidersApplication.java b/spring-security-mvc-boot/src/main/java/org/baeldung/multipleauthproviders/MultipleAuthProvidersApplication.java new file mode 100644 index 0000000000..077f558bd2 --- /dev/null +++ b/spring-security-mvc-boot/src/main/java/org/baeldung/multipleauthproviders/MultipleAuthProvidersApplication.java @@ -0,0 +1,12 @@ +package org.baeldung.multipleauthproviders; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +// @ImportResource({ "classpath*:spring-security-multiple-auth-providers.xml" }) +public class MultipleAuthProvidersApplication { + public static void main(String[] args) { + SpringApplication.run(MultipleAuthProvidersApplication.class, args); + } +} diff --git a/spring-security-mvc-boot/src/main/java/org/baeldung/multipleauthproviders/MultipleAuthProvidersSecurityConfig.java b/spring-security-mvc-boot/src/main/java/org/baeldung/multipleauthproviders/MultipleAuthProvidersSecurityConfig.java new file mode 100644 index 0000000000..432cc61e87 --- /dev/null +++ b/spring-security-mvc-boot/src/main/java/org/baeldung/multipleauthproviders/MultipleAuthProvidersSecurityConfig.java @@ -0,0 +1,34 @@ +package org.baeldung.multipleauthproviders; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; + +@EnableWebSecurity +public class MultipleAuthProvidersSecurityConfig extends WebSecurityConfigurerAdapter { + + @Autowired + CustomAuthenticationProvider customAuthProvider; + + @Override + public void configure(AuthenticationManagerBuilder auth) throws Exception { + + auth.authenticationProvider(customAuthProvider); + + auth.inMemoryAuthentication() + .withUser("memuser") + .password("pass") + .roles("USER"); + } + + @Override + protected void configure(HttpSecurity http) throws Exception { + http.httpBasic() + .and() + .authorizeRequests() + .antMatchers("/api/**") + .authenticated(); + } +} diff --git a/spring-security-mvc-boot/src/main/resources/spring-security-multiple-auth-providers.xml b/spring-security-mvc-boot/src/main/resources/spring-security-multiple-auth-providers.xml new file mode 100644 index 0000000000..4cfa6bbf26 --- /dev/null +++ b/spring-security-mvc-boot/src/main/resources/spring-security-multiple-auth-providers.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + diff --git a/spring-security-mvc-boot/src/test/java/org/baeldung/web/MultipleAuthProvidersApplicationTests.java b/spring-security-mvc-boot/src/test/java/org/baeldung/web/MultipleAuthProvidersApplicationTests.java new file mode 100644 index 0000000000..0d70cd64e4 --- /dev/null +++ b/spring-security-mvc-boot/src/test/java/org/baeldung/web/MultipleAuthProvidersApplicationTests.java @@ -0,0 +1,61 @@ +package org.baeldung.web; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Collections; + +import org.baeldung.multipleauthproviders.MultipleAuthProvidersApplication; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, classes = MultipleAuthProvidersApplication.class) +public class MultipleAuthProvidersApplicationTests { + @Autowired + private TestRestTemplate restTemplate; + + @Test + public void givenMemUsers_whenGetPingWithValidUser_thenOk() { + ResponseEntity result = makeRestCallToGetPing("memuser", "pass"); + + assertThat(result.getStatusCodeValue()).isEqualTo(200); + assertThat(result.getBody()).isEqualTo("OK"); + } + + @Test + public void givenExternalUsers_whenGetPingWithValidUser_thenOK() { + ResponseEntity result = makeRestCallToGetPing("externaluser", "pass"); + + assertThat(result.getStatusCodeValue()).isEqualTo(200); + assertThat(result.getBody()).isEqualTo("OK"); + } + + @Test + public void givenAuthProviders_whenGetPingWithNoCred_then401() { + ResponseEntity result = makeRestCallToGetPing(); + + assertThat(result.getStatusCodeValue()).isEqualTo(401); + } + + @Test + public void givenAuthProviders_whenGetPingWithBadCred_then401() { + ResponseEntity result = makeRestCallToGetPing("user", "bad_password"); + + assertThat(result.getStatusCodeValue()).isEqualTo(401); + } + + private ResponseEntity makeRestCallToGetPing(String username, String password) { + return restTemplate.withBasicAuth(username, password) + .getForEntity("/api/ping", String.class, Collections.emptyMap()); + } + + private ResponseEntity makeRestCallToGetPing() { + return restTemplate.getForEntity("/api/ping", String.class, Collections.emptyMap()); + } +} diff --git a/spring-security-sso/pom.xml b/spring-security-sso/pom.xml new file mode 100644 index 0000000000..7438cede16 --- /dev/null +++ b/spring-security-sso/pom.xml @@ -0,0 +1,28 @@ + + 4.0.0 + org.baeldung + spring-security-sso + 1.0.0-SNAPSHOT + + spring-security-sso + pom + + + parent-boot-5 + com.baeldung + 0.0.1-SNAPSHOT + ../parent-boot-5 + + + + spring-security-sso-auth-server + spring-security-sso-ui + spring-security-sso-ui-2 + + + + 3.0.1 + + + \ No newline at end of file diff --git a/spring-security-sso/spring-security-sso-auth-server/pom.xml b/spring-security-sso/spring-security-sso-auth-server/pom.xml new file mode 100644 index 0000000000..c7b23249f9 --- /dev/null +++ b/spring-security-sso/spring-security-sso-auth-server/pom.xml @@ -0,0 +1,28 @@ + + 4.0.0 + spring-security-sso-auth-server + + spring-security-sso-auth-server + war + + + org.baeldung + spring-security-sso + 1.0.0-SNAPSHOT + + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.security.oauth + spring-security-oauth2 + + + + + \ No newline at end of file diff --git a/spring-security-sso/spring-security-sso-auth-server/src/main/java/org/baeldung/config/AuthServerConfig.java b/spring-security-sso/spring-security-sso-auth-server/src/main/java/org/baeldung/config/AuthServerConfig.java new file mode 100644 index 0000000000..20cde21073 --- /dev/null +++ b/spring-security-sso/spring-security-sso-auth-server/src/main/java/org/baeldung/config/AuthServerConfig.java @@ -0,0 +1,41 @@ +package org.baeldung.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer; +import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter; +import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer; +import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer; +import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer; + +@Configuration +@EnableAuthorizationServer +public class AuthServerConfig extends AuthorizationServerConfigurerAdapter { + @Autowired + private AuthenticationManager authenticationManager; + + @Override + public void configure(final AuthorizationServerSecurityConfigurer oauthServer) throws Exception { + oauthServer.tokenKeyAccess("permitAll()") + .checkTokenAccess("isAuthenticated()"); + } + + @Override + public void configure(final ClientDetailsServiceConfigurer clients) throws Exception { + clients.inMemory() + .withClient("SampleClientId") + .secret("secret") + .authorizedGrantTypes("authorization_code") + .scopes("user_info") + .autoApprove(true) + // .accessTokenValiditySeconds(3600) + ; // 1 hour + } + + @Override + public void configure(final AuthorizationServerEndpointsConfigurer endpoints) throws Exception { + endpoints.authenticationManager(authenticationManager); + } + +} diff --git a/spring-security-sso/spring-security-sso-auth-server/src/main/java/org/baeldung/config/AuthorizationServerApplication.java b/spring-security-sso/spring-security-sso-auth-server/src/main/java/org/baeldung/config/AuthorizationServerApplication.java new file mode 100644 index 0000000000..5b0b39b444 --- /dev/null +++ b/spring-security-sso/spring-security-sso-auth-server/src/main/java/org/baeldung/config/AuthorizationServerApplication.java @@ -0,0 +1,16 @@ +package org.baeldung.config; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.web.support.SpringBootServletInitializer; +import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; + +@SpringBootApplication +@EnableResourceServer +public class AuthorizationServerApplication extends SpringBootServletInitializer { + + public static void main(String[] args) { + SpringApplication.run(AuthorizationServerApplication.class, args); + } + +} \ No newline at end of file diff --git a/spring-security-sso/spring-security-sso-auth-server/src/main/java/org/baeldung/config/SecurityConfig.java b/spring-security-sso/spring-security-sso-auth-server/src/main/java/org/baeldung/config/SecurityConfig.java new file mode 100644 index 0000000000..9de203b7c3 --- /dev/null +++ b/spring-security-sso/spring-security-sso-auth-server/src/main/java/org/baeldung/config/SecurityConfig.java @@ -0,0 +1,38 @@ +package org.baeldung.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; + +@Configuration +public class SecurityConfig extends WebSecurityConfigurerAdapter { + + @Autowired + private AuthenticationManager authenticationManager; + + @Override + protected void configure(HttpSecurity http) throws Exception { + http.requestMatchers() + .antMatchers("/login", "/oauth/authorize") + .and() + .authorizeRequests() + .anyRequest() + .authenticated() + .and() + .formLogin() + .permitAll(); + } + + @Override + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + auth.parentAuthenticationManager(authenticationManager) + .inMemoryAuthentication() + .withUser("john") + .password("123") + .roles("USER"); + } + +} diff --git a/spring-security-sso/spring-security-sso-auth-server/src/main/java/org/baeldung/config/UserController.java b/spring-security-sso/spring-security-sso-auth-server/src/main/java/org/baeldung/config/UserController.java new file mode 100644 index 0000000000..28128f9d97 --- /dev/null +++ b/spring-security-sso/spring-security-sso-auth-server/src/main/java/org/baeldung/config/UserController.java @@ -0,0 +1,16 @@ +package org.baeldung.config; + +import java.security.Principal; + +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class UserController { + + @RequestMapping("/user/me") + public Principal user(Principal principal) { + System.out.println(principal); + return principal; + } +} diff --git a/spring-security-sso/spring-security-sso-auth-server/src/main/resources/application.properties b/spring-security-sso/spring-security-sso-auth-server/src/main/resources/application.properties new file mode 100644 index 0000000000..32a0993b04 --- /dev/null +++ b/spring-security-sso/spring-security-sso-auth-server/src/main/resources/application.properties @@ -0,0 +1,4 @@ +server.port=8081 +server.context-path=/auth +security.basic.enabled=false +#logging.level.org.springframework=DEBUG \ No newline at end of file diff --git a/spring-security-sso/spring-security-sso-auth-server/src/test/java/org/baeldung/test/AuthServerIntegrationTest.java b/spring-security-sso/spring-security-sso-auth-server/src/test/java/org/baeldung/test/AuthServerIntegrationTest.java new file mode 100644 index 0000000000..9e2d6feca1 --- /dev/null +++ b/spring-security-sso/spring-security-sso-auth-server/src/test/java/org/baeldung/test/AuthServerIntegrationTest.java @@ -0,0 +1,18 @@ +package org.baeldung.test; + +import org.baeldung.config.AuthorizationServerApplication; +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.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = AuthorizationServerApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT) +public class AuthServerIntegrationTest { + + @Test + public void whenLoadApplication_thenSuccess() { + + } +} diff --git a/spring-security-sso/spring-security-sso-ui-2/pom.xml b/spring-security-sso/spring-security-sso-ui-2/pom.xml new file mode 100644 index 0000000000..6a8dc5385b --- /dev/null +++ b/spring-security-sso/spring-security-sso-ui-2/pom.xml @@ -0,0 +1,44 @@ + + 4.0.0 + spring-security-sso-ui-2 + + spring-security-sso-ui-2 + war + + + org.baeldung + spring-security-sso + 1.0.0-SNAPSHOT + + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-security + + + + org.springframework.security.oauth + spring-security-oauth2 + + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + + org.thymeleaf.extras + thymeleaf-extras-springsecurity4 + + + + + \ No newline at end of file diff --git a/spring-security-sso/spring-security-sso-ui-2/src/main/java/org/baeldung/config/UiApplication.java b/spring-security-sso/spring-security-sso-ui-2/src/main/java/org/baeldung/config/UiApplication.java new file mode 100644 index 0000000000..5ef699d264 --- /dev/null +++ b/spring-security-sso/spring-security-sso-ui-2/src/main/java/org/baeldung/config/UiApplication.java @@ -0,0 +1,33 @@ +package org.baeldung.config; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso; +import org.springframework.context.annotation.Bean; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.web.context.request.RequestContextListener; + +@EnableOAuth2Sso +@SpringBootApplication +public class UiApplication extends WebSecurityConfigurerAdapter { + + @Override + public void configure(HttpSecurity http) throws Exception { + http.antMatcher("/**") + .authorizeRequests() + .antMatchers("/", "/login**") + .permitAll() + .anyRequest() + .authenticated(); + } + + @Bean + public RequestContextListener requestContextListener() { + return new RequestContextListener(); + } + + public static void main(String[] args) { + SpringApplication.run(UiApplication.class, args); + } +} \ No newline at end of file diff --git a/spring-security-sso/spring-security-sso-ui-2/src/main/java/org/baeldung/config/UiWebConfig.java b/spring-security-sso/spring-security-sso-ui-2/src/main/java/org/baeldung/config/UiWebConfig.java new file mode 100644 index 0000000000..24d6c9b5d8 --- /dev/null +++ b/spring-security-sso/spring-security-sso-ui-2/src/main/java/org/baeldung/config/UiWebConfig.java @@ -0,0 +1,41 @@ +package org.baeldung.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; +import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; + +@Configuration +@EnableWebMvc +public class UiWebConfig extends WebMvcConfigurerAdapter { + + @Bean + public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() { + return new PropertySourcesPlaceholderConfigurer(); + } + + @Override + public void configureDefaultServletHandling(final DefaultServletHandlerConfigurer configurer) { + configurer.enable(); + } + + @Override + public void addViewControllers(final ViewControllerRegistry registry) { + super.addViewControllers(registry); + registry.addViewController("/") + .setViewName("forward:/index"); + registry.addViewController("/index"); + registry.addViewController("/securedPage"); + } + + @Override + public void addResourceHandlers(final ResourceHandlerRegistry registry) { + registry.addResourceHandler("/resources/**") + .addResourceLocations("/resources/"); + } + +} \ No newline at end of file diff --git a/spring-security-sso/spring-security-sso-ui-2/src/main/resources/application.yml b/spring-security-sso/spring-security-sso-ui-2/src/main/resources/application.yml new file mode 100644 index 0000000000..6b0d3db5ad --- /dev/null +++ b/spring-security-sso/spring-security-sso-ui-2/src/main/resources/application.yml @@ -0,0 +1,20 @@ +server: + port: 8083 + context-path: /ui2 + session: + cookie: + name: UI2SESSION +security: + basic: + enabled: false + oauth2: + client: + clientId: SampleClientId + clientSecret: secret + accessTokenUri: http://localhost:8081/auth/oauth/token + userAuthorizationUri: http://localhost:8081/auth/oauth/authorize + resource: + userInfoUri: http://localhost:8081/auth/user/me +spring: + thymeleaf: + cache: false \ No newline at end of file diff --git a/spring-security-sso/spring-security-sso-ui-2/src/main/resources/templates/index.html b/spring-security-sso/spring-security-sso-ui-2/src/main/resources/templates/index.html new file mode 100644 index 0000000000..38fa8bda50 --- /dev/null +++ b/spring-security-sso/spring-security-sso-ui-2/src/main/resources/templates/index.html @@ -0,0 +1,18 @@ + + + + +Spring Security SSO Client 2 + + + + +
+
+

Spring Security SSO Client 2

+ Login +
+
+ + \ No newline at end of file diff --git a/spring-security-sso/spring-security-sso-ui-2/src/main/resources/templates/securedPage.html b/spring-security-sso/spring-security-sso-ui-2/src/main/resources/templates/securedPage.html new file mode 100644 index 0000000000..7807298828 --- /dev/null +++ b/spring-security-sso/spring-security-sso-ui-2/src/main/resources/templates/securedPage.html @@ -0,0 +1,20 @@ + + + + +Spring Security SSO Client 2 + + + + +
+
+

Secured Page

+ Welcome, Name +
+ Your authorities are authorities +
+
+ + \ No newline at end of file diff --git a/spring-security-sso/spring-security-sso-ui-2/src/test/java/org/baeldung/test/UiIntegrationTest.java b/spring-security-sso/spring-security-sso-ui-2/src/test/java/org/baeldung/test/UiIntegrationTest.java new file mode 100644 index 0000000000..6386eac0b8 --- /dev/null +++ b/spring-security-sso/spring-security-sso-ui-2/src/test/java/org/baeldung/test/UiIntegrationTest.java @@ -0,0 +1,18 @@ +package org.baeldung.test; + +import org.baeldung.config.UiApplication; +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.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = UiApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT) +public class UiIntegrationTest { + + @Test + public void whenLoadApplication_thenSuccess() { + + } +} diff --git a/spring-security-sso/spring-security-sso-ui/pom.xml b/spring-security-sso/spring-security-sso-ui/pom.xml new file mode 100644 index 0000000000..fe1cd56a76 --- /dev/null +++ b/spring-security-sso/spring-security-sso-ui/pom.xml @@ -0,0 +1,44 @@ + + 4.0.0 + spring-security-sso-ui + + spring-security-sso-ui + war + + + org.baeldung + spring-security-sso + 1.0.0-SNAPSHOT + + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-security + + + + org.springframework.security.oauth + spring-security-oauth2 + + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + + org.thymeleaf.extras + thymeleaf-extras-springsecurity4 + + + + + \ No newline at end of file diff --git a/spring-security-sso/spring-security-sso-ui/src/main/java/org/baeldung/config/UiApplication.java b/spring-security-sso/spring-security-sso-ui/src/main/java/org/baeldung/config/UiApplication.java new file mode 100644 index 0000000000..5ef699d264 --- /dev/null +++ b/spring-security-sso/spring-security-sso-ui/src/main/java/org/baeldung/config/UiApplication.java @@ -0,0 +1,33 @@ +package org.baeldung.config; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso; +import org.springframework.context.annotation.Bean; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.web.context.request.RequestContextListener; + +@EnableOAuth2Sso +@SpringBootApplication +public class UiApplication extends WebSecurityConfigurerAdapter { + + @Override + public void configure(HttpSecurity http) throws Exception { + http.antMatcher("/**") + .authorizeRequests() + .antMatchers("/", "/login**") + .permitAll() + .anyRequest() + .authenticated(); + } + + @Bean + public RequestContextListener requestContextListener() { + return new RequestContextListener(); + } + + public static void main(String[] args) { + SpringApplication.run(UiApplication.class, args); + } +} \ No newline at end of file diff --git a/spring-security-sso/spring-security-sso-ui/src/main/java/org/baeldung/config/UiWebConfig.java b/spring-security-sso/spring-security-sso-ui/src/main/java/org/baeldung/config/UiWebConfig.java new file mode 100644 index 0000000000..24d6c9b5d8 --- /dev/null +++ b/spring-security-sso/spring-security-sso-ui/src/main/java/org/baeldung/config/UiWebConfig.java @@ -0,0 +1,41 @@ +package org.baeldung.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; +import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; + +@Configuration +@EnableWebMvc +public class UiWebConfig extends WebMvcConfigurerAdapter { + + @Bean + public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() { + return new PropertySourcesPlaceholderConfigurer(); + } + + @Override + public void configureDefaultServletHandling(final DefaultServletHandlerConfigurer configurer) { + configurer.enable(); + } + + @Override + public void addViewControllers(final ViewControllerRegistry registry) { + super.addViewControllers(registry); + registry.addViewController("/") + .setViewName("forward:/index"); + registry.addViewController("/index"); + registry.addViewController("/securedPage"); + } + + @Override + public void addResourceHandlers(final ResourceHandlerRegistry registry) { + registry.addResourceHandler("/resources/**") + .addResourceLocations("/resources/"); + } + +} \ No newline at end of file diff --git a/spring-security-sso/spring-security-sso-ui/src/main/resources/application.yml b/spring-security-sso/spring-security-sso-ui/src/main/resources/application.yml new file mode 100644 index 0000000000..bb4bd92033 --- /dev/null +++ b/spring-security-sso/spring-security-sso-ui/src/main/resources/application.yml @@ -0,0 +1,20 @@ +server: + port: 8082 + context-path: /ui + session: + cookie: + name: UISESSION +security: + basic: + enabled: false + oauth2: + client: + clientId: SampleClientId + clientSecret: secret + accessTokenUri: http://localhost:8081/auth/oauth/token + userAuthorizationUri: http://localhost:8081/auth/oauth/authorize + resource: + userInfoUri: http://localhost:8081/auth/user/me +spring: + thymeleaf: + cache: false \ No newline at end of file diff --git a/spring-security-sso/spring-security-sso-ui/src/main/resources/templates/index.html b/spring-security-sso/spring-security-sso-ui/src/main/resources/templates/index.html new file mode 100644 index 0000000000..12948e0738 --- /dev/null +++ b/spring-security-sso/spring-security-sso-ui/src/main/resources/templates/index.html @@ -0,0 +1,18 @@ + + + + +Spring Security SSO + + + + +
+
+

Spring Security SSO

+ Login +
+
+ + \ No newline at end of file diff --git a/spring-security-sso/spring-security-sso-ui/src/main/resources/templates/securedPage.html b/spring-security-sso/spring-security-sso-ui/src/main/resources/templates/securedPage.html new file mode 100644 index 0000000000..81ed51b2d6 --- /dev/null +++ b/spring-security-sso/spring-security-sso-ui/src/main/resources/templates/securedPage.html @@ -0,0 +1,18 @@ + + + + +Spring Security SSO + + + + +
+
+

Secured Page

+ Welcome, Name +
+
+ + \ No newline at end of file diff --git a/spring-security-sso/spring-security-sso-ui/src/test/java/org/baeldung/test/UiIntegrationTest.java b/spring-security-sso/spring-security-sso-ui/src/test/java/org/baeldung/test/UiIntegrationTest.java new file mode 100644 index 0000000000..6386eac0b8 --- /dev/null +++ b/spring-security-sso/spring-security-sso-ui/src/test/java/org/baeldung/test/UiIntegrationTest.java @@ -0,0 +1,18 @@ +package org.baeldung.test; + +import org.baeldung.config.UiApplication; +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.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = UiApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT) +public class UiIntegrationTest { + + @Test + public void whenLoadApplication_thenSuccess() { + + } +} diff --git a/structurizr/pom.xml b/structurizr/pom.xml new file mode 100644 index 0000000000..1656bb10ec --- /dev/null +++ b/structurizr/pom.xml @@ -0,0 +1,54 @@ + + + 4.0.0 + + com.baeldung + structurizr + + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + + + + 1.8 + 1.8 + + + + + com.structurizr + structurizr-core + 1.0.0-RC3 + + + com.structurizr + structurizr-spring + 1.0.0-RC3 + + + com.structurizr + structurizr-client + 0.6.0 + + + org.springframework + spring-context + 4.3.8.RELEASE + + + + + + + false + + central + bintray + http://jcenter.bintray.com + + + \ No newline at end of file diff --git a/structurizr/src/main/java/com/baeldung/structurizr/StructurizrSimple.java b/structurizr/src/main/java/com/baeldung/structurizr/StructurizrSimple.java new file mode 100644 index 0000000000..6eb0c7de73 --- /dev/null +++ b/structurizr/src/main/java/com/baeldung/structurizr/StructurizrSimple.java @@ -0,0 +1,155 @@ +package com.baeldung.structurizr; + +import java.io.File; +import java.io.StringWriter; + +import com.structurizr.Workspace; +import com.structurizr.api.StructurizrClient; +import com.structurizr.api.StructurizrClientException; +import com.structurizr.componentfinder.ComponentFinder; +import com.structurizr.componentfinder.ReferencedTypesSupportingTypesStrategy; +import com.structurizr.componentfinder.SourceCodeComponentFinderStrategy; +import com.structurizr.componentfinder.SpringComponentFinderStrategy; +import com.structurizr.io.WorkspaceWriterException; +import com.structurizr.io.plantuml.PlantUMLWriter; +import com.structurizr.model.Component; +import com.structurizr.model.Container; +import com.structurizr.model.Model; +import com.structurizr.model.Person; +import com.structurizr.model.SoftwareSystem; +import com.structurizr.model.Tags; +import com.structurizr.view.ComponentView; +import com.structurizr.view.ContainerView; +import com.structurizr.view.Routing; +import com.structurizr.view.Shape; +import com.structurizr.view.Styles; +import com.structurizr.view.SystemContextView; +import com.structurizr.view.View; +import com.structurizr.view.ViewSet; + +public class StructurizrSimple { + + public static final String PAYMENT_TERMINAL = "Payment Terminal"; + public static final String FRAUD_DETECTOR = "Fraud Detector"; + public static final String SOFTWARE_SYSTEM_VIEW = "SoftwareSystemView"; + public static final String CONTAINER_VIEW = "ContainerView"; + public static final String COMPONENT_VIEW = "ComponentView"; + public static final String JVM2_COMPONENT_VIEW = "JVM2ComponentView"; + + public static void main(String[] args) throws Exception { + Workspace workspace = getSoftwareSystem(); + + addContainers(workspace); + addComponents(workspace); + addSpringComponents(workspace); + exportToPlantUml(workspace.getViews().getViewWithKey(SOFTWARE_SYSTEM_VIEW)); + exportToPlantUml(workspace.getViews().getViewWithKey(CONTAINER_VIEW)); + exportToPlantUml(workspace.getViews().getViewWithKey(COMPONENT_VIEW)); + + exportToPlantUml(workspace.getViews().getViewWithKey(JVM2_COMPONENT_VIEW)); + + addStyles(workspace.getViews()); + //uploadToExternal(workspace); + } + + private static void addSpringComponents(Workspace workspace) throws Exception { + Container jvm2 = workspace.getModel().getSoftwareSystemWithName(PAYMENT_TERMINAL).getContainerWithName("JVM-2"); + findComponents(jvm2); + + ComponentView view = workspace.getViews().createComponentView(jvm2, JVM2_COMPONENT_VIEW, "JVM2ComponentView"); + view.addAllComponents(); + + } + + private static void findComponents(Container jvm) throws Exception { + ComponentFinder componentFinder = new ComponentFinder( + jvm, + "com.baeldung.structurizr", + new SpringComponentFinderStrategy( + new ReferencedTypesSupportingTypesStrategy() + ), + new SourceCodeComponentFinderStrategy(new File("."), 150)); + + componentFinder.findComponents(); + } + + private static void addComponents(Workspace workspace) { + Model model = workspace.getModel(); + + SoftwareSystem paymentTerminal = model.getSoftwareSystemWithName(PAYMENT_TERMINAL); + Container jvm1 = paymentTerminal.getContainerWithName("JVM-1"); + + Component jaxrs = jvm1.addComponent("jaxrs-jersey", "restful webservice implementation", "rest"); + Component gemfire = jvm1.addComponent("gemfire", "Clustered Cache Gemfire", "cache"); + Component hibernate = jvm1.addComponent("hibernate", "Data Access Layer", "jpa"); + + jaxrs.uses(gemfire, ""); + gemfire.uses(hibernate, ""); + + ComponentView componentView = workspace.getViews().createComponentView(jvm1, COMPONENT_VIEW, "JVM Components"); + componentView.addAllComponents(); + } + + private static void addContainers(Workspace workspace) { + Model model = workspace.getModel(); + + SoftwareSystem paymentTerminal = model.getSoftwareSystemWithName(PAYMENT_TERMINAL); + Container f5 = paymentTerminal.addContainer("Payment Load Balancer", "Payment Load Balancer", "F5"); + Container jvm1 = paymentTerminal.addContainer("JVM-1", "JVM-1", "Java Virtual Machine"); + Container jvm2 = paymentTerminal.addContainer("JVM-2", "JVM-2", "Java Virtual Machine"); + Container jvm3 = paymentTerminal.addContainer("JVM-3", "JVM-3", "Java Virtual Machine"); + Container oracle = paymentTerminal.addContainer("oracleDB", "Oracle Database", "RDBMS"); + + f5.uses(jvm1, "route"); + f5.uses(jvm2, "route"); + f5.uses(jvm3, "route"); + + jvm1.uses(oracle, "storage"); + jvm2.uses(oracle, "storage"); + jvm3.uses(oracle, "storage"); + + ContainerView view = workspace.getViews().createContainerView(paymentTerminal, CONTAINER_VIEW, "Container View"); + view.addAllContainers(); + } + + private static void uploadToExternal(Workspace workspace) throws StructurizrClientException { + StructurizrClient client = new StructurizrClient("e94bc0c9-76ef-41b0-8de7-82afc1010d04", "78d555dd-2a31-487c-952c-50508f1da495"); + client.putWorkspace(32961L, workspace); + } + + private static void exportToPlantUml(View view) throws WorkspaceWriterException { + StringWriter stringWriter = new StringWriter(); + PlantUMLWriter plantUMLWriter = new PlantUMLWriter(); + plantUMLWriter.write(view, stringWriter); + System.out.println(stringWriter.toString()); + } + + private static Workspace getSoftwareSystem() { + Workspace workspace = new Workspace("Payment Gateway", "Payment Gateway"); + Model model = workspace.getModel(); + + Person user = model.addPerson("Merchant", "Merchant"); + SoftwareSystem paymentTerminal = model.addSoftwareSystem(PAYMENT_TERMINAL, "Payment Terminal"); + user.uses(paymentTerminal, "Makes payment"); + SoftwareSystem fraudDetector = model.addSoftwareSystem(FRAUD_DETECTOR, "Fraud Detector"); + paymentTerminal.uses(fraudDetector, "Obtains fraud score"); + + ViewSet viewSet = workspace.getViews(); + + SystemContextView contextView = viewSet.createSystemContextView(workspace.getModel().getSoftwareSystemWithName(PAYMENT_TERMINAL), SOFTWARE_SYSTEM_VIEW, "Payment Gateway Diagram"); + contextView.addAllElements(); + + return workspace; + } + + private static void addStyles(ViewSet viewSet) { + Styles styles = viewSet.getConfiguration().getStyles(); + styles.addElementStyle(Tags.ELEMENT).color("#000000"); + styles.addElementStyle(Tags.PERSON).background("#ffbf00").shape(Shape.Person); + styles.addElementStyle(Tags.CONTAINER).background("#facc2E"); + styles.addRelationshipStyle(Tags.RELATIONSHIP).routing(Routing.Orthogonal); + + styles.addRelationshipStyle(Tags.ASYNCHRONOUS).dashed(true); + styles.addRelationshipStyle(Tags.SYNCHRONOUS).dashed(false); + } +} diff --git a/structurizr/src/main/java/com/baeldung/structurizr/spring/GenericComponent.java b/structurizr/src/main/java/com/baeldung/structurizr/spring/GenericComponent.java new file mode 100644 index 0000000000..56f2d52ce0 --- /dev/null +++ b/structurizr/src/main/java/com/baeldung/structurizr/spring/GenericComponent.java @@ -0,0 +1,7 @@ +package com.baeldung.structurizr.spring; + +import org.springframework.stereotype.Component; + +@Component +public class GenericComponent { +} diff --git a/structurizr/src/main/java/com/baeldung/structurizr/spring/PaymentController.java b/structurizr/src/main/java/com/baeldung/structurizr/spring/PaymentController.java new file mode 100644 index 0000000000..89a58b9885 --- /dev/null +++ b/structurizr/src/main/java/com/baeldung/structurizr/spring/PaymentController.java @@ -0,0 +1,14 @@ +package com.baeldung.structurizr.spring; + +import org.springframework.stereotype.Controller; + +import javax.annotation.Resource; + +@Controller +public class PaymentController { + @Resource + private PaymentRepository repository; + + @Resource + private GenericComponent component; +} diff --git a/structurizr/src/main/java/com/baeldung/structurizr/spring/PaymentRepository.java b/structurizr/src/main/java/com/baeldung/structurizr/spring/PaymentRepository.java new file mode 100644 index 0000000000..78b00495b6 --- /dev/null +++ b/structurizr/src/main/java/com/baeldung/structurizr/spring/PaymentRepository.java @@ -0,0 +1,7 @@ +package com.baeldung.structurizr.spring; + +import org.springframework.stereotype.Repository; + +@Repository +public class PaymentRepository { +} diff --git a/testing/README.md b/testing/README.md index fd94279fdf..e9208bfbf3 100644 --- a/testing/README.md +++ b/testing/README.md @@ -9,4 +9,4 @@ - [AssertJ for Guava](http://www.baeldung.com/assertJ-for-guava) - [Introduction to AssertJ](http://www.baeldung.com/introduction-to-assertj) - [Cucumber and Scenario Outline](http://www.baeldung.com/cucumber-scenario-outline) - +- [Testing with Google Truth](http://www.baeldung.com/google-truth) diff --git a/testing/pom.xml b/testing/pom.xml index 0bc70bdb96..8c6898ac67 100644 --- a/testing/pom.xml +++ b/testing/pom.xml @@ -52,6 +52,24 @@ ${pitest.version} pom + + + com.google.truth + truth + ${truth.version} + + + com.google.truth.extensions + truth-java8-extension + ${truth.version} + test + + + pl.pragmatists + JUnitParams + ${jUnitParams.version} + test + @@ -114,8 +132,10 @@ 1.2.5 1.1.10 0.7.7.201606060606 - 19.0 + 21.0 3.1.0 3.6.1 + 0.32 + 1.1.0
diff --git a/testing/src/main/java/com/baeldung/junitparams/SafeAdditionUtil.java b/testing/src/main/java/com/baeldung/junitparams/SafeAdditionUtil.java new file mode 100644 index 0000000000..a2c1573dca --- /dev/null +++ b/testing/src/main/java/com/baeldung/junitparams/SafeAdditionUtil.java @@ -0,0 +1,15 @@ +package com.baeldung.junitparams; + +public class SafeAdditionUtil { + + public int safeAdd(int a, int b) { + long result = ((long) a) + b; + if (result > Integer.MAX_VALUE) { + return Integer.MAX_VALUE; + } else if (result < Integer.MIN_VALUE) { + return Integer.MIN_VALUE; + } + return (int) result; + } + +} diff --git a/testing/src/main/java/com/baeldung/testing/truth/User.java b/testing/src/main/java/com/baeldung/testing/truth/User.java new file mode 100644 index 0000000000..fe857dd265 --- /dev/null +++ b/testing/src/main/java/com/baeldung/testing/truth/User.java @@ -0,0 +1,57 @@ +package com.baeldung.testing.truth; + +import java.util.Arrays; +import java.util.List; +import java.util.Objects; + +public class User implements Comparable { + private String name = "John Doe"; + private List emails = Arrays.asList("contact@baeldung.com", "staff@baeldung.com"); + + public User() { + } + + public User(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public List getEmails() { + return emails; + } + + public void setEmails(List emails) { + this.emails = emails; + } + + @Override + public int hashCode() { + int hash = 5; + hash = 37 * hash + Objects.hashCode(this.name); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + final User other = (User) obj; + return Objects.equals(this.name, other.name); + } + + @Override + public int compareTo(User o) { + return this.getName() + .compareToIgnoreCase(o.getName()); + } + +} diff --git a/testing/src/main/java/com/baeldung/testing/truth/UserSubject.java b/testing/src/main/java/com/baeldung/testing/truth/UserSubject.java new file mode 100644 index 0000000000..2fd84085a0 --- /dev/null +++ b/testing/src/main/java/com/baeldung/testing/truth/UserSubject.java @@ -0,0 +1,46 @@ +package com.baeldung.testing.truth; + +import com.google.common.truth.ComparableSubject; +import com.google.common.truth.FailureStrategy; +import com.google.common.truth.IterableSubject; +import com.google.common.truth.SubjectFactory; +import com.google.common.truth.Truth; + +public class UserSubject extends ComparableSubject { + + private UserSubject(FailureStrategy failureStrategy, User target) { + super(failureStrategy, target); + } + + private static final SubjectFactory USER_SUBJECT_FACTORY = new SubjectFactory() { + @Override + public UserSubject getSubject(FailureStrategy failureStrategy, User target) { + return new UserSubject(failureStrategy, target); + } + }; + + public static UserSubject assertThat(User user) { + return Truth.assertAbout(USER_SUBJECT_FACTORY) + .that(user); + } + + // Our API begins here + public void hasName(String name) { + if (!actual().getName() + .equals(name)) { + fail("has name", name); + } + } + + public void hasNameIgnoringCase(String name) { + if (!actual().getName() + .equalsIgnoreCase(name)) { + fail("has name ignoring case", name); + } + } + + public IterableSubject emails() { + return Truth.assertThat(actual().getEmails()); + } + +} \ No newline at end of file diff --git a/testing/src/test/java/com/baeldung/junitparams/SafeAdditionUtilTest.java b/testing/src/test/java/com/baeldung/junitparams/SafeAdditionUtilTest.java new file mode 100644 index 0000000000..8ab49309cd --- /dev/null +++ b/testing/src/test/java/com/baeldung/junitparams/SafeAdditionUtilTest.java @@ -0,0 +1,54 @@ +package com.baeldung.junitparams; + +import static org.junit.Assert.assertEquals; + +import junitparams.FileParameters; +import junitparams.JUnitParamsRunner; +import junitparams.Parameters; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(JUnitParamsRunner.class) +public class SafeAdditionUtilTest { + + private SafeAdditionUtil serviceUnderTest = new SafeAdditionUtil(); + + @Test + @Parameters({ "1, 2, 3", "-10, 30, 20", "15, -5, 10", "-5, -10, -15" }) + public void whenWithAnnotationProvidedParams_thenSafeAdd(int a, int b, int expectedValue) { + assertEquals(expectedValue, serviceUnderTest.safeAdd(a, b)); + } + + @Test + @Parameters(method = "parametersToTestAdd") + public void whenWithNamedMethod_thendSafeAdd(int a, int b, int expectedValue) { + assertEquals(expectedValue, serviceUnderTest.safeAdd(a, b)); + } + + private Object[] parametersToTestAdd() { + return new Object[] { new Object[] { 1, 2, 3 }, new Object[] { -10, 30, 20 }, new Object[] { Integer.MAX_VALUE, 2, Integer.MAX_VALUE }, new Object[] { Integer.MIN_VALUE, -8, Integer.MIN_VALUE } }; + } + + @Test + @Parameters + public void whenWithnoParam_thenLoadByNameSafeAdd(int a, int b, int expectedValue) { + assertEquals(expectedValue, serviceUnderTest.safeAdd(a, b)); + } + + private Object[] parametersForWhenWithnoParam_thenLoadByNameSafeAdd() { + return new Object[] { new Object[] { 1, 2, 3 }, new Object[] { -10, 30, 20 }, new Object[] { Integer.MAX_VALUE, 2, Integer.MAX_VALUE }, new Object[] { Integer.MIN_VALUE, -8, Integer.MIN_VALUE } }; + } + + @Test + @Parameters(source = TestDataProvider.class) + public void whenWithNamedClass_thenSafeAdd(int a, int b, int expectedValue) { + assertEquals(expectedValue, serviceUnderTest.safeAdd(a, b)); + } + + @Test + @FileParameters("src/test/resources/JunitParamsTestParameters.csv") + public void whenWithCsvFile_thenSafeAdd(int a, int b, int expectedValue) { + assertEquals(expectedValue, serviceUnderTest.safeAdd(a, b)); + } + +} diff --git a/testing/src/test/java/com/baeldung/junitparams/TestDataProvider.java b/testing/src/test/java/com/baeldung/junitparams/TestDataProvider.java new file mode 100644 index 0000000000..d318345a56 --- /dev/null +++ b/testing/src/test/java/com/baeldung/junitparams/TestDataProvider.java @@ -0,0 +1,13 @@ +package com.baeldung.junitparams; + +public class TestDataProvider { + + public static Object[] provideBasicData() { + return new Object[] { new Object[] { 1, 2, 3 }, new Object[] { -10, 30, 20 }, new Object[] { 15, -5, 10 }, new Object[] { -5, -10, -15 } }; + } + + public static Object[] provideEdgeCaseData() { + return new Object[] { new Object[] { Integer.MAX_VALUE, 2, Integer.MAX_VALUE }, new Object[] { Integer.MIN_VALUE, -2, Integer.MIN_VALUE }, }; + } + +} diff --git a/testing/src/test/java/com/baeldung/testing/truth/GoogleTruthUnitTest.java b/testing/src/test/java/com/baeldung/testing/truth/GoogleTruthUnitTest.java new file mode 100644 index 0000000000..5be27db9db --- /dev/null +++ b/testing/src/test/java/com/baeldung/testing/truth/GoogleTruthUnitTest.java @@ -0,0 +1,561 @@ +package com.baeldung.testing.truth; + +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.Multimap; +import com.google.common.collect.Range; +import com.google.common.collect.Table; +import com.google.common.collect.TreeBasedTable; +import com.google.common.collect.TreeMultiset; +import static com.baeldung.testing.truth.UserSubject.*; +import static com.google.common.truth.Truth.*; +import static com.google.common.truth.Truth8.*; +import java.math.BigDecimal; +import java.util.Arrays; +import java.util.Comparator; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.regex.Pattern; +import java.util.stream.IntStream; +import java.util.stream.Stream; +import org.junit.Ignore; +import org.junit.Test; + +public class GoogleTruthUnitTest { + + @Test + public void whenComparingInteger_thenEqual() { + int anInt = 10; + + assertThat(anInt).isEqualTo(10); + } + + @Test + public void whenComparingFloat_thenIsBigger() { + float aFloat = 10.0f; + + assertThat(aFloat).isGreaterThan(1.0f); + } + + @Test + public void whenComparingDouble_thenIsSmaller() { + double aDouble = 10.0f; + + assertThat(aDouble).isLessThan(20.0); + } + + @Test + public void whenComparingFloat_thenWithinPrecision() { + float aFloat = 23.04f; + + assertThat(aFloat).isWithin(1.3f) + .of(23.3f); + } + + @Test + public void whenComparingFloat_thenNotWithinPrecision() { + float aFloat = 23.04f; + + assertThat(aFloat).isNotWithin(1.3f) + .of(100f); + } + + @Test + public void whenComparingDouble_thenWithinPrecision() { + double aDouble = 22.18; + + assertThat(aDouble).isWithin(2) + .of(23d); + } + + @Test + public void whenComparingDouble_thenNotWithinPrecision() { + double aDouble = 22.08; + + assertThat(aDouble).isNotWithin(2) + .of(100); + } + + @Test + public void whenComparingBigDecimal_thenEqualIgnoringScale() { + BigDecimal aBigDecimal = BigDecimal.valueOf(1000, 3); + + assertThat(aBigDecimal).isEqualToIgnoringScale(new BigDecimal(1.0)); + } + + @Test + public void whenCheckingBoolean_thenTrue() { + boolean aBoolean = true; + + assertThat(aBoolean).isTrue(); + } + + @Test + public void whenCheckingBoolean_thenFalse() { + boolean aBoolean = false; + + assertThat(aBoolean).isFalse(); + } + + @Test + public void whenComparingArrays_thenEqual() { + String[] firstArrayOfStrings = { "one", "two", "three" }; + String[] secondArrayOfStrings = { "one", "two", "three" }; + + assertThat(firstArrayOfStrings).isEqualTo(secondArrayOfStrings); + } + + @Test + public void whenComparingArrays_thenNotEqual() { + String[] firstArrayOfStrings = { "one", "two", "three" }; + String[] secondArrayOfStrings = { "three", "two", "one" }; + + assertThat(firstArrayOfStrings).isNotEqualTo(secondArrayOfStrings); + } + + @Test + public void whenCheckingArray_thenEmpty() { + Object[] anArray = {}; + + assertThat(anArray).isEmpty(); + } + + @Test + public void whenCheckingArray_thenNotEmpty() { + String[] arrayOfStrings = { "One String " }; + + assertThat(arrayOfStrings).isNotEmpty(); + } + + @Test + public void whenCheckingArrayOfDoubles_thenWithinPrecision() { + double[] arrayOfDoubles = { 1, 2, 3, 4, 5 }; + + assertThat(arrayOfDoubles).hasValuesWithin(5) + .of(6, 7, 8, 9, 10); + } + + @Test + public void whenComparingUsers_thenEqual() { + User aUser = new User("John Doe"); + User anotherUser = new User("John Doe"); + + assertThat(aUser).isEqualTo(anotherUser); + } + + @Test + public void whenComparingUser_thenIsNull() { + User aUser = null; + + assertThat(aUser).isNull(); + } + + @Test + public void whenComparingUser_thenNotNull() { + User aUser = new User(); + + assertThat(aUser).isNotNull(); + } + + @Test + public void whenComparingUser_thenInstanceOf() { + User aUser = new User(); + + assertThat(aUser).isInstanceOf(User.class); + } + + @Test + public void whenComparingUser_thenInList() { + User aUser = new User(); + + assertThat(aUser).isIn(Arrays.asList(1, 3, aUser, null)); + } + + @Test + public void whenComparingUser_thenNotInList() { + User aUser = new User(); + + assertThat(aUser).isNotIn(Arrays.asList(1, 3, "Three")); + } + + @Test + public void whenComparingNullUser_thenInList() { + User aUser = null; + User anotherUser = new User(); + + assertThat(aUser).isIn(Arrays.asList(1, 3, anotherUser, null)); + } + + @Test + public void whenCheckingString_thenStartsWithString() { + String aString = "This is a string"; + + assertThat(aString).startsWith("This"); + } + + @Test + public void whenCheckingString_thenContainsString() { + String aString = "This is a string"; + + assertThat(aString).contains("is a"); + } + + @Test + public void whenCheckingString_thenEndsWithString() { + String aString = "This is a string"; + + assertThat(aString).endsWith("string"); + } + + @Test + public void whenCheckingString_thenExpectedLength() { + String aString = "This is a string"; + + assertThat(aString).hasLength(16); + } + + @Test + public void whenCheckingString_thenEmpty() { + String aString = ""; + + assertThat(aString).isEmpty(); + } + + @Test + public void whenCheckingString_thenMatches() { + String aString = "The string to match"; + + assertThat(aString).matches(Pattern.compile("[a-zA-Z\\s]+")); + } + + @Test + public void whenCheckingComparable_thenAtLeast() { + Comparable aComparable = 5; + + assertThat(aComparable).isAtLeast(1); + } + + @Test + public void whenCheckingComparable_thenAtMost() { + Comparable aComparable = 5; + + assertThat(aComparable).isAtMost(10); + } + + @Test + public void whenCheckingComparable_thenInList() { + Comparable aComparable = 5; + + assertThat(aComparable).isIn(Arrays.asList(4, 5, 6)); + } + + @Test + public void whenCheckingComparable_thenInRange() { + Comparable aComparable = 5; + + assertThat(aComparable).isIn(Range.closed(1, 10)); + } + + @Test + public void whenCheckingComparable_thenNotInRange() { + Comparable aComparable = 5; + + assertThat(aComparable).isNotIn(Range.closed(10, 15)); + } + + @Test + public void whenComparingUsers_thenEquivalent() { + User aUser = new User(); + aUser.setName("John Doe"); + + User anotherUser = new User(); + anotherUser.setName("john doe"); + + assertThat(aUser).isEquivalentAccordingToCompareTo(anotherUser); + } + + @Test + public void whenCheckingIterable_thenContains() { + List aList = Arrays.asList(4, 5, 6); + + assertThat(aList).contains(5); + } + + @Test + public void whenCheckingIterable_thenDoesNotContains() { + List aList = Arrays.asList(4, 5, 6); + + assertThat(aList).doesNotContain(9); + } + + @Test + public void whenCheckingIterable_thenContainsAny() { + List aList = Arrays.asList(4, 5, 6); + + assertThat(aList).containsAnyOf(0, 5, 10); + } + + @Test + public void whenCheckingIterable_thenContainsAnyInList() { + List aList = Arrays.asList(1, 2, 3); + + assertThat(aList).containsAnyIn(Arrays.asList(1, 5, 10)); + } + + @Test + public void whenCheckingIterable_thenNoDuplicates() { + List aList = Arrays.asList(-2, -1, 0, 1, 2); + + assertThat(aList).containsNoDuplicates(); + } + + @Test + public void whenCheckingIterable_thenContainsNoneOf() { + List aList = Arrays.asList(4, 5, 6); + + assertThat(aList).containsNoneOf(9, 8, 7); + } + + @Test + public void whenCheckingIterable_thenContainsNoneIn() { + List aList = Arrays.asList(4, 5, 6); + + assertThat(aList).containsNoneIn(Arrays.asList(9, 10, 11)); + } + + @Test + public void whenCheckingIterable_thenContainsExactElements() { + List aList = Arrays.asList("10", "20", "30"); + List anotherList = Arrays.asList("10", "20", "30"); + + assertThat(aList).containsExactlyElementsIn(anotherList) + .inOrder(); + } + + @Test + public void whenCheckingIterable_thenOrdered() { + Set aSet = new LinkedHashSet<>(Arrays.asList("one", "three", "two")); + + assertThat(aSet).isOrdered(); + } + + @Test + public void givenComparator_whenCheckingIterable_thenOrdered() { + Comparator aComparator = (a, b) -> new Float(a).compareTo(new Float(b)); + + List aList = Arrays.asList("1", "012", "0020", "100"); + + assertThat(aList).isOrdered(aComparator); + } + + @Test + public void whenCheckingMap_thenContainsEntry() { + Map aMap = new HashMap<>(); + aMap.put("one", 1L); + + assertThat(aMap).containsEntry("one", 1L); + } + + @Test + public void whenCheckingMap_thenContainsKey() { + Map map = new HashMap<>(); + map.put("one", 1L); + + assertThat(map).containsKey("one"); + } + + @Test + public void whenCheckingMap_thenContainsEntries() { + Map aMap = new HashMap<>(); + aMap.put("first", 1L); + aMap.put("second", 2.0); + aMap.put("third", 3f); + + Map anotherMap = new HashMap<>(aMap); + + assertThat(aMap).containsExactlyEntriesIn(anotherMap); + } + + @Test + public void whenCheckingException_thenInstanceOf() { + Exception anException = new IllegalArgumentException(new NumberFormatException()); + + assertThat(anException).hasCauseThat() + .isInstanceOf(NumberFormatException.class); + } + + @Test + public void whenCheckingException_thenCauseMessageIsKnown() { + Exception anException = new IllegalArgumentException("Bad value"); + + assertThat(anException).hasMessageThat() + .startsWith("Bad"); + } + + @Test + public void whenCheckingClass_thenIsAssignable() { + Class aClass = Double.class; + + assertThat(aClass).isAssignableTo(Number.class); + } + + // Java 8 Tests + @Test + public void whenCheckingJavaOptional_thenHasValue() { + Optional anOptional = Optional.of(1); + + assertThat(anOptional).hasValue(1); + } + + @Test + public void whenCheckingJavaOptional_thenPresent() { + Optional anOptional = Optional.of("Baeldung"); + + assertThat(anOptional).isPresent(); + } + + @Test + public void whenCheckingJavaOptional_thenEmpty() { + Optional anOptional = Optional.empty(); + + assertThat(anOptional).isEmpty(); + } + + @Test + public void whenCheckingStream_thenContainsInOrder() { + Stream anStream = Stream.of(1, 2, 3); + + assertThat(anStream).containsAllOf(1, 2, 3) + .inOrder(); + } + + @Test + public void whenCheckingStream_thenDoesNotContain() { + Stream anStream = IntStream.range(1, 100) + .boxed(); + + assertThat(anStream).doesNotContain(0); + } + + // Guava Tests + @Test + public void whenCheckingGuavaOptional_thenIsAbsent() { + com.google.common.base.Optional anOptional = com.google.common.base.Optional.absent(); + + assertThat(anOptional).isAbsent(); + } + + @Test + public void whenCheckingGuavaMultimap_thenExpectedSize() { + Multimap aMultimap = ArrayListMultimap.create(); + aMultimap.put("one", 1L); + aMultimap.put("one", 2.0); + + assertThat(aMultimap).valuesForKey("one") + .hasSize(2); + } + + @Test + public void whenCheckingGuavaMultiset_thenExpectedCount() { + TreeMultiset aMultiset = TreeMultiset.create(); + aMultiset.add("baeldung", 10); + + assertThat(aMultiset).hasCount("baeldung", 10); + } + + @Test + public void whenCheckingGuavaTable_thenContains() { + Table aTable = getDummyGuavaTable(); + + assertThat(aTable).contains("firstRow", "firstColumn"); + } + + @Test + public void whenCheckingGuavaTable_thenContainsCell() { + Table aTable = getDummyGuavaTable(); + + assertThat(aTable).containsCell("firstRow", "firstColumn", "baeldung"); + } + + @Test + public void whenCheckingGuavaTable_thenContainsRow() { + Table aTable = getDummyGuavaTable(); + + assertThat(aTable).containsRow("firstRow"); + } + + @Test + public void whenCheckingGuavaTable_thenContainsColumn() { + Table aTable = getDummyGuavaTable(); + + assertThat(aTable).containsColumn("firstColumn"); + } + + @Test + public void whenCheckingGuavaTable_thenContainsValue() { + Table aTable = getDummyGuavaTable(); + + assertThat(aTable).containsValue("baeldung"); + } + + @Ignore + @Test + public void whenFailingAssertion_thenMessagePrefix() { + User aUser = new User(); + + assertThat(aUser).named("User [%s]", aUser.getName()) + .isNull(); + } + + @Ignore + @Test + public void whenFailingAssertion_thenCustomMessage() { + User aUser = new User(); + + assertWithMessage("TEST-985: Secret user subject was NOT null!").that(aUser) + .isNull(); + } + + @Ignore + @Test + public void whenFailingAssertion_thenCustomMessageAndPrefix() { + User aUser = new User(); + + assertWithMessage("TEST-985: Secret user subject was NOT null!").that(aUser) + .named("User [%s]", aUser.getName()) + .isNull(); + } + + private Table getDummyGuavaTable() { + Table aTable = TreeBasedTable.create(); + aTable.put("firstRow", "firstColumn", "baeldung"); + return aTable; + } + + // Custom User type + @Test + public void whenCheckingUser_thenHasName() { + User aUser = new User(); + + assertThat(aUser).hasName("John Doe"); + } + + @Test + public void whenCheckingUser_thenHasNameIgnoringCase() { + User aUser = new User(); + + assertThat(aUser).hasNameIgnoringCase("john doe"); + } + + @Test + public void givenUser_whenCheckingEmails_thenExpectedSize() { + User aUser = new User(); + + assertThat(aUser).emails() + .hasSize(2); + } + +} diff --git a/testing/src/test/resources/JunitParamsTestParameters.csv b/testing/src/test/resources/JunitParamsTestParameters.csv new file mode 100644 index 0000000000..84eb5a0b23 --- /dev/null +++ b/testing/src/test/resources/JunitParamsTestParameters.csv @@ -0,0 +1,4 @@ +1,2,3 +-10, 30, 20 +15, -5, 10 +-5, -10, -15 \ No newline at end of file