diff --git a/core-java-modules/core-java-11-2/pom.xml b/core-java-modules/core-java-11-2/pom.xml index 3d008f5294..5f76c0bf3b 100644 --- a/core-java-modules/core-java-11-2/pom.xml +++ b/core-java-modules/core-java-11-2/pom.xml @@ -50,6 +50,11 @@ ${junit.jupiter.version} test + + org.apache.commons + commons-lang3 + ${commons-lang3.version} + @@ -73,6 +78,7 @@ 5.7.0 3.17.2 5.11.1 + 3.12.0 \ No newline at end of file diff --git a/core-java-modules/core-java-11-2/src/test/java/com/baeldung/version/VersionUnitTest.java b/core-java-modules/core-java-11-2/src/test/java/com/baeldung/version/VersionUnitTest.java new file mode 100644 index 0000000000..fb7d5647a5 --- /dev/null +++ b/core-java-modules/core-java-11-2/src/test/java/com/baeldung/version/VersionUnitTest.java @@ -0,0 +1,48 @@ +package com.baeldung.version; + +import org.apache.commons.lang3.SystemUtils; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +public class VersionUnitTest { + + @Test + public void givenJava_whenUsingRuntime_thenGetVersion() { + String expectedVersion = "11"; + Runtime.Version runtimeVersion = Runtime.version(); + String version = String.valueOf(runtimeVersion.version().get(0)); + Assertions.assertThat(version).isEqualTo(expectedVersion); + } + + @Test + @Disabled("Only valid for Java 8 and lower") + public void givenJava_whenUsingCommonsLang_thenGetVersion() { + int expectedVersion = 8; + String[] versionElements = SystemUtils.JAVA_SPECIFICATION_VERSION.split("\\."); + int discard = Integer.parseInt(versionElements[0]); + int version; + if (discard == 1) { + version = Integer.parseInt(versionElements[1]); + } else { + version = discard; + } + Assertions.assertThat(version).isEqualTo(expectedVersion); + } + + @Test + @Disabled("Only valid for Java 8 and lower") + public void givenJava_whenUsingSystemProp_thenGetVersion() { + int expectedVersion = 8; + String[] versionElements = System.getProperty("java.version").split("\\."); + int discard = Integer.parseInt(versionElements[0]); + int version; + if (discard == 1) { + version = Integer.parseInt(versionElements[1]); + } else { + version = discard; + } + Assertions.assertThat(version).isEqualTo(expectedVersion); + } +} + diff --git a/core-java-modules/core-java-jpms/decoupling-pattern2/consumermodule2/pom.xml b/core-java-modules/core-java-jpms/decoupling-pattern2/consumermodule2/pom.xml index 13d0b2d201..774319a067 100644 --- a/core-java-modules/core-java-jpms/decoupling-pattern2/consumermodule2/pom.xml +++ b/core-java-modules/core-java-jpms/decoupling-pattern2/consumermodule2/pom.xml @@ -45,4 +45,4 @@ 1.0 - \ No newline at end of file + diff --git a/core-java-modules/core-java-lang-4/src/main/java/com/baeldung/hash/Player.java b/core-java-modules/core-java-lang-4/src/main/java/com/baeldung/hash/Player.java new file mode 100644 index 0000000000..79d2396816 --- /dev/null +++ b/core-java-modules/core-java-lang-4/src/main/java/com/baeldung/hash/Player.java @@ -0,0 +1,91 @@ +package com.baeldung.hash; + +import java.util.Objects; + +public class Player { + private String firstName; + private String lastName; + private String position; + + public Player() { + + } + + public Player(String firstName, String lastName, String position) { + this.firstName = firstName; + this.lastName = lastName; + this.position = position; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public String getPosition() { + return position; + } + + public void setPosition(String position) { + this.position = position; + } + + @Override + public int hashCode() { + return Objects.hash(firstName, lastName, position); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null) { + return false; + } + + if (getClass() != obj.getClass()) { + return false; + } + + Player other = (Player) obj; + + if (firstName == null) { + if (other.firstName != null) { + return false; + } + } else if (!firstName.equals(other.firstName)) { + return false; + } + + if (lastName == null) { + if (other.lastName != null) { + return false; + } + } else if (!lastName.equals(other.lastName)) { + return false; + } + + if (position == null) { + if (other.position != null) { + return false; + } + } else if (!position.equals(other.position)) { + return false; + } + return true; + } + +} diff --git a/core-java-modules/core-java-lang-4/src/test/java/com/baeldung/hash/HashCodeUnitTest.java b/core-java-modules/core-java-lang-4/src/test/java/com/baeldung/hash/HashCodeUnitTest.java new file mode 100644 index 0000000000..d1a9e06611 --- /dev/null +++ b/core-java-modules/core-java-lang-4/src/test/java/com/baeldung/hash/HashCodeUnitTest.java @@ -0,0 +1,67 @@ +package com.baeldung.hash; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; + +import java.util.Objects; + +import org.junit.Test; + +public class HashCodeUnitTest { + + @Test + public void whenCallingObjectsHashCodeOnIndenticalObjects_thenSameHashCodeReturned() { + String stringOne = "test"; + String stringTwo = "test"; + int hashCode1 = Objects.hashCode(stringOne); + int hashCode2 = Objects.hashCode(stringTwo); + + assertEquals(hashCode1, hashCode2); + } + + @Test + public void whenCallingObjectsHashCodeOnNullObject_thenZeroReturned() { + String nullString = null; + int hashCode = Objects.hashCode(nullString); + assertEquals(0, hashCode); + } + + @Test + public void whenCallingObjectHashCodeOnIndenticalObjects_thenSameHashCodeReturned() { + Double valueOne = Double.valueOf(1.0012); + Double valueTwo = Double.valueOf(1.0012); + + int hashCode1 = valueOne.hashCode(); + int hashCode2 = valueTwo.hashCode(); + + assertEquals(hashCode1, hashCode2); + } + + @Test(expected = NullPointerException.class) + public void whenCallingObjectHashCodeOnNullObject_theNullPointerExceptionThrown() { + Double value = null; + value.hashCode(); + } + + @Test + public void whenCallingObjectsHashOnStrings_thenSameHashCodeReturned() { + String strOne = "one"; + String strTwo = "two"; + String strOne2 = "one"; + String strTwo2 = "two"; + + int hashCode1 = Objects.hash(strOne, strTwo); + int hashCode2 = Objects.hash(strOne2, strTwo2); + + assertEquals(hashCode1, hashCode2); + } + + @Test + public void whenCallingObjectsHashOnSingleString_thenDifferentHashcodeFromObjectsHashCodeCallReturned() { + String testString = "test string"; + int hashCode1 = Objects.hash(testString); + int hashCode2 = Objects.hashCode(testString); + + assertNotEquals(hashCode1, hashCode2); + } +} diff --git a/core-java-modules/core-java-lang-4/src/test/java/com/baeldung/hash/PlayerUnitTest.java b/core-java-modules/core-java-lang-4/src/test/java/com/baeldung/hash/PlayerUnitTest.java new file mode 100644 index 0000000000..fe0ef8a727 --- /dev/null +++ b/core-java-modules/core-java-lang-4/src/test/java/com/baeldung/hash/PlayerUnitTest.java @@ -0,0 +1,33 @@ +package com.baeldung.hash; + +import static org.junit.Assert.assertEquals; + +import java.util.Arrays; + +import org.junit.Test; + +public class PlayerUnitTest { + + @Test + public void whenCallingHashCodeOnIdenticalValue_thenSameHashCodeReturned() { + Player player = new Player("Eduardo", "Rodriguez", "Pitcher"); + Player indenticalPlayer = new Player("Eduardo", "Rodriguez", "Pitcher"); + + int hashCode1 = player.hashCode(); + int hashCode2 = player.hashCode(); + int hashCode3 = indenticalPlayer.hashCode(); + + assertEquals(hashCode1, hashCode2); + assertEquals(hashCode1, hashCode3); + } + + @Test + public void whenCallingHashCodeAndArraysHashCode_thenSameHashCodeReturned() { + Player player = new Player("Bobby", "Dalbec", "First Base"); + int hashcode1 = player.hashCode(); + String[] playerInfo = { "Bobby", "Dalbec", "First Base" }; + int hashcode2 = Arrays.hashCode(playerInfo); + + assertEquals(hashcode1, hashcode2); + } +} diff --git a/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/interfacevsabstractclass/Car.java b/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/interfacevsabstractclass/Car.java new file mode 100644 index 0000000000..6f17ecc536 --- /dev/null +++ b/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/interfacevsabstractclass/Car.java @@ -0,0 +1,42 @@ +package com.baeldung.interfacevsabstractclass; + +public class Car extends Vehicle { + + public Car(String vechicleName) { + super(vechicleName); + } + + public Car(String vechicleName, String vehicleModel) { + super(vechicleName, vehicleModel); + } + + public Car(String vechicleName, String vehicleModel, Long makeYear) { + super(vechicleName, vehicleModel, makeYear); + } + + @Override + protected void start() { + // code implementation details on starting a car. + } + + @Override + protected void stop() { + // code implementation details on stopping a car. + } + + @Override + protected void drive() { + // code implementation details on start driving a car. + } + + @Override + protected void changeGear() { + // code implementation details on changing the car gear. + } + + @Override + protected void reverse() { + // code implementation details on reverse driving a car. + } + +} diff --git a/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/interfacevsabstractclass/ImageSender.java b/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/interfacevsabstractclass/ImageSender.java new file mode 100644 index 0000000000..1948cc6583 --- /dev/null +++ b/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/interfacevsabstractclass/ImageSender.java @@ -0,0 +1,12 @@ +package com.baeldung.interfacevsabstractclass; + +import java.io.File; + +public class ImageSender implements Sender { + + @Override + public void send(File fileToBeSent) { + // image sending implementation code. + } + +} \ No newline at end of file diff --git a/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/interfacevsabstractclass/Sender.java b/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/interfacevsabstractclass/Sender.java new file mode 100644 index 0000000000..fde6527ef6 --- /dev/null +++ b/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/interfacevsabstractclass/Sender.java @@ -0,0 +1,8 @@ +package com.baeldung.interfacevsabstractclass; + +import java.io.File; + +public interface Sender { + + void send(File fileToBeSent); +} diff --git a/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/interfacevsabstractclass/Vehicle.java b/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/interfacevsabstractclass/Vehicle.java new file mode 100644 index 0000000000..d98b8ca93b --- /dev/null +++ b/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/interfacevsabstractclass/Vehicle.java @@ -0,0 +1,57 @@ +package com.baeldung.interfacevsabstractclass; + +public abstract class Vehicle { + + private String vehicleName; + private String vehicleModel; + private Long makeYear; + + public Vehicle(String vehicleName) { + this.vehicleName = vehicleName; + } + + public Vehicle(String vehicleName, String vehicleModel) { + this(vehicleName); + this.vehicleModel = vehicleModel; + } + + public Vehicle(String vechicleName, String vehicleModel, Long makeYear) { + this(vechicleName, vehicleModel); + this.makeYear = makeYear; + } + + public String getVehicleName() { + return vehicleName; + } + + public void setVehicleName(String vehicleName) { + this.vehicleName = vehicleName; + } + + public String getVehicleModel() { + return vehicleModel; + } + + public void setVehicleModel(String vehicleModel) { + this.vehicleModel = vehicleModel; + } + + public Long getMakeYear() { + return makeYear; + } + + public void setMakeYear(Long makeYear) { + this.makeYear = makeYear; + } + + protected abstract void start(); + + protected abstract void stop(); + + protected abstract void drive(); + + protected abstract void changeGear(); + + protected abstract void reverse(); + +} diff --git a/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/interfacevsabstractclass/VideoSender.java b/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/interfacevsabstractclass/VideoSender.java new file mode 100644 index 0000000000..71f8050590 --- /dev/null +++ b/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/interfacevsabstractclass/VideoSender.java @@ -0,0 +1,12 @@ +package com.baeldung.interfacevsabstractclass; + +import java.io.File; + +public class VideoSender implements Sender { + + @Override + public void send(File fileToBeSent) { + // video sending implementation code + } + +} \ No newline at end of file diff --git a/core-java-modules/core-java-lang-oop-patterns/src/test/java/com/baeldung/interfacevsabstractclass/SenderUnitTest.java b/core-java-modules/core-java-lang-oop-patterns/src/test/java/com/baeldung/interfacevsabstractclass/SenderUnitTest.java new file mode 100644 index 0000000000..6419721b3a --- /dev/null +++ b/core-java-modules/core-java-lang-oop-patterns/src/test/java/com/baeldung/interfacevsabstractclass/SenderUnitTest.java @@ -0,0 +1,23 @@ +package com.baeldung.interfacevsabstractclass; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; + +import com.baeldung.interfacevsabstractclass.ImageSender; +import com.baeldung.interfacevsabstractclass.Sender; + +import java.io.File; + +class SenderUnitTest { + + public final static String IMAGE_FILE_PATH = "/sample_image_file_path/photo.jpg"; + + @Test + void givenImageUploaded_whenButtonClicked_thenSendImage() { + File imageFile = new File(IMAGE_FILE_PATH); + + Sender sender = new ImageSender(); + sender.send(imageFile); + } + +} diff --git a/core-java-modules/core-java-lang-oop-patterns/src/test/java/com/baeldung/interfacevsabstractclass/VehicleUnitTest.java b/core-java-modules/core-java-lang-oop-patterns/src/test/java/com/baeldung/interfacevsabstractclass/VehicleUnitTest.java new file mode 100644 index 0000000000..1650ab9257 --- /dev/null +++ b/core-java-modules/core-java-lang-oop-patterns/src/test/java/com/baeldung/interfacevsabstractclass/VehicleUnitTest.java @@ -0,0 +1,22 @@ +package com.baeldung.interfacevsabstractclass; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +import com.baeldung.interfacevsabstractclass.Car; +import com.baeldung.interfacevsabstractclass.Vehicle; + +class VehicleUnitTest { + + @Test + void givenVehicle_whenNeedToDrive_thenStart() { + Vehicle car = new Car("BMW"); + + car.start(); + car.drive(); + car.changeGear(); + car.stop(); + } + +} diff --git a/core-java-modules/core-java-networking-2/src/test/java/com/baeldung/download/FileDownloadIntegrationTest.java b/core-java-modules/core-java-networking-2/src/test/java/com/baeldung/download/FileDownloadIntegrationTest.java index 16017ee482..987a69582f 100644 --- a/core-java-modules/core-java-networking-2/src/test/java/com/baeldung/download/FileDownloadIntegrationTest.java +++ b/core-java-modules/core-java-networking-2/src/test/java/com/baeldung/download/FileDownloadIntegrationTest.java @@ -17,9 +17,9 @@ import static org.junit.Assert.assertTrue; public class FileDownloadIntegrationTest { - static String FILE_URL = "http://ovh.net/files/1Mio.dat"; + static String FILE_URL = "https://s3.amazonaws.com/baeldung.com/Do+JSON+with+Jackson+by+Baeldung.pdf"; static String FILE_NAME = "file.dat"; - static String FILE_MD5_HASH = "6cb91af4ed4c60c11613b75cd1fc6116"; + static String FILE_MD5_HASH = "c959feb066b37f5c4f0e0f45bbbb4f86"; @Test public void givenJavaIO_whenDownloadingFile_thenDownloadShouldBeCorrect() throws NoSuchAlgorithmException, IOException { diff --git a/core-java-modules/core-java-streams-3/pom.xml b/core-java-modules/core-java-streams-3/pom.xml index 659f1937f2..01b83f229a 100644 --- a/core-java-modules/core-java-streams-3/pom.xml +++ b/core-java-modules/core-java-streams-3/pom.xml @@ -27,6 +27,17 @@ ${lombok.version} provided + + org.openjdk.jmh + jmh-core + ${jmh.version} + + + org.openjdk.jmh + jmh-generator-annprocess + ${jmh.version} + test + org.assertj @@ -44,11 +55,30 @@ true + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.8 + 1.8 + + + org.openjdk.jmh + jmh-generator-annprocess + ${jmh.version} + + + + + + 1.18.20 3.6.1 + 1.29 \ No newline at end of file diff --git a/core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/BenchmarkRunner.java b/core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/BenchmarkRunner.java new file mode 100644 index 0000000000..461d728ad0 --- /dev/null +++ b/core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/BenchmarkRunner.java @@ -0,0 +1,9 @@ +package com.baeldung.streams.parallel; + +public class BenchmarkRunner { + + public static void main(String[] args) throws Exception { + org.openjdk.jmh.Main.main(args); + } + +} diff --git a/core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/DifferentSourceSplitting.java b/core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/DifferentSourceSplitting.java new file mode 100644 index 0000000000..9ad569df30 --- /dev/null +++ b/core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/DifferentSourceSplitting.java @@ -0,0 +1,54 @@ +package com.baeldung.streams.parallel; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.stream.IntStream; + +public class DifferentSourceSplitting { + + private static final List arrayListOfNumbers = new ArrayList<>(); + private static final List linkedListOfNumbers = new LinkedList<>(); + + static { + IntStream.rangeClosed(1, 1_000_000).forEach(i -> { + arrayListOfNumbers.add(i); + linkedListOfNumbers.add(i); + }); + } + + @Benchmark + @BenchmarkMode(Mode.AverageTime) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + public static void differentSourceArrayListSequential() { + arrayListOfNumbers.stream().reduce(0, Integer::sum); + } + + @Benchmark + @BenchmarkMode(Mode.AverageTime) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + public static void differentSourceArrayListParallel() { + arrayListOfNumbers.parallelStream().reduce(0, Integer::sum); + } + + @Benchmark + @BenchmarkMode(Mode.AverageTime) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + public static void differentSourceLinkedListSequential() { + linkedListOfNumbers.stream().reduce(0, Integer::sum); + } + + @Benchmark + @BenchmarkMode(Mode.AverageTime) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + public static void differentSourceLinkedListParallel() { + linkedListOfNumbers.parallelStream().reduce(0, Integer::sum); + } + +} diff --git a/core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/MemoryLocalityCosts.java b/core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/MemoryLocalityCosts.java new file mode 100644 index 0000000000..bc5cbf491b --- /dev/null +++ b/core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/MemoryLocalityCosts.java @@ -0,0 +1,52 @@ +package com.baeldung.streams.parallel; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; + +import java.util.Arrays; +import java.util.concurrent.TimeUnit; +import java.util.stream.IntStream; + +public class MemoryLocalityCosts { + + private static final int[] intArray = new int[1_000_000]; + private static final Integer[] integerArray = new Integer[1_000_000]; + + static { + IntStream.rangeClosed(1, 1_000_000).forEach(i -> { + intArray[i-1] = i; + integerArray[i-1] = i; + }); + } + + @Benchmark + @BenchmarkMode(Mode.AverageTime) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + public static void localityIntArraySequential() { + Arrays.stream(intArray).reduce(0, Integer::sum); + } + + @Benchmark + @BenchmarkMode(Mode.AverageTime) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + public static void localityIntArrayParallel() { + Arrays.stream(intArray).parallel().reduce(0, Integer::sum); + } + + @Benchmark + @BenchmarkMode(Mode.AverageTime) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + public static void localityIntegerArraySequential() { + Arrays.stream(integerArray).reduce(0, Integer::sum); + } + + @Benchmark + @BenchmarkMode(Mode.AverageTime) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + public static void localityIntegerArrayParallel() { + Arrays.stream(integerArray).parallel().reduce(0, Integer::sum); + } + +} diff --git a/core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/MergingCosts.java b/core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/MergingCosts.java new file mode 100644 index 0000000000..a9919dbe72 --- /dev/null +++ b/core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/MergingCosts.java @@ -0,0 +1,52 @@ +package com.baeldung.streams.parallel; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +public class MergingCosts { + + private static final List arrayListOfNumbers = new ArrayList<>(); + + static { + IntStream.rangeClosed(1, 1_000_000).forEach(i -> { + arrayListOfNumbers.add(i); + }); + } + + @Benchmark + @BenchmarkMode(Mode.AverageTime) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + public static void mergingCostsSumSequential() { + arrayListOfNumbers.stream().reduce(0, Integer::sum); + } + + @Benchmark + @BenchmarkMode(Mode.AverageTime) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + public static void mergingCostsSumParallel() { + arrayListOfNumbers.stream().parallel().reduce(0, Integer::sum); + } + + @Benchmark + @BenchmarkMode(Mode.AverageTime) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + public static void mergingCostsGroupingSequential() { + arrayListOfNumbers.stream().collect(Collectors.toSet()); + } + + @Benchmark + @BenchmarkMode(Mode.AverageTime) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + public static void mergingCostsGroupingParallel() { + arrayListOfNumbers.stream().parallel().collect(Collectors.toSet()); + } + +} diff --git a/core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/ParallelStream.java b/core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/ParallelStream.java new file mode 100644 index 0000000000..f236f418e8 --- /dev/null +++ b/core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/ParallelStream.java @@ -0,0 +1,15 @@ +package com.baeldung.streams.parallel; + +import java.util.Arrays; +import java.util.List; + +public class ParallelStream { + + public static void main(String[] args) { + List listOfNumbers = Arrays.asList(1, 2, 3, 4); + listOfNumbers.parallelStream().forEach(number -> + System.out.println(number + " " + Thread.currentThread().getName()) + ); + } + +} diff --git a/core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/SequentialStream.java b/core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/SequentialStream.java new file mode 100644 index 0000000000..01379130fa --- /dev/null +++ b/core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/SequentialStream.java @@ -0,0 +1,15 @@ +package com.baeldung.streams.parallel; + +import java.util.Arrays; +import java.util.List; + +public class SequentialStream { + + public static void main(String[] args) { + List listOfNumbers = Arrays.asList(1, 2, 3, 4); + listOfNumbers.stream().forEach(number -> + System.out.println(number + " " + Thread.currentThread().getName()) + ); + } + +} diff --git a/core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/SplittingCosts.java b/core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/SplittingCosts.java new file mode 100644 index 0000000000..d1e878df1f --- /dev/null +++ b/core-java-modules/core-java-streams-3/src/main/java/com/baeldung/streams/parallel/SplittingCosts.java @@ -0,0 +1,27 @@ +package com.baeldung.streams.parallel; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; + +import java.util.concurrent.TimeUnit; +import java.util.stream.IntStream; + +public class SplittingCosts { + + @Benchmark + @BenchmarkMode(Mode.AverageTime) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + public static void sourceSplittingIntStreamSequential() { + IntStream.rangeClosed(1, 100).reduce(0, Integer::sum); + } + + @Benchmark + @BenchmarkMode(Mode.AverageTime) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + public static void sourceSplittingIntStreamParallel() { + IntStream.rangeClosed(1, 100).parallel().reduce(0, Integer::sum); + } + +} diff --git a/core-java-modules/core-java-streams-3/src/test/java/com/baeldung/streams/parallel/ForkJoinUnitTest.java b/core-java-modules/core-java-streams-3/src/test/java/com/baeldung/streams/parallel/ForkJoinUnitTest.java new file mode 100644 index 0000000000..f9aab8ed6c --- /dev/null +++ b/core-java-modules/core-java-streams-3/src/test/java/com/baeldung/streams/parallel/ForkJoinUnitTest.java @@ -0,0 +1,46 @@ +package com.baeldung.streams.parallel; + +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ForkJoinPool; + +import static org.assertj.core.api.Assertions.assertThat; + +class ForkJoinUnitTest { + + @Test + void givenSequentialStreamOfNumbers_whenReducingSumWithIdentityFive_thenResultIsCorrect() { + List listOfNumbers = Arrays.asList(1, 2, 3, 4); + int sum = listOfNumbers.stream().reduce(5, Integer::sum); + assertThat(sum).isEqualTo(15); + } + + @Test + void givenParallelStreamOfNumbers_whenReducingSumWithIdentityFive_thenResultIsNotCorrect() { + List listOfNumbers = Arrays.asList(1, 2, 3, 4); + int sum = listOfNumbers.parallelStream().reduce(5, Integer::sum); + assertThat(sum).isNotEqualTo(15); + } + + @Test + void givenParallelStreamOfNumbers_whenReducingSumWithIdentityZero_thenResultIsCorrect() { + List listOfNumbers = Arrays.asList(1, 2, 3, 4); + int sum = listOfNumbers.parallelStream().reduce(0, Integer::sum) + 5; + assertThat(sum).isEqualTo(15); + } + + @Test + public void givenParallelStreamOfNumbers_whenUsingCustomThreadPool_thenResultIsCorrect() + throws InterruptedException, ExecutionException { + List listOfNumbers = Arrays.asList(1, 2, 3, 4); + ForkJoinPool customThreadPool = new ForkJoinPool(4); + int sum = customThreadPool.submit( + () -> listOfNumbers.parallelStream().reduce(0, Integer::sum)).get(); + customThreadPool.shutdown(); + assertThat(sum).isEqualTo(10); + } + +} diff --git a/core-java-modules/core-java-string-operations-3/src/test/java/com/baeldung/splitkeepdelimiters/SplitAndKeepDelimitersUnitTest.java b/core-java-modules/core-java-string-operations-3/src/test/java/com/baeldung/splitkeepdelimiters/SplitAndKeepDelimitersUnitTest.java new file mode 100644 index 0000000000..ede8be4c05 --- /dev/null +++ b/core-java-modules/core-java-string-operations-3/src/test/java/com/baeldung/splitkeepdelimiters/SplitAndKeepDelimitersUnitTest.java @@ -0,0 +1,59 @@ +package com.baeldung.splitkeepdelimiters; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.regex.Pattern; + +import org.apache.commons.lang3.StringUtils; +import org.junit.jupiter.api.Test; + +import com.google.common.base.Splitter; + +public class SplitAndKeepDelimitersUnitTest { + + private final String positivelookAheadRegex = "((?=@))"; + private final String positivelookBehindRegex = "((?<=@))"; + private final String positivelookAroundRegex = "((?=@)|(?<=@))"; + private final String positiveLookAroundMultiDelimiterRegex = "((?=:|#|@)|(?<=:|#|@))"; + + private String text = "Hello@World@This@Is@A@Java@Program"; + private String textMixed = "@HelloWorld@This:Is@A#Java#Program"; + private String textMixed2 = "pg@no;10@hello;world@this;is@a#10words;Java#Program"; + + @Test + public void givenString_splitAndKeepDelimiters_using_javaLangString() { + + assertThat(text.split(positivelookAheadRegex)).containsExactly("Hello", "@World", "@This", "@Is", "@A", "@Java", "@Program"); + + assertThat(text.split(positivelookBehindRegex)).containsExactly("Hello@", "World@", "This@", "Is@", "A@", "Java@", "Program"); + + assertThat(text.split(positivelookAroundRegex)).containsExactly("Hello", "@", "World", "@", "This", "@", "Is", "@", "A", "@", "Java", "@", "Program"); + + assertThat(textMixed.split(positiveLookAroundMultiDelimiterRegex)).containsExactly("@", "HelloWorld", "@", "This", ":", "Is", "@", "A", "#", "Java", "#", "Program"); + + } + + @Test + public void givenString_splitAndKeepDelimiters_using_ApacheCommonsLang3StringUtils() { + + assertThat(StringUtils.splitByCharacterType(textMixed2)).containsExactly("pg", "@", "no", ";", "10", "@", "hello", ";", "world", "@", "this", ";", "is", "@", "a", "#", "10", "words", ";", "J", "ava", "#", "P", "rogram"); + + } + + @Test + public void givenString_splitAndKeepDelimiters_using_GuavaSplitter() { + + assertThat(Splitter.onPattern(positivelookAroundRegex) + .splitToList(text)).containsExactly("Hello", "@", "World", "@", "This", "@", "Is", "@", "A", "@", "Java", "@", "Program"); + + assertThat(Splitter.on(Pattern.compile(positivelookAroundRegex)) + .splitToList(text)).containsExactly("Hello", "@", "World", "@", "This", "@", "Is", "@", "A", "@", "Java", "@", "Program"); + + assertThat(Splitter.onPattern(positiveLookAroundMultiDelimiterRegex) + .splitToList(textMixed)).containsExactly("@", "HelloWorld", "@", "This", ":", "Is", "@", "A", "#", "Java", "#", "Program"); + + assertThat(Splitter.on(Pattern.compile(positiveLookAroundMultiDelimiterRegex)) + .splitToList(textMixed)).containsExactly("@", "HelloWorld", "@", "This", ":", "Is", "@", "A", "#", "Java", "#", "Program"); + + } +} diff --git a/javaxval/src/test/java/com/baeldung/javaxval/bigdecimal/InvoiceUnitTest.java b/javaxval/src/test/java/com/baeldung/javaxval/bigdecimal/InvoiceUnitTest.java index 2df0cf81af..801d7966a5 100644 --- a/javaxval/src/test/java/com/baeldung/javaxval/bigdecimal/InvoiceUnitTest.java +++ b/javaxval/src/test/java/com/baeldung/javaxval/bigdecimal/InvoiceUnitTest.java @@ -1,18 +1,17 @@ package com.baeldung.javaxval.bigdecimal; -import static org.assertj.core.api.Assertions.assertThat; - -import java.math.BigDecimal; -import java.util.Set; - -import javax.validation.ConstraintViolation; -import javax.validation.Validation; -import javax.validation.Validator; - import com.baeldung.javaxval.LocaleAwareUnitTest; import org.junit.BeforeClass; import org.junit.Test; +import javax.validation.ConstraintViolation; +import javax.validation.Validation; +import javax.validation.Validator; +import java.math.BigDecimal; +import java.util.Set; + +import static org.assertj.core.api.Assertions.assertThat; + public class InvoiceUnitTest extends LocaleAwareUnitTest { private static Validator validator; @@ -24,41 +23,67 @@ public class InvoiceUnitTest extends LocaleAwareUnitTest { } @Test - public void whenPriceIntegerDigitLessThanThreeWithDecimalValue_thenShouldGiveConstraintViolations() { - Invoice invoice = new Invoice(new BigDecimal(10.21), "Book purchased"); + public void whenLessThanThreeIntegerDigits_thenShouldNotGiveConstraintViolations() { + Invoice invoice = new Invoice(new BigDecimal("10.21"), "Book purchased"); Set> violations = validator.validate(invoice); - assertThat(violations.size()).isEqualTo(1); - violations.forEach(action -> assertThat(action.getMessage()).isEqualTo("numeric value out of bounds (<3 digits>.<2 digits> expected)")); + assertThat(violations).isEmpty(); } @Test - public void whenPriceIntegerDigitLessThanThreeWithIntegerValue_thenShouldNotGiveConstraintViolations() { - Invoice invoice = new Invoice(new BigDecimal(10), "Book purchased"); + public void whenThreeIntegerDigits_thenShouldNotGiveConstraintViolations() { + Invoice invoice = new Invoice(new BigDecimal("102.21"), "Book purchased"); Set> violations = validator.validate(invoice); - assertThat(violations.size()).isEqualTo(0); + assertThat(violations).isEmpty(); } @Test - public void whenPriceIntegerDigitGreaterThanThree_thenShouldGiveConstraintViolations() { - Invoice invoice = new Invoice(new BigDecimal(1021.21), "Book purchased"); + public void whenMoreThanThreeIntegerDigits_thenShouldGiveConstraintViolations() { + Invoice invoice = new Invoice(new BigDecimal("1021.21"), "Book purchased"); Set> violations = validator.validate(invoice); - assertThat(violations.size()).isEqualTo(1); - violations.forEach(action -> assertThat(action.getMessage()).isEqualTo("numeric value out of bounds (<3 digits>.<2 digits> expected)")); + assertThat(violations).hasSize(1); + assertThat(violations) + .extracting("message") + .containsOnly("numeric value out of bounds (<3 digits>.<2 digits> expected)"); + } + + @Test + public void whenLessThanTwoFractionDigits_thenShouldNotGiveConstraintViolations() { + Invoice invoice = new Invoice(new BigDecimal("99.9"), "Book purchased"); + Set> violations = validator.validate(invoice); + assertThat(violations).isEmpty(); + } + + @Test + public void whenTwoFractionDigits_thenShouldNotGiveConstraintViolations() { + Invoice invoice = new Invoice(new BigDecimal("99.99"), "Book purchased"); + Set> violations = validator.validate(invoice); + assertThat(violations).isEmpty(); + } + + @Test + public void whenMoreThanTwoFractionDigits_thenShouldGiveConstraintViolations() { + Invoice invoice = new Invoice(new BigDecimal("99.999"), "Book purchased"); + Set> violations = validator.validate(invoice); + assertThat(violations).hasSize(1); + assertThat(violations) + .extracting("message") + .containsOnly("numeric value out of bounds (<3 digits>.<2 digits> expected)"); } @Test public void whenPriceIsZero_thenShouldGiveConstraintViolations() { - Invoice invoice = new Invoice(new BigDecimal(000.00), "Book purchased"); + Invoice invoice = new Invoice(new BigDecimal("0.00"), "Book purchased"); Set> violations = validator.validate(invoice); - assertThat(violations.size()).isEqualTo(1); - violations.forEach(action -> assertThat(action.getMessage()).isEqualTo("must be greater than 0.0")); + assertThat(violations).hasSize(1); + assertThat(violations) + .extracting("message") + .containsOnly("must be greater than 0.0"); } @Test public void whenPriceIsGreaterThanZero_thenShouldNotGiveConstraintViolations() { - Invoice invoice = new Invoice(new BigDecimal(100.50), "Book purchased"); + Invoice invoice = new Invoice(new BigDecimal("100.50"), "Book purchased"); Set> violations = validator.validate(invoice); - assertThat(violations.size()).isEqualTo(0); + assertThat(violations).isEmpty(); } - } diff --git a/kubernetes/k8s-intro/README.md b/kubernetes/k8s-intro/README.md index 83cbcca4db..6ac593452c 100644 --- a/kubernetes/k8s-intro/README.md +++ b/kubernetes/k8s-intro/README.md @@ -16,3 +16,4 @@ If you get a valid response, then you're good to go. - [Paging and Async Calls with the Kubernetes API](https://www.baeldung.com/java-kubernetes-paging-async) - [Using Watch with the Kubernetes API](https://www.baeldung.com/java-kubernetes-watch) +- [Using Namespaces and Selectors With the Kubernetes Java API](https://www.baeldung.com/java-kubernetes-namespaces-selectors) diff --git a/kubernetes/k8s-intro/src/k8s/create-http-server.yml b/kubernetes/k8s-intro/src/k8s/create-http-server.yml new file mode 100644 index 0000000000..59ef344de3 --- /dev/null +++ b/kubernetes/k8s-intro/src/k8s/create-http-server.yml @@ -0,0 +1,58 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: ns1 +--- +apiVersion: v1 +kind: Namespace +metadata: + name: ns2 +--- + apiVersion: apps/v1 + kind: Deployment + metadata: + name: httpd + namespace: ns1 + labels: + app: httpd + version: "1" + spec: + replicas: 3 + selector: + matchLabels: + app: httpd + template: + metadata: + labels: + app: httpd + spec: + containers: + - name: main + image: httpd:alpine + ports: + - containerPort: 80 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: httpd + namespace: ns2 + labels: + app: httpd + version: "2" + foo: bar +spec: + replicas: 3 + selector: + matchLabels: + app: httpd + template: + metadata: + labels: + app: httpd + spec: + containers: + - name: main + image: httpd:alpine + ports: + - containerPort: 80 \ No newline at end of file diff --git a/kubernetes/k8s-intro/src/main/java/com/baeldung/kubernetes/intro/ListPodsWithFieldSelectors.java b/kubernetes/k8s-intro/src/main/java/com/baeldung/kubernetes/intro/ListPodsWithFieldSelectors.java new file mode 100644 index 0000000000..459f61099c --- /dev/null +++ b/kubernetes/k8s-intro/src/main/java/com/baeldung/kubernetes/intro/ListPodsWithFieldSelectors.java @@ -0,0 +1,68 @@ +/** + * + */ +package com.baeldung.kubernetes.intro; + + +import java.util.concurrent.TimeUnit; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.kubernetes.client.openapi.ApiClient; +import io.kubernetes.client.openapi.apis.CoreV1Api; +import io.kubernetes.client.openapi.models.V1NodeList; +import io.kubernetes.client.openapi.models.V1PodList; +import io.kubernetes.client.util.Config; +import okhttp3.OkHttpClient; +import okhttp3.logging.HttpLoggingInterceptor; + +/** + * @author Philippe + * + */ +public class ListPodsWithFieldSelectors { + + private static final Logger log = LoggerFactory.getLogger(ListPodsWithFieldSelectors.class); + + /** + * @param args + */ + public static void main(String[] args) throws Exception { + + ApiClient client = Config.defaultClient(); + HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(message -> log.info(message)); + interceptor.setLevel(HttpLoggingInterceptor.Level.BODY); + OkHttpClient newClient = client.getHttpClient() + .newBuilder() + .addInterceptor(interceptor) + .readTimeout(0, TimeUnit.SECONDS) + .build(); + + client.setHttpClient(newClient); + CoreV1Api api = new CoreV1Api(client); + + String fs = createSelector(args); + V1PodList items = api.listPodForAllNamespaces(null, null, fs, null, null, null, null, null, 10, false); + items.getItems() + .stream() + .map((pod) -> pod.getMetadata().getName() ) + .forEach((name) -> System.out.println("name=" + name)); + + } + + private static String createSelector(String[] args) { + + StringBuilder b = new StringBuilder(); + for( int i = 0 ; i < args.length; i++ ) { + if( b.length() > 0 ) { + b.append(','); + } + + b.append(args[i]); + } + + return b.toString(); + } + +} diff --git a/kubernetes/k8s-intro/src/main/java/com/baeldung/kubernetes/intro/ListPodsWithLabelSelectors.java b/kubernetes/k8s-intro/src/main/java/com/baeldung/kubernetes/intro/ListPodsWithLabelSelectors.java new file mode 100644 index 0000000000..2e7c8b6a1f --- /dev/null +++ b/kubernetes/k8s-intro/src/main/java/com/baeldung/kubernetes/intro/ListPodsWithLabelSelectors.java @@ -0,0 +1,68 @@ +/** + * + */ +package com.baeldung.kubernetes.intro; + + +import java.util.concurrent.TimeUnit; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.kubernetes.client.openapi.ApiClient; +import io.kubernetes.client.openapi.apis.CoreV1Api; +import io.kubernetes.client.openapi.models.V1NodeList; +import io.kubernetes.client.openapi.models.V1PodList; +import io.kubernetes.client.util.Config; +import okhttp3.OkHttpClient; +import okhttp3.logging.HttpLoggingInterceptor; + +/** + * @author Philippe + * + */ +public class ListPodsWithLabelSelectors { + + private static final Logger log = LoggerFactory.getLogger(ListPodsWithLabelSelectors.class); + + /** + * @param args + */ + public static void main(String[] args) throws Exception { + + ApiClient client = Config.defaultClient(); + HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(message -> log.info(message)); + interceptor.setLevel(HttpLoggingInterceptor.Level.BODY); + OkHttpClient newClient = client.getHttpClient() + .newBuilder() + .addInterceptor(interceptor) + .readTimeout(0, TimeUnit.SECONDS) + .build(); + + client.setHttpClient(newClient); + CoreV1Api api = new CoreV1Api(client); + + String selector = createSelector(args); + V1PodList items = api.listPodForAllNamespaces(null, null, null, selector, null, null, null, null, 10, false); + items.getItems() + .stream() + .map((pod) -> pod.getMetadata().getName() ) + .forEach((name) -> System.out.println("name=" + name)); + + } + + private static String createSelector(String[] args) { + + StringBuilder b = new StringBuilder(); + for( int i = 0 ; i < args.length; i++ ) { + if( b.length() > 0 ) { + b.append(','); + } + + b.append(args[i]); + } + + return b.toString(); + } + +} diff --git a/kubernetes/k8s-intro/src/main/java/com/baeldung/kubernetes/intro/ListPodsWithNamespaces.java b/kubernetes/k8s-intro/src/main/java/com/baeldung/kubernetes/intro/ListPodsWithNamespaces.java new file mode 100644 index 0000000000..68a951f394 --- /dev/null +++ b/kubernetes/k8s-intro/src/main/java/com/baeldung/kubernetes/intro/ListPodsWithNamespaces.java @@ -0,0 +1,52 @@ +/** + * + */ +package com.baeldung.kubernetes.intro; + + +import java.util.concurrent.TimeUnit; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.kubernetes.client.openapi.ApiClient; +import io.kubernetes.client.openapi.apis.CoreV1Api; +import io.kubernetes.client.openapi.models.V1NodeList; +import io.kubernetes.client.openapi.models.V1PodList; +import io.kubernetes.client.util.Config; +import okhttp3.OkHttpClient; +import okhttp3.logging.HttpLoggingInterceptor; + +/** + * @author Philippe + * + */ +public class ListPodsWithNamespaces { + + private static final Logger log = LoggerFactory.getLogger(ListPodsWithNamespaces.class); + + /** + * @param args + */ + public static void main(String[] args) throws Exception { + + ApiClient client = Config.defaultClient(); + HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(message -> log.info(message)); + interceptor.setLevel(HttpLoggingInterceptor.Level.BODY); + OkHttpClient newClient = client.getHttpClient() + .newBuilder() + .addInterceptor(interceptor) + .readTimeout(0, TimeUnit.SECONDS) + .build(); + + client.setHttpClient(newClient); + CoreV1Api api = new CoreV1Api(client); + String namespace = "ns1"; + V1PodList items = api.listNamespacedPod(namespace,null, null, null, null, null, null, null, null, 10, false); + items.getItems() + .stream() + .map((pod) -> pod.getMetadata().getName() ) + .forEach((name) -> System.out.println("name=" + name)); + + } +} diff --git a/kubernetes/k8s-intro/src/test/java/com/baeldung/kubernetes/intro/ListPodsWithFieldSelectorsLiveTest.java b/kubernetes/k8s-intro/src/test/java/com/baeldung/kubernetes/intro/ListPodsWithFieldSelectorsLiveTest.java new file mode 100644 index 0000000000..9413fe1460 --- /dev/null +++ b/kubernetes/k8s-intro/src/test/java/com/baeldung/kubernetes/intro/ListPodsWithFieldSelectorsLiveTest.java @@ -0,0 +1,27 @@ +package com.baeldung.kubernetes.intro; + +import org.junit.jupiter.api.Test; + +class ListPodsWithFieldSelectorsLiveTest { + @Test + void givenEqualitySelector_whenListPodsWithFieldSelectors_thenSuccess() throws Exception { + ListPodsWithFieldSelectors.main(new String[] { + "metadata.namespace=ns1" + }); + } + + @Test + void givenInequalitySelector_whenListPodsWithFieldSelectors_thenSuccess() throws Exception { + ListPodsWithFieldSelectors.main(new String[] { + "metadata.namespace!=ns1" + }); + } + + @Test + void givenChainedSelector_whenListPodsWithFieldSelectors_thenSuccess() throws Exception { + ListPodsWithFieldSelectors.main(new String[] { + "metadata.namespace=ns1", + "status.phase=Running" + }); + } +} diff --git a/kubernetes/k8s-intro/src/test/java/com/baeldung/kubernetes/intro/ListPodsWithLabelSelectorsLiveTest.java b/kubernetes/k8s-intro/src/test/java/com/baeldung/kubernetes/intro/ListPodsWithLabelSelectorsLiveTest.java new file mode 100644 index 0000000000..eb64853225 --- /dev/null +++ b/kubernetes/k8s-intro/src/test/java/com/baeldung/kubernetes/intro/ListPodsWithLabelSelectorsLiveTest.java @@ -0,0 +1,55 @@ +package com.baeldung.kubernetes.intro; + +import org.junit.jupiter.api.Test; + +class ListPodsWithLabelSelectorsLiveTest { + @Test + void givenEqualitySelector_whenListPodsWithLabelSelectors_thenSuccess() throws Exception { + ListPodsWithLabelSelectors.main(new String[] { + "app=httpd" + }); + } + + @Test + void givenInqualitySelector_whenListPodsWithLabelSelectors_thenSuccess() throws Exception { + ListPodsWithLabelSelectors.main(new String[] { + "app!=httpd" + }); + } + + @Test + void givenInSetSelector_whenListPodsWithLabelSelectors_thenSuccess() throws Exception { + ListPodsWithLabelSelectors.main(new String[] { + "app in (httpd,test)" + }); + } + + @Test + void givenNotInSetSelector_whenListPodsWithLabelSelectors_thenSuccess() throws Exception { + ListPodsWithLabelSelectors.main(new String[] { + "app notin (httpd)" + }); + } + + @Test + void givenLabelPresentSelector_whenListPodsWithLabelSelectors_thenSuccess() throws Exception { + ListPodsWithLabelSelectors.main(new String[] { + "app" + }); + } + + @Test + void givenLabelNotPresentSelector_whenListPodsWithLabelSelectors_thenSuccess() throws Exception { + ListPodsWithLabelSelectors.main(new String[] { + "!app" + }); + } + + @Test + void givenChainedSelector_whenListPodsWithLabelSelectors_thenSuccess() throws Exception { + ListPodsWithLabelSelectors.main(new String[] { + "app=httpd", + "!foo" + }); + } +} diff --git a/libraries-http-2/README.md b/libraries-http-2/README.md index f3fdf1becb..4085d98ea5 100644 --- a/libraries-http-2/README.md +++ b/libraries-http-2/README.md @@ -8,5 +8,6 @@ This module contains articles about HTTP libraries. - [Decode an OkHttp JSON Response](https://www.baeldung.com/okhttp-json-response) - [Retrofit 2 – Dynamic URL](https://www.baeldung.com/retrofit-dynamic-url) - [Adding Interceptors in OkHTTP](https://www.baeldung.com/java-okhttp-interceptors) +- [A Guide to Events in OkHTTP](https://www.baeldung.com/java-okhttp-events) - More articles [[<-- prev]](/libraries-http) diff --git a/libraries-http-2/src/main/java/com/baeldung/okhttp/events/EventTimer.java b/libraries-http-2/src/main/java/com/baeldung/okhttp/events/EventTimer.java new file mode 100644 index 0000000000..356dea9fc6 --- /dev/null +++ b/libraries-http-2/src/main/java/com/baeldung/okhttp/events/EventTimer.java @@ -0,0 +1,156 @@ +package com.baeldung.okhttp.events; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.util.List; + +import okhttp3.Call; +import okhttp3.Connection; +import okhttp3.EventListener; +import okhttp3.Handshake; +import okhttp3.HttpUrl; +import okhttp3.Protocol; +import okhttp3.Request; +import okhttp3.Response; + +public class EventTimer extends EventListener { + + private long start; + + private void logTimedEvent(String name) { + long now = System.nanoTime(); + if (name.equals("callStart")) { + start = now; + } + long elapsedNanos = now - start; + System.out.printf("%.3f %s%n", elapsedNanos / 1000000000d, name); + } + + @Override + public void callStart(Call call) { + logTimedEvent("callStart"); + } + + @Override + public void proxySelectStart(Call call, HttpUrl url) { + logTimedEvent("proxySelectStart"); + } + + @Override + public void proxySelectEnd(Call call, HttpUrl url, List proxies) { + logTimedEvent("proxySelectEnd"); + } + + @Override + public void dnsStart(Call call, String domainName) { + logTimedEvent("dnsStart"); + } + + @Override + public void dnsEnd(Call call, String domainName, List inetAddressList) { + logTimedEvent("dnsEnd"); + } + + @Override + public void connectStart(Call call, InetSocketAddress inetSocketAddress, Proxy proxy) { + logTimedEvent("connectStart"); + } + + @Override + public void secureConnectStart(Call call) { + logTimedEvent("secureConnectStart"); + } + + @Override + public void secureConnectEnd(Call call, Handshake handshake) { + logTimedEvent("secureConnectEnd"); + } + + @Override + public void connectEnd(Call call, InetSocketAddress inetSocketAddress, Proxy proxy, Protocol protocol) { + logTimedEvent("connectEnd"); + } + + @Override + public void connectFailed(Call call, InetSocketAddress inetSocketAddress, Proxy proxy, Protocol protocol, IOException ioe) { + logTimedEvent("connectFailed"); + } + + @Override + public void connectionAcquired(Call call, Connection connection) { + logTimedEvent("connectionAcquired"); + } + + @Override + public void connectionReleased(Call call, Connection connection) { + logTimedEvent("connectionReleased"); + } + + @Override + public void requestHeadersStart(Call call) { + logTimedEvent("requestHeadersStart"); + } + + @Override + public void requestHeadersEnd(Call call, Request request) { + logTimedEvent("requestHeadersEnd"); + } + + @Override + public void requestBodyStart(Call call) { + logTimedEvent("requestBodyStart"); + } + + @Override + public void requestBodyEnd(Call call, long byteCount) { + logTimedEvent("requestBodyEnd"); + } + + @Override + public void requestFailed(Call call, IOException ioe) { + logTimedEvent("requestFailed"); + } + + @Override + public void responseHeadersStart(Call call) { + logTimedEvent("responseHeadersStart"); + } + + @Override + public void responseHeadersEnd(Call call, Response response) { + logTimedEvent("responseHeadersEnd"); + } + + @Override + public void responseBodyStart(Call call) { + logTimedEvent("responseBodyStart"); + } + + @Override + public void responseBodyEnd(Call call, long byteCount) { + logTimedEvent("responseBodyEnd"); + } + + @Override + public void responseFailed(Call call, IOException ioe) { + logTimedEvent("responseFailed"); + } + + @Override + public void callEnd(Call call) { + logTimedEvent("callEnd"); + } + + @Override + public void callFailed(Call call, IOException ioe) { + logTimedEvent("callFailed"); + } + + @Override + public void canceled(Call call) { + logTimedEvent("canceled"); + } + +} diff --git a/libraries-http-2/src/main/java/com/baeldung/okhttp/events/SimpleLogEventsListener.java b/libraries-http-2/src/main/java/com/baeldung/okhttp/events/SimpleLogEventsListener.java new file mode 100644 index 0000000000..93e3eb6308 --- /dev/null +++ b/libraries-http-2/src/main/java/com/baeldung/okhttp/events/SimpleLogEventsListener.java @@ -0,0 +1,37 @@ +package com.baeldung.okhttp.events; + +import java.time.LocalDateTime; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import okhttp3.Call; +import okhttp3.EventListener; +import okhttp3.Request; +import okhttp3.Response; + +public class SimpleLogEventsListener extends EventListener { + + private static final Logger LOGGER = LoggerFactory.getLogger(SimpleLogEventsListener.class); + + @Override + public void callStart(Call call) { + LOGGER.info("callStart at {}", LocalDateTime.now()); + } + + @Override + public void requestHeadersEnd(Call call, Request request) { + LOGGER.info("requestHeadersEnd at {} with headers {}", LocalDateTime.now(), request.headers()); + } + + @Override + public void responseHeadersEnd(Call call, Response response) { + LOGGER.info("responseHeadersEnd at {} with headers {}", LocalDateTime.now(), response.headers()); + } + + @Override + public void callEnd(Call call) { + LOGGER.info("callEnd at {}", LocalDateTime.now()); + } + +} diff --git a/libraries-http-2/src/test/java/com/baeldung/okhttp/events/EventTimerLiveTest.java b/libraries-http-2/src/test/java/com/baeldung/okhttp/events/EventTimerLiveTest.java new file mode 100644 index 0000000000..ebf4cd1404 --- /dev/null +++ b/libraries-http-2/src/test/java/com/baeldung/okhttp/events/EventTimerLiveTest.java @@ -0,0 +1,31 @@ +package com.baeldung.okhttp.events; + +import static org.junit.Assert.*; + +import java.io.IOException; + +import org.junit.Test; + +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; + +public class EventTimerLiveTest { + + @Test + public void givenSimpleEventTimer_whenRequestSent_thenCallsLogged() throws IOException { + + OkHttpClient client = new OkHttpClient.Builder() + .eventListener(new EventTimer()) + .build(); + + Request request = new Request.Builder() + .url("https://www.baeldung.com/") + .build(); + + try (Response response = client.newCall(request).execute()) { + assertEquals("Response code should be: ", 200, response.code()); + } + } + +} diff --git a/libraries-http-2/src/test/java/com/baeldung/okhttp/events/LogEventsListenerIntegrationTest.java b/libraries-http-2/src/test/java/com/baeldung/okhttp/events/LogEventsListenerIntegrationTest.java new file mode 100644 index 0000000000..c5884e8a12 --- /dev/null +++ b/libraries-http-2/src/test/java/com/baeldung/okhttp/events/LogEventsListenerIntegrationTest.java @@ -0,0 +1,53 @@ +package com.baeldung.okhttp.events; + +import static org.junit.Assert.assertEquals; + +import java.io.IOException; +import java.net.SocketTimeoutException; + +import org.junit.Rule; +import org.junit.Test; + +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; + +public class LogEventsListenerIntegrationTest { + + @Rule + public MockWebServer server = new MockWebServer(); + + @Test + public void givenSimpleEventLogger_whenRequestSent_thenCallsLogged() throws IOException { + server.enqueue(new MockResponse().setBody("Hello Baeldung Readers!")); + + OkHttpClient client = new OkHttpClient.Builder() + .eventListener(new SimpleLogEventsListener()) + .build(); + + Request request = new Request.Builder() + .url(server.url("/")) + .build(); + + try (Response response = client.newCall(request).execute()) { + assertEquals("Response code should be: ", 200, response.code()); + assertEquals("Body should be: ", "Hello Baeldung Readers!", response.body().string()); + } + } + + @Test (expected = SocketTimeoutException.class) + public void givenConnectionError_whenRequestSent_thenFailedCallsLogged() throws IOException { + OkHttpClient client = new OkHttpClient.Builder() + .eventListener(new EventTimer()) + .build(); + + Request request = new Request.Builder() + .url(server.url("/")) + .build(); + + client.newCall(request).execute(); + } + +} diff --git a/maven-modules/maven-copy-files/copy-rename-maven-plugin/pom.xml b/maven-modules/maven-copy-files/copy-rename-maven-plugin/pom.xml new file mode 100644 index 0000000000..24a7c48499 --- /dev/null +++ b/maven-modules/maven-copy-files/copy-rename-maven-plugin/pom.xml @@ -0,0 +1,92 @@ + + + 4.0.0 + + maven-copy-files + com.baeldung + 1.0-SNAPSHOT + + org.baeldung + copy-rename-maven-plugin + 1.0-SNAPSHOT + copy-rename-maven-plugin + + UTF-8 + 1.7 + 1.7 + + + + junit + junit + 4.11 + test + + + + + + com.coderplus.maven.plugins + copy-rename-maven-plugin + 1.0 + + + copy-file + generate-sources + + copy + + + source-files/foo.txt + target/destination-folder/foo.txt + + + + + + + + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-jar-plugin + 3.0.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + maven-site-plugin + 3.7.1 + + + maven-project-info-reports-plugin + 3.0.0 + + + + + diff --git a/maven-modules/maven-copy-files/copy-rename-maven-plugin/source-files/foo.txt b/maven-modules/maven-copy-files/copy-rename-maven-plugin/source-files/foo.txt new file mode 100644 index 0000000000..b2fa85b97f --- /dev/null +++ b/maven-modules/maven-copy-files/copy-rename-maven-plugin/source-files/foo.txt @@ -0,0 +1 @@ +Copy File Example diff --git a/maven-modules/maven-copy-files/copy-rename-maven-plugin/src/test/java/org/baeldung/CopyFileUnitTest.java b/maven-modules/maven-copy-files/copy-rename-maven-plugin/src/test/java/org/baeldung/CopyFileUnitTest.java new file mode 100644 index 0000000000..a98db61fa9 --- /dev/null +++ b/maven-modules/maven-copy-files/copy-rename-maven-plugin/src/test/java/org/baeldung/CopyFileUnitTest.java @@ -0,0 +1,16 @@ +package org.baeldung; + +import org.junit.Test; + +import java.io.File; + +import static org.junit.Assert.assertEquals; + +public class CopyFileUnitTest { + + @Test + public void whenCopyingAFileFromSourceToDestination_thenFileShouldBeInDestination() { + File destinationFile = new File("target/destination-folder/foo.txt"); + assertEquals(true, destinationFile.exists()); + } +} diff --git a/maven-modules/maven-copy-files/maven-antrun-plugin/pom.xml b/maven-modules/maven-copy-files/maven-antrun-plugin/pom.xml new file mode 100644 index 0000000000..61017dd18a --- /dev/null +++ b/maven-modules/maven-copy-files/maven-antrun-plugin/pom.xml @@ -0,0 +1,94 @@ + + + 4.0.0 + + maven-copy-files + com.baeldung + 1.0-SNAPSHOT + + org.baeldung + maven-antrun-plugin + 1.0-SNAPSHOT + maven-antrun-plugin + + UTF-8 + 1.7 + 1.7 + + + + junit + junit + 4.11 + test + + + + + + maven-antrun-plugin + 3.0.0 + + + generate-sources + + + + + + + + + + run + + + + + + + + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-jar-plugin + 3.0.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + maven-site-plugin + 3.7.1 + + + maven-project-info-reports-plugin + 3.0.0 + + + + + diff --git a/maven-modules/maven-copy-files/maven-antrun-plugin/source-files/foo.txt b/maven-modules/maven-copy-files/maven-antrun-plugin/source-files/foo.txt new file mode 100644 index 0000000000..b2fa85b97f --- /dev/null +++ b/maven-modules/maven-copy-files/maven-antrun-plugin/source-files/foo.txt @@ -0,0 +1 @@ +Copy File Example diff --git a/maven-modules/maven-copy-files/maven-antrun-plugin/src/test/java/org/baeldung/CopyFileUnitTest.java b/maven-modules/maven-copy-files/maven-antrun-plugin/src/test/java/org/baeldung/CopyFileUnitTest.java new file mode 100644 index 0000000000..a98db61fa9 --- /dev/null +++ b/maven-modules/maven-copy-files/maven-antrun-plugin/src/test/java/org/baeldung/CopyFileUnitTest.java @@ -0,0 +1,16 @@ +package org.baeldung; + +import org.junit.Test; + +import java.io.File; + +import static org.junit.Assert.assertEquals; + +public class CopyFileUnitTest { + + @Test + public void whenCopyingAFileFromSourceToDestination_thenFileShouldBeInDestination() { + File destinationFile = new File("target/destination-folder/foo.txt"); + assertEquals(true, destinationFile.exists()); + } +} diff --git a/maven-modules/maven-copy-files/maven-resources-plugin/pom.xml b/maven-modules/maven-copy-files/maven-resources-plugin/pom.xml new file mode 100644 index 0000000000..7dbe851f95 --- /dev/null +++ b/maven-modules/maven-copy-files/maven-resources-plugin/pom.xml @@ -0,0 +1,92 @@ + + + 4.0.0 + + maven-copy-files + com.baeldung + 1.0-SNAPSHOT + + org.baeldung + maven-resources-plugin + 1.0-SNAPSHOT + maven-resoures-plugin + + UTF-8 + 1.7 + 1.7 + + + + junit + junit + 4.11 + test + + + + + + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + copy-resource-one + generate-sources + + copy-resources + + + ${basedir}/target/destination-folder + + + source-files + + foo.txt + + + + + + + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-jar-plugin + 3.0.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + maven-site-plugin + 3.7.1 + + + maven-project-info-reports-plugin + 3.0.0 + + + + + diff --git a/maven-modules/maven-copy-files/maven-resources-plugin/source-files/foo.txt b/maven-modules/maven-copy-files/maven-resources-plugin/source-files/foo.txt new file mode 100644 index 0000000000..b2fa85b97f --- /dev/null +++ b/maven-modules/maven-copy-files/maven-resources-plugin/source-files/foo.txt @@ -0,0 +1 @@ +Copy File Example diff --git a/maven-modules/maven-copy-files/maven-resources-plugin/src/test/java/org/baeldung/CopyFileUnitTest.java b/maven-modules/maven-copy-files/maven-resources-plugin/src/test/java/org/baeldung/CopyFileUnitTest.java new file mode 100644 index 0000000000..a98db61fa9 --- /dev/null +++ b/maven-modules/maven-copy-files/maven-resources-plugin/src/test/java/org/baeldung/CopyFileUnitTest.java @@ -0,0 +1,16 @@ +package org.baeldung; + +import org.junit.Test; + +import java.io.File; + +import static org.junit.Assert.assertEquals; + +public class CopyFileUnitTest { + + @Test + public void whenCopyingAFileFromSourceToDestination_thenFileShouldBeInDestination() { + File destinationFile = new File("target/destination-folder/foo.txt"); + assertEquals(true, destinationFile.exists()); + } +} diff --git a/maven-modules/maven-copy-files/pom.xml b/maven-modules/maven-copy-files/pom.xml new file mode 100644 index 0000000000..b7b67286bc --- /dev/null +++ b/maven-modules/maven-copy-files/pom.xml @@ -0,0 +1,80 @@ + + + 4.0.0 + + maven-modules + com.baeldung + 0.0.1-SNAPSHOT + + com.baeldung + maven-copy-files + 1.0-SNAPSHOT + pom + maven-copy-files + + http://www.example.com + + UTF-8 + 1.7 + 1.7 + + + + junit + junit + 4.11 + test + + + + + + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-jar-plugin + 3.0.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + maven-site-plugin + 3.7.1 + + + maven-project-info-reports-plugin + 3.0.0 + + + + + + maven-resources-plugin + maven-antrun-plugin + copy-rename-maven-plugin + + diff --git a/maven-modules/maven-printing-plugins/.gitignore b/maven-modules/maven-printing-plugins/.gitignore new file mode 100644 index 0000000000..333c1e910a --- /dev/null +++ b/maven-modules/maven-printing-plugins/.gitignore @@ -0,0 +1 @@ +logs/ diff --git a/maven-modules/maven-printing-plugins/pom.xml b/maven-modules/maven-printing-plugins/pom.xml new file mode 100644 index 0000000000..6ea1ab2a84 --- /dev/null +++ b/maven-modules/maven-printing-plugins/pom.xml @@ -0,0 +1,85 @@ + + + 4.0.0 + maven-printing-plugins + maven-printing-plugins + + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + ../.. + + + + + + maven-antrun-plugin + 3.0.0 + + + antrun-plugin + validate + + run + + + + + + + + + + + + + + com.github.ekryd.echo-maven-plugin + echo-maven-plugin + 1.3.2 + + + echo-maven-plugin-1 + package + + echo + + + Hello, world + Embed a line break: ${line.separator} + ArtifactId is ${project.artifactId} + INFO + /logs/log-echo.txt + true + + + + + + org.codehaus.gmaven + groovy-maven-plugin + 2.1.1 + + + validate + + execute + + + + log.info('Test message: {}', 'Hello, World!') + log.info('Embed a line break {}', System.lineSeparator()) + log.info('ArtifactId is: ${project.artifactId}') + log.warn('Message only in debug mode') + + + + + + + + diff --git a/maven-modules/pom.xml b/maven-modules/pom.xml index 08a8f05631..0f146e26da 100644 --- a/maven-modules/pom.xml +++ b/maven-modules/pom.xml @@ -16,6 +16,7 @@ + maven-copy-files maven-custom-plugin maven-exec-plugin maven-integration-test @@ -30,6 +31,7 @@ version-collision version-overriding-plugins versions-maven-plugin + maven-printing-plugins - \ No newline at end of file + diff --git a/netflix-modules/mantis/pom.xml b/netflix-modules/mantis/pom.xml index 474b8f6dbf..1f8b377b94 100644 --- a/netflix-modules/mantis/pom.xml +++ b/netflix-modules/mantis/pom.xml @@ -19,7 +19,6 @@ org.springframework.boot spring-boot-starter - 2.1.3.RELEASE io.mantisrx @@ -35,36 +34,31 @@ com.fasterxml.jackson.core jackson-databind - 2.10.2 net.andreinc.mockneat mockneat - 0.3.8 + 0.4.2 org.projectlombok lombok - 1.18.12 org.springframework spring-webflux - 5.0.9.RELEASE test io.projectreactor.netty reactor-netty - 0.9.12.RELEASE test - - SpringLibReleaseRepo - https://repo.spring.io/libs-release/ + jcenter + https://jcenter.bintray.com/ diff --git a/parent-boot-1/pom.xml b/parent-boot-1/pom.xml index 2e9c767aa2..96f4b1cbe3 100644 --- a/parent-boot-1/pom.xml +++ b/parent-boot-1/pom.xml @@ -1,6 +1,5 @@ - 4.0.0 diff --git a/parent-boot-2/pom.xml b/parent-boot-2/pom.xml index f5bf8784a9..c67842e313 100644 --- a/parent-boot-2/pom.xml +++ b/parent-boot-2/pom.xml @@ -1,6 +1,5 @@ - 4.0.0 diff --git a/parent-java/pom.xml b/parent-java/pom.xml index ce79b34f57..c1abe79b2e 100644 --- a/parent-java/pom.xml +++ b/parent-java/pom.xml @@ -1,8 +1,7 @@ - + 4.0.0 parent-java 0.0.1-SNAPSHOT diff --git a/parent-spring-4/pom.xml b/parent-spring-4/pom.xml index 931cad374b..e0e91cec9a 100644 --- a/parent-spring-4/pom.xml +++ b/parent-spring-4/pom.xml @@ -1,6 +1,5 @@ - 4.0.0 diff --git a/parent-spring-5/pom.xml b/parent-spring-5/pom.xml index 3219c504d5..b70ca2bd0f 100644 --- a/parent-spring-5/pom.xml +++ b/parent-spring-5/pom.xml @@ -1,6 +1,5 @@ - 4.0.0 diff --git a/patterns/design-patterns-behavioral/pom.xml b/patterns/design-patterns-behavioral/pom.xml index 93e07bb477..bc032a0f8f 100644 --- a/patterns/design-patterns-behavioral/pom.xml +++ b/patterns/design-patterns-behavioral/pom.xml @@ -26,6 +26,11 @@ ${lombok.version} provided + + com.google.code.findbugs + annotations + ${findbugs.annotations.version} + org.apache.commons commons-lang3 @@ -41,6 +46,7 @@ 16.0.2 + 3.0.1 3.9.1 diff --git a/patterns/design-patterns-behavioral/src/main/java/com/baeldung/nulls/FindBugsAnnotations.java b/patterns/design-patterns-behavioral/src/main/java/com/baeldung/nulls/FindBugsAnnotations.java index 697d5e4959..594516e3f2 100644 --- a/patterns/design-patterns-behavioral/src/main/java/com/baeldung/nulls/FindBugsAnnotations.java +++ b/patterns/design-patterns-behavioral/src/main/java/com/baeldung/nulls/FindBugsAnnotations.java @@ -1,12 +1,12 @@ package com.baeldung.nulls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import edu.umd.cs.findbugs.annotations.NonNull; +import edu.umd.cs.findbugs.annotations.Nullable; public class FindBugsAnnotations { - public void accept(@NotNull Object param) { + public void accept(@NonNull Object param) { System.out.println(param.toString()); } @@ -14,7 +14,7 @@ public class FindBugsAnnotations { System.out.println("Printing " + param); } - @NotNull + @NonNull public Object process() throws Exception { Object result = doSomething(); if (result == null) { diff --git a/persistence-modules/hibernate-mapping/README.md b/persistence-modules/hibernate-mapping/README.md index b5d0cb2f99..984f49bb70 100644 --- a/persistence-modules/hibernate-mapping/README.md +++ b/persistence-modules/hibernate-mapping/README.md @@ -13,3 +13,4 @@ This module contains articles about Object-relational Mapping (ORM) with Hiberna - [Hibernate – Mapping Date and Time](https://www.baeldung.com/hibernate-date-time) - [Mapping LOB Data in Hibernate](https://www.baeldung.com/hibernate-lob) - [FetchMode in Hibernate](https://www.baeldung.com/hibernate-fetchmode) +- [Mapping PostgreSQL Array With Hibernate](https://www.baeldung.com/java-hibernate-map-postgresql-array) diff --git a/persistence-modules/hibernate-mapping/pom.xml b/persistence-modules/hibernate-mapping/pom.xml index 1c0c3eb159..0248f0cb04 100644 --- a/persistence-modules/hibernate-mapping/pom.xml +++ b/persistence-modules/hibernate-mapping/pom.xml @@ -13,11 +13,22 @@ + + org.postgresql + postgresql + ${postgresql.version} + test + org.hibernate hibernate-core ${hibernate.version} + + com.vladmihalcea + hibernate-types-52 + ${hibernate-types.version} + org.assertj assertj-core @@ -64,7 +75,9 @@ + 42.2.20 5.4.12.Final + 2.10.4 3.8.0 6.0.16.Final 3.0.1-b11 diff --git a/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/CustomIntegerArrayType.java b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/CustomIntegerArrayType.java new file mode 100644 index 0000000000..233bb95dc1 --- /dev/null +++ b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/CustomIntegerArrayType.java @@ -0,0 +1,85 @@ +package com.baeldung.hibernate.arraymapping; + +import java.io.Serializable; +import java.sql.Array; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.util.Arrays; + +import org.hibernate.HibernateException; +import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.usertype.UserType; + +public class CustomIntegerArrayType implements UserType { + + @Override + public int[] sqlTypes() { + return new int[]{Types.ARRAY}; + } + + @Override + public Class returnedClass() { + return Integer[].class; + } + + @Override + public boolean equals(Object x, Object y) throws HibernateException { + if (x instanceof Integer[] && y instanceof Integer[]) { + return Arrays.deepEquals((Integer[])x, (Integer[])y); + } else { + return false; + } + } + + @Override + public int hashCode(Object x) throws HibernateException { + return Arrays.hashCode((Integer[])x); + } + + @Override + public Object nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner) + throws HibernateException, SQLException { + Array array = rs.getArray(names[0]); + return array != null ? array.getArray() : null; + } + + @Override + public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor session) + throws HibernateException, SQLException { + if (value != null && st != null) { + Array array = session.connection().createArrayOf("int", (Integer[])value); + st.setArray(index, array); + } else { + st.setNull(index, sqlTypes()[0]); + } + } + + @Override + public Object deepCopy(Object value) throws HibernateException { + Integer[] a = (Integer[])value; + return Arrays.copyOf(a, a.length); + } + + @Override + public boolean isMutable() { + return false; + } + + @Override + public Serializable disassemble(Object value) throws HibernateException { + return (Serializable) value; + } + + @Override + public Object assemble(Serializable cached, Object owner) throws HibernateException { + return cached; + } + + @Override + public Object replace(Object original, Object target, Object owner) throws HibernateException { + return original; + } + +} diff --git a/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/CustomStringArrayType.java b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/CustomStringArrayType.java new file mode 100644 index 0000000000..7bd284def7 --- /dev/null +++ b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/CustomStringArrayType.java @@ -0,0 +1,85 @@ +package com.baeldung.hibernate.arraymapping; + +import java.io.Serializable; +import java.sql.Array; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.util.Arrays; + +import org.hibernate.HibernateException; +import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.usertype.UserType; + +public class CustomStringArrayType implements UserType { + + @Override + public int[] sqlTypes() { + return new int[]{Types.ARRAY}; + } + + @Override + public Class returnedClass() { + return String[].class; + } + + @Override + public boolean equals(Object x, Object y) throws HibernateException { + if (x instanceof String[] && y instanceof String[]) { + return Arrays.deepEquals((String[])x, (String[])y); + } else { + return false; + } + } + + @Override + public int hashCode(Object x) throws HibernateException { + return Arrays.hashCode((String[])x); + } + + @Override + public Object nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner) + throws HibernateException, SQLException { + Array array = rs.getArray(names[0]); + return array != null ? array.getArray() : null; + } + + @Override + public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor session) + throws HibernateException, SQLException { + if (value != null && st != null) { + Array array = session.connection().createArrayOf("text", (String[])value); + st.setArray(index, array); + } else { + st.setNull(index, sqlTypes()[0]); + } + } + + @Override + public Object deepCopy(Object value) throws HibernateException { + String[] a = (String[])value; + return Arrays.copyOf(a, a.length); + } + + @Override + public boolean isMutable() { + return false; + } + + @Override + public Serializable disassemble(Object value) throws HibernateException { + return (Serializable) value; + } + + @Override + public Object assemble(Serializable cached, Object owner) throws HibernateException { + return cached; + } + + @Override + public Object replace(Object original, Object target, Object owner) throws HibernateException { + return original; + } + +} diff --git a/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/HibernateSessionUtil.java b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/HibernateSessionUtil.java new file mode 100644 index 0000000000..dc3ec93a9d --- /dev/null +++ b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/HibernateSessionUtil.java @@ -0,0 +1,61 @@ +package com.baeldung.hibernate.arraymapping; + +import java.io.FileInputStream; +import java.io.IOException; +import java.net.URL; +import java.util.Properties; + +import org.apache.commons.lang3.StringUtils; +import org.hibernate.SessionFactory; +import org.hibernate.boot.Metadata; +import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.service.ServiceRegistry; + +import com.baeldung.hibernate.arraymapping.User; + +public class HibernateSessionUtil { + + private static SessionFactory sessionFactory; + private static String PROPERTY_FILE_NAME; + + public static SessionFactory getSessionFactory() throws IOException { + return getSessionFactory(null); + } + + public static SessionFactory getSessionFactory(String propertyFileName) throws IOException { + PROPERTY_FILE_NAME = propertyFileName; + if (sessionFactory == null) { + ServiceRegistry serviceRegistry = configureServiceRegistry(); + sessionFactory = makeSessionFactory(serviceRegistry); + } + return sessionFactory; + } + + private static SessionFactory makeSessionFactory(ServiceRegistry serviceRegistry) { + MetadataSources metadataSources = new MetadataSources(serviceRegistry); + metadataSources.addAnnotatedClass(User.class); + + Metadata metadata = metadataSources.buildMetadata(); + return metadata.getSessionFactoryBuilder() + .build(); + + } + + private static ServiceRegistry configureServiceRegistry() throws IOException { + Properties properties = getProperties(); + return new StandardServiceRegistryBuilder().applySettings(properties) + .build(); + } + + private static Properties getProperties() throws IOException { + Properties properties = new Properties(); + URL propertiesURL = Thread.currentThread() + .getContextClassLoader() + .getResource(StringUtils.defaultString(PROPERTY_FILE_NAME, "hibernate_postgres.properties")); + try (FileInputStream inputStream = new FileInputStream(propertiesURL.getFile())) { + properties.load(inputStream); + } + return properties; + } +} diff --git a/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/User.java b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/User.java new file mode 100644 index 0000000000..018bedc349 --- /dev/null +++ b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/arraymapping/User.java @@ -0,0 +1,82 @@ +package com.baeldung.hibernate.arraymapping; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; + +import org.hibernate.annotations.Type; + +import com.vladmihalcea.hibernate.type.array.StringArrayType; + +import org.hibernate.annotations.*; + +@TypeDefs({ + @TypeDef( + name = "string-array", + typeClass = StringArrayType.class + ) +}) +@Entity +public class User { + + @Id + private Long id; + + private String name; + + @Column(columnDefinition = "text[]") + @Type(type = "com.baeldung.hibernate.arraymapping.CustomStringArrayType") + private String[] roles; + + @Column(columnDefinition = "int[]") + @Type(type = "com.baeldung.hibernate.arraymapping.CustomIntegerArrayType") + private Integer[] locations; + + @Type(type = "string-array") + @Column( + name = "phone_numbers", + columnDefinition = "text[]" + ) + private String[] phoneNumbers; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String[] getRoles() { + return roles; + } + + public void setRoles(String[] roles) { + this.roles = roles; + } + + public Integer[] getLocations() { + return locations; + } + + public void setLocations(Integer[] locations) { + this.locations = locations; + } + + public String[] getPhoneNumbers() { + return phoneNumbers; + } + + public void setPhoneNumbers(String[] phoneNumbers) { + this.phoneNumbers = phoneNumbers; + } + +} diff --git a/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/arraymapping/ArrayMappingIntegrationTest.java b/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/arraymapping/ArrayMappingIntegrationTest.java new file mode 100644 index 0000000000..ba0ccc2aa2 --- /dev/null +++ b/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/arraymapping/ArrayMappingIntegrationTest.java @@ -0,0 +1,133 @@ +package com.baeldung.hibernate.arraymapping; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.IOException; + +import org.hibernate.HibernateException; +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + + +public class ArrayMappingIntegrationTest { + + private Session session; + private Transaction transaction; + + @BeforeEach + public void setup() throws IOException { + try { + session = HibernateSessionUtil.getSessionFactory().openSession(); + transaction = session.beginTransaction(); + + bootstrapData(); + + } catch (HibernateException | IOException e) { + System.out.println("Can't connect to a PostgreSQL DB"); + } + } + + @AfterEach + public void cleanup() { + if (null != session) { + transaction.rollback(); + session.close(); + } + } + + @Test + public void givenArrayMapping_whenQueried_thenReturnArraysFromDB() throws HibernateException, IOException { + if (null != session) { + User user = session.find(User.class, 1L); + + assertEquals("john", user.getName()); + assertEquals("superuser", user.getRoles()[0]); + assertEquals("admin", user.getRoles()[1]); + assertEquals(100, user.getLocations()[0]); + assertEquals(389, user.getLocations()[1]); + assertEquals("7000000000", user.getPhoneNumbers()[0]); + assertEquals("8000000000", user.getPhoneNumbers()[1]); + } + } + + @Test + public void givenArrayMapping_whenArraysAreInserted_thenPersistInDB() throws HibernateException, IOException { + if (null != session) { + transaction = session.beginTransaction(); + + User user = new User(); + user.setId(2L); + user.setName("smith"); + + String[] roles = {"admin", "employee"}; + user.setRoles(roles); + + Integer[] locations = {190, 578}; + user.setLocations(locations); + + session.persist(user); + session.flush(); + session.clear(); + + transaction.commit(); + + User userDBObj = session.find(User.class, 2L); + + assertEquals("smith", userDBObj.getName()); + assertEquals("admin", userDBObj.getRoles()[0]); + assertEquals(578, userDBObj.getLocations()[1]); + } + } + + @Test + public void givenArrayMapping_whenArrayIsUpdated_thenPersistInDB() throws HibernateException, IOException { + if (null != session) { + transaction = session.beginTransaction(); + + User user = session.find(User.class, 1L); + + String[] updatedRoles = {"superuser", "superadmin"}; + String[] updatedPhoneNumbers = {"9000000000"}; + + user.setRoles(updatedRoles); + user.setPhoneNumbers(updatedPhoneNumbers); + + session.persist(user); + session.flush(); + session.clear(); + + User userDBObj = session.find(User.class, 1L); + + assertEquals("john", userDBObj.getName()); + assertEquals("superadmin", userDBObj.getRoles()[1]); + assertEquals("9000000000", userDBObj.getPhoneNumbers()[0]); + } + } + + public void bootstrapData() { + session.createQuery("delete from User").executeUpdate(); + + User user = new User(); + user.setId(1L); + user.setName("john"); + + String[] roles = {"superuser", "admin"}; + user.setRoles(roles); + + Integer[] locations = {100, 389}; + user.setLocations(locations); + + String[] phoneNumbers = {"7000000000", "8000000000"}; + user.setPhoneNumbers(phoneNumbers); + + session.persist(user); + session.flush(); + session.clear(); + + transaction.commit(); + } + +} diff --git a/persistence-modules/hibernate-mapping/src/test/resources/hibernate_postgres.properties b/persistence-modules/hibernate-mapping/src/test/resources/hibernate_postgres.properties new file mode 100644 index 0000000000..72e3dcd781 --- /dev/null +++ b/persistence-modules/hibernate-mapping/src/test/resources/hibernate_postgres.properties @@ -0,0 +1,14 @@ +hibernate.connection.driver_class=org.postgresql.Driver +hibernate.connection.url=jdbc:postgresql://localhost:5432/postgres +hibernate.connection.username=web +hibernate.connection.autocommit=true +jdbc.password= + +hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect +hibernate.show_sql=true +hibernate.hbm2ddl.auto=none + +hibernate.c3p0.min_size=5 +hibernate.c3p0.max_size=20 +hibernate.c3p0.acquire_increment=5 +hibernate.c3p0.timeout=1800 diff --git a/persistence-modules/java-jpa-3/pom.xml b/persistence-modules/java-jpa-3/pom.xml index 11673935b1..d81bfca5bd 100644 --- a/persistence-modules/java-jpa-3/pom.xml +++ b/persistence-modules/java-jpa-3/pom.xml @@ -68,6 +68,12 @@ ${assertj.version} test + + junit + junit + ${junit.version} + test + diff --git a/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/IdGeneration/User.java b/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/IdGeneration/User.java new file mode 100644 index 0000000000..88e742adce --- /dev/null +++ b/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/IdGeneration/User.java @@ -0,0 +1,41 @@ +package com.baeldung.jpa.IdGeneration; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; + +@Entity +public class User { + + @Id +// @GeneratedValue(strategy = GenerationType.SEQUENCE) + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + private String username; + private String password; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } +} diff --git a/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/IdGeneration/UserService.java b/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/IdGeneration/UserService.java new file mode 100644 index 0000000000..9c34ef9bb4 --- /dev/null +++ b/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/IdGeneration/UserService.java @@ -0,0 +1,19 @@ +package com.baeldung.jpa.IdGeneration; + +import javax.persistence.EntityManager; +import javax.transaction.Transactional; + +public class UserService { + + EntityManager entityManager; + + public UserService(EntityManager entityManager) { + this.entityManager = entityManager; + } + + @Transactional + public long saveUser(User user){ + entityManager.persist(user); + return user.getId(); + } +} diff --git a/persistence-modules/java-jpa-3/src/main/resources/META-INF/persistence.xml b/persistence-modules/java-jpa-3/src/main/resources/META-INF/persistence.xml index 19ecae8491..bc41f35c01 100644 --- a/persistence-modules/java-jpa-3/src/main/resources/META-INF/persistence.xml +++ b/persistence-modules/java-jpa-3/src/main/resources/META-INF/persistence.xml @@ -97,4 +97,20 @@ + + + org.hibernate.jpa.HibernatePersistenceProvider + com.baeldung.jpa.IdGeneration.User + true + + + + + + + + + + + diff --git a/persistence-modules/java-jpa-3/src/test/java/com/baeldung/jpa/IdGeneration/IdGenerationIntegrationTest.java b/persistence-modules/java-jpa-3/src/test/java/com/baeldung/jpa/IdGeneration/IdGenerationIntegrationTest.java new file mode 100644 index 0000000000..941ad52344 --- /dev/null +++ b/persistence-modules/java-jpa-3/src/test/java/com/baeldung/jpa/IdGeneration/IdGenerationIntegrationTest.java @@ -0,0 +1,47 @@ +package com.baeldung.jpa.IdGeneration; + +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.Persistence; +import java.util.UUID; + +public class IdGenerationIntegrationTest { + + private static EntityManager entityManager; + private static UserService service; + + @BeforeClass + public static void setup() { + EntityManagerFactory factory = Persistence.createEntityManagerFactory("jpa-h2-id-generation"); + entityManager = factory.createEntityManager(); + service = new UserService(entityManager); + } + + @Test + public void whenNewUserIsPersisted_thenEntityHasNoId() { + User user = new User(); + user.setUsername("test"); + user.setPassword(UUID.randomUUID().toString()); + + long index = service.saveUser(user); + Assert.assertEquals(0L, index); + } + + @Test + public void whenTransactionIsControlled_thenEntityHasId() { + User user = new User(); + user.setUsername("test"); + user.setPassword(UUID.randomUUID().toString()); + + entityManager.getTransaction().begin(); + long index = service.saveUser(user); + entityManager.getTransaction().commit(); + + Assert.assertEquals(2L, index); + } + +} diff --git a/persistence-modules/spring-data-jpa-annotations/src/main/java/com/baeldung/attribute/override/entity/Address.java b/persistence-modules/spring-data-jpa-annotations/src/main/java/com/baeldung/attribute/override/entity/Address.java new file mode 100644 index 0000000000..95a3708173 --- /dev/null +++ b/persistence-modules/spring-data-jpa-annotations/src/main/java/com/baeldung/attribute/override/entity/Address.java @@ -0,0 +1,25 @@ +package com.baeldung.attribute.override.entity; + +import javax.persistence.Embeddable; + +@Embeddable +public class Address { + private String name; + private String city; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } +} diff --git a/persistence-modules/spring-data-jpa-annotations/src/main/java/com/baeldung/attribute/override/entity/Brand.java b/persistence-modules/spring-data-jpa-annotations/src/main/java/com/baeldung/attribute/override/entity/Brand.java new file mode 100644 index 0000000000..9918cbaa70 --- /dev/null +++ b/persistence-modules/spring-data-jpa-annotations/src/main/java/com/baeldung/attribute/override/entity/Brand.java @@ -0,0 +1,29 @@ +package com.baeldung.attribute.override.entity; + +import javax.persistence.Embeddable; +import javax.persistence.Embedded; +import java.time.LocalDate; + +@Embeddable +public class Brand { + private String name; + private LocalDate foundationDate; + @Embedded + private Address address; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public LocalDate getFoundationDate() { + return foundationDate; + } + + public void setFoundationDate(LocalDate foundationDate) { + this.foundationDate = foundationDate; + } +} diff --git a/persistence-modules/spring-data-jpa-annotations/src/main/java/com/baeldung/attribute/override/entity/Car.java b/persistence-modules/spring-data-jpa-annotations/src/main/java/com/baeldung/attribute/override/entity/Car.java new file mode 100644 index 0000000000..5421090e58 --- /dev/null +++ b/persistence-modules/spring-data-jpa-annotations/src/main/java/com/baeldung/attribute/override/entity/Car.java @@ -0,0 +1,54 @@ +package com.baeldung.attribute.override.entity; + +import javax.persistence.AttributeOverride; +import javax.persistence.AttributeOverrides; +import javax.persistence.Column; +import javax.persistence.ElementCollection; +import javax.persistence.Embedded; +import javax.persistence.Entity; +import java.util.Map; + +@Entity +@AttributeOverride(name = "identifier", column = @Column(name = "VIN")) +public class Car extends Vehicle { + + private String model; + private String name; + @Embedded + @AttributeOverrides({ + @AttributeOverride(name = "name", column = @Column(name = "BRAND_NAME", length = 5)), + @AttributeOverride(name = "address.name", column = @Column(name = "ADDRESS_NAME")) + }) + private Brand brand; + @ElementCollection + @AttributeOverrides({ + @AttributeOverride(name = "key.name", column = @Column(name = "OWNER_NAME")), + @AttributeOverride(name = "key.surname", column = @Column(name = "OWNER_SURNAME")), + @AttributeOverride(name = "value.name", column = @Column(name = "ADDRESS_NAME")), + }) + Map owners; + + public String getModel() { + return model; + } + + public void setModel(String model) { + this.model = model; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Brand getBrand() { + return brand; + } + + public void setBrand(Brand brand) { + this.brand = brand; + } +} diff --git a/persistence-modules/spring-data-jpa-annotations/src/main/java/com/baeldung/attribute/override/entity/Owner.java b/persistence-modules/spring-data-jpa-annotations/src/main/java/com/baeldung/attribute/override/entity/Owner.java new file mode 100644 index 0000000000..28ef6c7974 --- /dev/null +++ b/persistence-modules/spring-data-jpa-annotations/src/main/java/com/baeldung/attribute/override/entity/Owner.java @@ -0,0 +1,25 @@ +package com.baeldung.attribute.override.entity; + +import javax.persistence.Embeddable; + +@Embeddable +public class Owner { + private String name; + private String surname; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getSurname() { + return surname; + } + + public void setSurname(String surname) { + this.surname = surname; + } +} diff --git a/persistence-modules/spring-data-jpa-annotations/src/main/java/com/baeldung/attribute/override/entity/Vehicle.java b/persistence-modules/spring-data-jpa-annotations/src/main/java/com/baeldung/attribute/override/entity/Vehicle.java new file mode 100644 index 0000000000..2d4c0c04b3 --- /dev/null +++ b/persistence-modules/spring-data-jpa-annotations/src/main/java/com/baeldung/attribute/override/entity/Vehicle.java @@ -0,0 +1,38 @@ +package com.baeldung.attribute.override.entity; + +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.MappedSuperclass; + +@MappedSuperclass +public class Vehicle { + @Id + @GeneratedValue + private Integer id; + private String identifier; + private Integer numberOfWheels; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getIdentifier() { + return identifier; + } + + public void setIdentifier(String identifier) { + this.identifier = identifier; + } + + public Integer getNumberOfWheels() { + return numberOfWheels; + } + + public void setNumberOfWheels(Integer numberOfWheels) { + this.numberOfWheels = numberOfWheels; + } +} diff --git a/persistence-modules/spring-data-jpa-annotations/src/main/java/com/baeldung/attribute/override/repository/CarRepository.java b/persistence-modules/spring-data-jpa-annotations/src/main/java/com/baeldung/attribute/override/repository/CarRepository.java new file mode 100644 index 0000000000..17cea77d89 --- /dev/null +++ b/persistence-modules/spring-data-jpa-annotations/src/main/java/com/baeldung/attribute/override/repository/CarRepository.java @@ -0,0 +1,7 @@ +package com.baeldung.attribute.override.repository; + +import com.baeldung.attribute.override.entity.Car; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface CarRepository extends JpaRepository { +} diff --git a/persistence-modules/spring-data-jpa-annotations/src/test/java/com/baeldung/attribute/override/AttributeOverrideIntegrationTest.java b/persistence-modules/spring-data-jpa-annotations/src/test/java/com/baeldung/attribute/override/AttributeOverrideIntegrationTest.java new file mode 100644 index 0000000000..4cc599c7de --- /dev/null +++ b/persistence-modules/spring-data-jpa-annotations/src/test/java/com/baeldung/attribute/override/AttributeOverrideIntegrationTest.java @@ -0,0 +1,56 @@ +package com.baeldung.attribute.override; + +import com.baeldung.Application; +import com.baeldung.attribute.override.entity.Address; +import com.baeldung.attribute.override.entity.Brand; +import com.baeldung.attribute.override.entity.Car; +import com.baeldung.attribute.override.repository.CarRepository; +import org.assertj.core.api.Assertions; +import org.jetbrains.annotations.NotNull; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDate; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = { Application.class }) +public class AttributeOverrideIntegrationTest { + + private static final LocalDate FORD_FOUNDATION_DATE = LocalDate.parse("1903-06-16"); + @Autowired + CarRepository carRepository; + + @Test + @Transactional + public void whenInsertingCar_thenEmbeddedAndMappedFieldsArePopulated() { + + Car fordMustang = createMustang(); + + carRepository.save(fordMustang); + Car actualCar = carRepository.getOne(fordMustang.getId()); + + Assertions.assertThat(actualCar).isEqualTo(fordMustang); + } + + @NotNull + private Car createMustang() { + Address address = new Address(); + address.setName("Ford United States"); + address.setCity("Dearborn"); + + Brand ford = new Brand(); + ford.setName("Ford"); + ford.setFoundationDate(FORD_FOUNDATION_DATE); + + Car fordMustang = new Car(); + fordMustang.setIdentifier("WP1AB29P88LA47599"); + fordMustang.setModel("Ford"); + fordMustang.setName("My car"); + fordMustang.setBrand(ford); + return fordMustang; + } +} diff --git a/persistence-modules/spring-data-jpa-crud/src/main/java/com/baeldung/softdelete/Product.java b/persistence-modules/spring-data-jpa-crud/src/main/java/com/baeldung/softdelete/Product.java new file mode 100644 index 0000000000..ef06f77c45 --- /dev/null +++ b/persistence-modules/spring-data-jpa-crud/src/main/java/com/baeldung/softdelete/Product.java @@ -0,0 +1,68 @@ +package com.baeldung.softdelete; + + +import java.io.Serializable; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +import org.hibernate.annotations.Filter; +import org.hibernate.annotations.FilterDef; +import org.hibernate.annotations.ParamDef; +import org.hibernate.annotations.SQLDelete; + +@Entity +@Table(name = "tbl_products") +@SQLDelete(sql = "UPDATE tbl_products SET deleted = true WHERE id=?") +@FilterDef(name = "deletedProductFilter", parameters = @ParamDef(name = "isDeleted", type = "boolean")) +@Filter(name = "deletedProductFilter", condition = "deleted = :isDeleted") +public class Product implements Serializable { + + private static final long serialVersionUID = 1L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String name; + + private double price; + + private boolean deleted = Boolean.FALSE; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public double getPrice() { + return price; + } + + public void setPrice(double price) { + this.price = price; + } + + public boolean isDeleted() { + return deleted; + } + + public void setDeleted(boolean deleted) { + this.deleted = deleted; + } + +} diff --git a/persistence-modules/spring-data-jpa-crud/src/main/java/com/baeldung/softdelete/ProductController.java b/persistence-modules/spring-data-jpa-crud/src/main/java/com/baeldung/softdelete/ProductController.java new file mode 100644 index 0000000000..ebfdfbb2e7 --- /dev/null +++ b/persistence-modules/spring-data-jpa-crud/src/main/java/com/baeldung/softdelete/ProductController.java @@ -0,0 +1,34 @@ +package com.baeldung.softdelete; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/api/products") +public class ProductController { + + @Autowired + private ProductService productService; + + @PostMapping + public Product createOne(@RequestBody Product product) { + return productService.create(product); + } + + @DeleteMapping("/{id}") + public void removeOne(@PathVariable("id") Long id) { + productService.remove(id); + } + + @GetMapping + public Iterable findAll(@RequestParam(value = "isDeleted", required = false, defaultValue = "false") boolean isDeleted) { + return productService.findAll(isDeleted); + } +} diff --git a/persistence-modules/spring-data-jpa-crud/src/main/java/com/baeldung/softdelete/ProductRepository.java b/persistence-modules/spring-data-jpa-crud/src/main/java/com/baeldung/softdelete/ProductRepository.java new file mode 100644 index 0000000000..a305a142aa --- /dev/null +++ b/persistence-modules/spring-data-jpa-crud/src/main/java/com/baeldung/softdelete/ProductRepository.java @@ -0,0 +1,7 @@ +package com.baeldung.softdelete; + +import org.springframework.data.repository.CrudRepository; + +public interface ProductRepository extends CrudRepository{ + +} diff --git a/persistence-modules/spring-data-jpa-crud/src/main/java/com/baeldung/softdelete/ProductService.java b/persistence-modules/spring-data-jpa-crud/src/main/java/com/baeldung/softdelete/ProductService.java new file mode 100644 index 0000000000..82d02fa87c --- /dev/null +++ b/persistence-modules/spring-data-jpa-crud/src/main/java/com/baeldung/softdelete/ProductService.java @@ -0,0 +1,35 @@ +package com.baeldung.softdelete; + +import javax.persistence.EntityManager; + +import org.hibernate.Filter; +import org.hibernate.Session; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class ProductService { + + @Autowired + private ProductRepository productRepository; + + @Autowired + private EntityManager entityManager; + + public Product create(Product product) { + return productRepository.save(product); + } + + public void remove(Long id){ + productRepository.deleteById(id); + } + + public Iterable findAll(boolean isDeleted){ + Session session = entityManager.unwrap(Session.class); + Filter filter = session.enableFilter("deletedProductFilter"); + filter.setParameter("isDeleted", isDeleted); + Iterable products = productRepository.findAll(); + session.disableFilter("deletedProductFilter"); + return products; + } +} \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa-crud/src/main/resources/application.properties b/persistence-modules/spring-data-jpa-crud/src/main/resources/application.properties index af0df308cd..18ef8d4e60 100644 --- a/persistence-modules/spring-data-jpa-crud/src/main/resources/application.properties +++ b/persistence-modules/spring-data-jpa-crud/src/main/resources/application.properties @@ -5,10 +5,5 @@ spring.jpa.properties.hibernate.order_inserts=true spring.jpa.properties.hibernate.order_updates=true spring.jpa.properties.hibernate.generate_statistics=true -# JPA-Schema-Generation -# Use below configuration to generate database schema create commands based on the entity models -# and export them into the create.sql file -#spring.jpa.properties.javax.persistence.schema-generation.scripts.action=create -#spring.jpa.properties.javax.persistence.schema-generation.scripts.create-target=create.sql -#spring.jpa.properties.javax.persistence.schema-generation.scripts.create-source=metadata -#spring.jpa.properties.hibernate.format_sql=true \ No newline at end of file +spring.jpa.database-platform=org.hibernate.dialect.H2Dialect + diff --git a/pom.xml b/pom.xml index ab3c73ff8a..d8bf527184 100644 --- a/pom.xml +++ b/pom.xml @@ -623,6 +623,7 @@ spring-boot-rest-2 spring-caching + spring-caching-2 spring-cloud spring-cloud-bus @@ -1079,6 +1080,7 @@ spring-boot-rest-2 spring-caching + spring-caching-2 spring-cloud spring-cloud-bus @@ -1274,6 +1276,7 @@ + spring-boot-modules/spring-boot-cassandre core-java-modules/core-java-9 core-java-modules/core-java-9-improvements core-java-modules/core-java-9-jigsaw diff --git a/reactor-core/README.md b/reactor-core/README.md index 0214aa26fd..08dac354ab 100644 --- a/reactor-core/README.md +++ b/reactor-core/README.md @@ -8,3 +8,4 @@ This module contains articles about Reactor Core. - [Combining Publishers in Project Reactor](https://www.baeldung.com/reactor-combine-streams) - [Programmatically Creating Sequences with Project Reactor](https://www.baeldung.com/flux-sequences-reactor) - [How to Extract a Mono’s Content in Java](https://www.baeldung.com/java-string-from-mono) +- [How to Convert Mono> Into Flux](https://www.baeldung.com/java-mono-list-to-flux) diff --git a/reactor-core/src/test/java/com/baeldung/mono/MonoUnitTest.java b/reactor-core/src/test/java/com/baeldung/mono/MonoUnitTest.java index f9e67b0a2f..0c6e0c07ef 100644 --- a/reactor-core/src/test/java/com/baeldung/mono/MonoUnitTest.java +++ b/reactor-core/src/test/java/com/baeldung/mono/MonoUnitTest.java @@ -1,10 +1,14 @@ package com.baeldung.mono; import org.junit.Test; +import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; import java.time.Duration; import java.time.temporal.ChronoUnit; +import java.util.ArrayList; +import java.util.List; import java.util.Optional; import static org.junit.Assert.assertEquals; @@ -40,4 +44,40 @@ public class MonoUnitTest { // blocking return Mono.just("Hello world!"); } + + @Test + public void whenMonoProducesListOfElements_thenConvertToFluxofElements() { + + Mono> monoList = monoOfList(); + + StepVerifier.create(monoTofluxUsingFlatMapIterable(monoList)) + .expectNext("one", "two", "three", "four") + .verifyComplete(); + + StepVerifier.create(monoTofluxUsingFlatMapMany(monoList)) + .expectNext("one", "two", "three", "four") + .verifyComplete(); + } + + private Flux monoTofluxUsingFlatMapIterable(Mono> monoList) { + return monoList + .flatMapIterable(list -> list) + .log(); + } + + private Flux monoTofluxUsingFlatMapMany(Mono> monoList) { + return monoList + .flatMapMany(Flux::fromIterable) + .log(); + } + + private Mono> monoOfList() { + List list = new ArrayList<>(); + list.add("one"); + list.add("two"); + list.add("three"); + list.add("four"); + + return Mono.just(list); + } } diff --git a/spring-boot-modules/spring-boot-cassandre/README.md b/spring-boot-modules/spring-boot-cassandre/README.md new file mode 100644 index 0000000000..14ffbb7d6b --- /dev/null +++ b/spring-boot-modules/spring-boot-cassandre/README.md @@ -0,0 +1,11 @@ +# Cassandre trading bot example + +This project is an example of a trading bot developed with Cassandre + +## Running the examples + +* `mvn test` - Run strategy backtesting +* `mvn spring-boot:run` - Run the bot + +## Relevant Articles +- [Build a Trading Bot with Cassandre Spring Boot Starter](https://www.baeldung.com/build-a-trading-bot-with-cassandre-spring-boot-starter/) diff --git a/spring-boot-modules/spring-boot-cassandre/pom.xml b/spring-boot-modules/spring-boot-cassandre/pom.xml new file mode 100644 index 0000000000..75163d2c2b --- /dev/null +++ b/spring-boot-modules/spring-boot-cassandre/pom.xml @@ -0,0 +1,68 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.4.5 + + + com.example + demo + 0.0.1-SNAPSHOT + Cassandre trading bot tutorial + Cassandre trading bot tutorial + + 11 + + + + org.springframework.boot + spring-boot-starter + + + + + tech.cassandre.trading.bot + cassandre-trading-bot-spring-boot-starter + 4.2.1 + + + org.knowm.xchange + xchange-kucoin + 5.0.7 + + + org.hsqldb + hsqldb + 2.5.1 + + + + org.springframework.boot + spring-boot-starter-test + test + + + + tech.cassandre.trading.bot + cassandre-trading-bot-spring-boot-starter-test + 4.2.1 + test + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + 2.4.5 + + + + + diff --git a/spring-boot-modules/spring-boot-cassandre/src/main/java/com/example/demo/DemoApplication.java b/spring-boot-modules/spring-boot-cassandre/src/main/java/com/example/demo/DemoApplication.java new file mode 100644 index 0000000000..094d95b93f --- /dev/null +++ b/spring-boot-modules/spring-boot-cassandre/src/main/java/com/example/demo/DemoApplication.java @@ -0,0 +1,13 @@ +package com.example.demo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class DemoApplication { + + public static void main(String[] args) { + SpringApplication.run(DemoApplication.class, args); + } + +} diff --git a/spring-boot-modules/spring-boot-cassandre/src/main/java/com/example/demo/MyFirstStrategy.java b/spring-boot-modules/spring-boot-cassandre/src/main/java/com/example/demo/MyFirstStrategy.java new file mode 100644 index 0000000000..ea8ae74aa6 --- /dev/null +++ b/spring-boot-modules/spring-boot-cassandre/src/main/java/com/example/demo/MyFirstStrategy.java @@ -0,0 +1,66 @@ +package com.example.demo; + +import static tech.cassandre.trading.bot.dto.position.PositionStatusDTO.CLOSED; +import static tech.cassandre.trading.bot.dto.position.PositionStatusDTO.OPENED; +import static tech.cassandre.trading.bot.dto.util.CurrencyDTO.BTC; +import static tech.cassandre.trading.bot.dto.util.CurrencyDTO.USDT; + +import java.math.BigDecimal; +import java.util.Optional; +import java.util.Set; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import tech.cassandre.trading.bot.dto.market.TickerDTO; +import tech.cassandre.trading.bot.dto.position.PositionDTO; +import tech.cassandre.trading.bot.dto.position.PositionRulesDTO; +import tech.cassandre.trading.bot.dto.user.AccountDTO; +import tech.cassandre.trading.bot.dto.util.CurrencyPairDTO; +import tech.cassandre.trading.bot.strategy.BasicCassandreStrategy; +import tech.cassandre.trading.bot.strategy.CassandreStrategy; + +@CassandreStrategy +public class MyFirstStrategy extends BasicCassandreStrategy { + + private final Logger logger = LoggerFactory.getLogger(MyFirstStrategy.class); + + @Override + public Set getRequestedCurrencyPairs() { + return Set.of(new CurrencyPairDTO(BTC, USDT)); + } + + @Override + public Optional getTradeAccount(Set accounts) { + return accounts.stream() + .filter(a -> "trade".equals(a.getName())) + .findFirst(); + } + + @Override + public void onTickerUpdate(TickerDTO ticker) { + logger.info("Received a new ticker : {}", ticker); + + if (new BigDecimal("56000").compareTo(ticker.getLast()) == -1) { + + if (canBuy(new CurrencyPairDTO(BTC, USDT), new BigDecimal("0.01"))) { + PositionRulesDTO rules = PositionRulesDTO.builder() + .stopGainPercentage(4f) + .stopLossPercentage(25f) + .build(); + createLongPosition(new CurrencyPairDTO(BTC, USDT), new BigDecimal("0.01"), rules); + } + + } + } + + @Override + public void onPositionStatusUpdate(PositionDTO position) { + if (position.getStatus() == OPENED) { + logger.info("> New position opened : {}", position.getPositionId()); + } + if (position.getStatus() == CLOSED) { + logger.info("> Position closed : {}", position.getDescription()); + } + } + +} diff --git a/spring-boot-modules/spring-boot-cassandre/src/main/resources/application.properties b/spring-boot-modules/spring-boot-cassandre/src/main/resources/application.properties new file mode 100644 index 0000000000..5ecdabd47a --- /dev/null +++ b/spring-boot-modules/spring-boot-cassandre/src/main/resources/application.properties @@ -0,0 +1,22 @@ +# +# Exchange configuration. +cassandre.trading.bot.exchange.name=kucoin +cassandre.trading.bot.exchange.username=kucoin.cassandre.test@gmail.com +cassandre.trading.bot.exchange.passphrase=cassandre +cassandre.trading.bot.exchange.key=6054ad25365ac6000689a998 +cassandre.trading.bot.exchange.secret=af080d55-afe3-47c9-8ec1-4b479fbcc5e7 +# +# Modes +cassandre.trading.bot.exchange.modes.sandbox=true +cassandre.trading.bot.exchange.modes.dry=false +# +# Exchange API calls rates (ms or standard ISO 8601 duration like 'PT5S'). +cassandre.trading.bot.exchange.rates.account=2000 +cassandre.trading.bot.exchange.rates.ticker=2000 +cassandre.trading.bot.exchange.rates.trade=2000 +# +# Database configuration. +cassandre.trading.bot.database.datasource.driver-class-name=org.hsqldb.jdbc.JDBCDriver +cassandre.trading.bot.database.datasource.url=jdbc:hsqldb:mem:cassandre +cassandre.trading.bot.database.datasource.username=sa +cassandre.trading.bot.database.datasource.password= diff --git a/spring-boot-modules/spring-boot-cassandre/src/test/java/com/example/demo/DemoApplicationTests.java b/spring-boot-modules/spring-boot-cassandre/src/test/java/com/example/demo/DemoApplicationTests.java new file mode 100644 index 0000000000..eaa99696e2 --- /dev/null +++ b/spring-boot-modules/spring-boot-cassandre/src/test/java/com/example/demo/DemoApplicationTests.java @@ -0,0 +1,13 @@ +package com.example.demo; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class DemoApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/spring-boot-modules/spring-boot-cassandre/src/test/java/com/example/demo/MyFirstStrategyUnitTest.java b/spring-boot-modules/spring-boot-cassandre/src/test/java/com/example/demo/MyFirstStrategyUnitTest.java new file mode 100644 index 0000000000..bf7c353821 --- /dev/null +++ b/spring-boot-modules/spring-boot-cassandre/src/test/java/com/example/demo/MyFirstStrategyUnitTest.java @@ -0,0 +1,55 @@ +package com.example.demo; + +import static org.awaitility.Awaitility.await; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static tech.cassandre.trading.bot.dto.position.PositionStatusDTO.OPENED; +import static tech.cassandre.trading.bot.dto.util.CurrencyDTO.USDT; + +import java.util.HashMap; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Import; + +import tech.cassandre.trading.bot.dto.util.CurrencyDTO; +import tech.cassandre.trading.bot.dto.util.GainDTO; +import tech.cassandre.trading.bot.test.mock.TickerFluxMock; + +@SpringBootTest +@Import(TickerFluxMock.class) +@DisplayName("Simple strategy test") +public class MyFirstStrategyUnitTest { + + private final Logger logger = LoggerFactory.getLogger(MyFirstStrategyUnitTest.class); + + @Autowired + private MyFirstStrategy strategy; + + @Autowired + private TickerFluxMock tickerFluxMock; + + @Test + @DisplayName("Check gains") + public void whenTickersArrives_thenCheckGains() { + await().forever().until(() -> tickerFluxMock.isFluxDone()); + + final HashMap gains = strategy.getGains(); + + logger.info("Cumulated gains:"); + gains.forEach((currency, gain) -> logger.info(currency + " : " + gain.getAmount())); + + logger.info("Position still opened :"); + strategy.getPositions() + .values() + .stream() + .filter(p -> p.getStatus().equals(OPENED)) + .forEach(p -> logger.info(" - {} " + p.getDescription())); + + assertTrue(gains.get(USDT).getPercentage() > 0); + } + +} diff --git a/spring-boot-modules/spring-boot-cassandre/src/test/resources/application.properties b/spring-boot-modules/spring-boot-cassandre/src/test/resources/application.properties new file mode 100644 index 0000000000..3d6feb09d7 --- /dev/null +++ b/spring-boot-modules/spring-boot-cassandre/src/test/resources/application.properties @@ -0,0 +1,22 @@ +# +# Exchange configuration. +cassandre.trading.bot.exchange.name=kucoin +cassandre.trading.bot.exchange.username=kucoin.cassandre.test@gmail.com +cassandre.trading.bot.exchange.passphrase=cassandre +cassandre.trading.bot.exchange.key=6054ad25365ac6000689a998 +cassandre.trading.bot.exchange.secret=af080d55-afe3-47c9-8ec1-4b479fbcc5e7 +# +# Modes +cassandre.trading.bot.exchange.modes.sandbox=true +cassandre.trading.bot.exchange.modes.dry=true +# +# Exchange API calls rates (ms or standard ISO 8601 duration like 'PT5S'). +cassandre.trading.bot.exchange.rates.account=2000 +cassandre.trading.bot.exchange.rates.ticker=2000 +cassandre.trading.bot.exchange.rates.trade=2000 +# +# Database configuration. +cassandre.trading.bot.database.datasource.driver-class-name=org.hsqldb.jdbc.JDBCDriver +cassandre.trading.bot.database.datasource.url=jdbc:hsqldb:mem:cassandre +cassandre.trading.bot.database.datasource.username=sa +cassandre.trading.bot.database.datasource.password= diff --git a/spring-boot-modules/spring-boot-cassandre/src/test/resources/tickers-btc-usdt.tsv b/spring-boot-modules/spring-boot-cassandre/src/test/resources/tickers-btc-usdt.tsv new file mode 100644 index 0000000000..b89bd96bdc --- /dev/null +++ b/spring-boot-modules/spring-boot-cassandre/src/test/resources/tickers-btc-usdt.tsv @@ -0,0 +1,89 @@ +1612569600 38294.4 39195.5 40964.2 38217.5 3882.29460938 153897343.463150723 +1612656000 39195.4 38807.6 39623.6 37341.4 2389.96820017 91972455.834535369 +1612742400 38807.6 46373.5 46767.9 38010 4971.54731481 212132648.426718929 +1612828800 46374.6 46434.8 48139.3 44961 4330.72854712 201891604.027160303 +1612915200 46430 44812.2 47300 43687.5 4351.84907778 198189685.592028516 +1613001600 44806.1 47941.5 48647.6 44005.8 4045.91883504 188171651.974437139 +1613088000 47963.1 47310.7 48958.8 46181.2 3356.01832119 159561721.419695848 +1613174400 47305.4 47152.6 48120.5 46225.5 2740.99221759 129227867.922246174 +1613260800 47152.5 48591.9 49686.9 47026.3 3359.4690565 163299915.839307312 +1613347200 48587.2 47904.4 49003.6 42841.6 3974.98461358 188990056.26923591 +1613433600 47913.1 49147.7 50619.3 47023.9 3599.85370182 176084748.845657596 +1613520000 49147.7 52118.1 52609.6 48931.1 3356.85082847 170893567.530348564 +1613606400 52114.3 51568.9 52522.9 50906.4 2183.18379408 113272339.172174965 +1613692800 51561.1 55890.5 56317.7 50727 3749.6920105 200656740.865959032 +1613779200 55893.6 55851.5 57622.6 53463.3 3394.87226216 190744601.429330887 +1613865600 55851.4 57423 58336.3 55489.6 2514.02340013 143658132.671448082 +1613952000 57420.6 54096.6 57517.8 44160 6125.32442907 330513978.457310237 +1614038400 54085.9 48908.3 54174.2 44900 8048.96505298 389277314.445372085 +1614124800 48902.9 49685.2 51361.9 47003.2 4816.75027676 239303706.844272809 +1614211200 49676.5 47082.7 52019.6 46624.4 3701.80236678 184044004.383578525 +1614297600 47082 46289.6 48408.8 44135 5329.77125908 247604118.914146591 +1614384000 46290.2 46114.4 48381.9 44836.5 2872.64640734 134946360.020429589 +1614470400 46111.3 45141.6 46626.1 43004.3 3940.17863714 175990962.484551548 +1614556800 45136.5 49590.3 49771.3 44958.9 3548.51026561 169389196.772247159 +1614643200 49590.3 48441.2 50201.6 47052.8 2936.94454126 142575425.463057812 +1614729600 48440.6 50345.5 52623.9 48100 3177.38943911 160801620.821885745 +1614816000 50347.6 48374.5 51762.1 47505.7 3624.17683614 178873453.27515484 +1614902400 48374.5 48758.9 49450 46189.8 3697.34556922 176318969.507294567 +1614988800 48746.9 48871.9 49255.1 47001 1949.15311354 94201823.810314647 +1615075200 48885 50930.4 51424.7 48885 2444.3584982 122962479.787996993 +1615161600 50956.6 52377 52387.5 49287.5 2710.99151191 137751640.241286989 +1615248000 52376.9 54867.6 54867.6 51833.8 3070.93581512 165487483.114064122 +1615334400 54867.5 55865.5 57364 52911.4 4049.50553851 224565244.752334892 +1615420800 55863.7 57781.1 58150 54238 3403.69441456 191915265.020541521 +1615507200 57781 57238.5 58057.5 55013.7 4031.0376629 228810606.091302364 +1615593600 57220.7 61180.9 61815.3 56059.3 4394.62318443 259602986.875738328 +1615680000 61174.3 59000 61700 59000 3084.33952274 186155667.656432156 +1615766400 59000 55607.1 60632.9 54525.6 5910.33518227 338468393.188725572 +1615852800 55607.1 56880.3 56918.9 53240.3 7410.49057723 409052587.523700888 +1615939200 56880.3 58875.8 58951.8 54147.5 5828.79026943 328135601.648660052 +1616025600 58882.9 57648.9 60107.7 57000 5073.7458698 297279816.540519693 +1616112000 57648.9 58024.2 59450.1 56071 3727.09434161 217005823.723994618 +1616198400 58024.3 58113.5 59874.6 57825.6 2746.52973805 161565114.165299707 +1616284800 58113.5 57350.2 58591.6 55501 3265.35649781 186845535.507151609 +1616371200 57345.3 54096.1 58415.5 53667 4219.99501831 237141977.003568352 +1616457600 54086.8 54348.4 55823.1 52986.3 4374.34046303 239135883.538398977 +1616544000 54348.4 52307.4 57200 51499.6 6416.76024581 351202326.218690674 +1616630400 52307.1 51301.7 53239.1 50455 7242.6466396 375950351.557038048 +1616716800 51301.7 55032 55062.5 51225.3 4609.48192944 245299757.451540308 +1616803200 55031.9 55820.4 56628.6 53967.5 3634.73588532 200758048.816804103 +1616889600 55820.3 55772.9 56541 54666.6 3158.20452681 176119911.151714842 +1616976000 55772.8 57628.9 58400.5 54926.5 4413.63121553 251384747.301649587 +1617062400 57630.8 58754.6 59351.9 57072.8 3563.87315049 208118726.050535887 +1617148800 58753.2 58745.9 59800 56357.5 4921.45848213 288469053.074870873 +1617235200 58745.5 58735.7 59487.1 57879 3163.98213108 186078130.901422269 +1617321600 58735.7 58963.6 60179.1 58460.7 2553.76427314 151446539.609794648 +1617408000 58963.6 57058.3 59795 56721.2 2512.19109578 147434403.06515736 +1617494400 57052.5 58201.4 58481.2 56432.6 2069.14670128 119228330.17272614 +1617580800 58201.4 59116.2 59254.1 56501 3003.76043377 174821106.684799505 +1617667200 59116.2 57988.3 59497.5 57304.8 2964.86183859 173169186.845682699 +1617753600 57988.3 55958.2 58668.6 55439 5277.04906389 299996660.411940246 +1617840000 55958.2 58076.7 58141 55700.6 3175.60482079 181817013.517575328 +1617926400 58076.7 58131.6 58900 57666.9 3516.19104669 204849717.059779284 +1618012800 58138.2 59770.2 61350 57902.1 5533.50675561 332014577.538990658 +1618099200 59770.2 60007.6 60687.4 59247.6 3896.37426019 233158562.799039154 +1618185600 60007.6 59863.4 61270.7 59417.4 4611.409014 277430208.743380477 +1618272000 59863.4 63578.7 63759.7 59815 6906.310253 430518557.569547626 +1618358400 63578.7 62958.7 64840 61000 7696.509177 487298143.928065301 +1618444800 62954.4 63152.6 63772.1 62023.9 4709.82427144 296178401.81115496 +1618531200 63152.6 61342.6 63509.7 59930.8 8295.32523869 510423835.691643255 +1618617600 61342.7 59995.2 62497.8 59599.6 5367.42979289 328364887.709585395 +1618704000 59995.3 56150.6 60409.5 49001 11485.97101449 637797282.448645379 +1618790400 56152.7 55618.8 57583.4 54205.2 7721.306905 432634348.931871989 +1618876800 55618.7 56427.8 57061.6 53328 8677.75606016 480164200.559836543 +1618963200 56426.1 53793.6 56761.7 53602 6240.82191836 345339357.806167462 +1619049600 53793.5 51696.4 55474.7 50400 8879.16016304 475394174.249706678 +1619136000 51691.2 51102.7 52112.1 47502.1 8885.07060366 441295812.644904319 +1619222400 51109.8 50033 51157.9 48676.5 4833.41744745 241336360.887795675 +1619308800 50041.5 49086.9 50554.6 46966.2 4805.34664069 237153315.222670555 +1619395200 49069 54000.2 54336.4 48775.8 6695.12934907 353727728.269533971 +1619481600 53997.1 55014.3 55439 53240.8 4344.22291318 237020455.905144335 +1619568000 55014.2 54833.2 56399.1 53808.3 4801.04618634 262912695.604761319 +1619654400 54833.1 53558.4 55181.2 52340.1 4356.05177188 234153663.397444462 +1619740800 53558.5 57697.3 57936.4 53042.6 5000.47557303 277531927.921795199 +1619827200 57697.3 57794.7 58471.4 57006.3 3639.78966647 210179438.189007639 +1619913600 57794.7 56568.5 57903.7 56044.3 3508.52428767 199206958.05741809 +1620000000 56568.5 57159.7 58977.9 56451.3 4780.43387226 276554749.540429296 +1620086400 57159.7 53196.3 57188.2 53083.3 7079.55804728 390469293.396018923 +1620172800 53196.3 57834.5 57979.7 52888 4224.63060355 233779565.506303973 diff --git a/spring-boot-modules/spring-boot-cassandre/src/test/resources/user-trade.tsv b/spring-boot-modules/spring-boot-cassandre/src/test/resources/user-trade.tsv new file mode 100644 index 0000000000..d0fa4e9767 --- /dev/null +++ b/spring-boot-modules/spring-boot-cassandre/src/test/resources/user-trade.tsv @@ -0,0 +1,3 @@ +BTC 1 +USDT 100000 +ETH 10 \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-mvc-3/src/main/java/com/baeldung/filtersinterceptors/FilterInterceptorApp.java b/spring-boot-modules/spring-boot-mvc-3/src/main/java/com/baeldung/filtersinterceptors/FilterInterceptorApp.java new file mode 100644 index 0000000000..b1e6badd43 --- /dev/null +++ b/spring-boot-modules/spring-boot-mvc-3/src/main/java/com/baeldung/filtersinterceptors/FilterInterceptorApp.java @@ -0,0 +1,11 @@ +package com.baeldung.filtersinterceptors; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication(scanBasePackages = "com.baeldung.filtersinterceptors") +public class FilterInterceptorApp { + public static void main(String[] args) { + SpringApplication.run(FilterInterceptorApp.class, args); + } +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-mvc-3/src/main/java/com/baeldung/filtersinterceptors/HelloConroller.java b/spring-boot-modules/spring-boot-mvc-3/src/main/java/com/baeldung/filtersinterceptors/HelloConroller.java new file mode 100644 index 0000000000..db2da63d43 --- /dev/null +++ b/spring-boot-modules/spring-boot-mvc-3/src/main/java/com/baeldung/filtersinterceptors/HelloConroller.java @@ -0,0 +1,19 @@ +package com.baeldung.filtersinterceptors; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; + +@Controller +public class HelloConroller { + + private Logger logger = LoggerFactory.getLogger(HelloConroller.class); + + @GetMapping("/hello") + public String hello() { + logger.info("Hello from the controller"); + return "hello"; + } + +} diff --git a/spring-boot-modules/spring-boot-mvc-3/src/main/java/com/baeldung/filtersinterceptors/LogFilter.java b/spring-boot-modules/spring-boot-mvc-3/src/main/java/com/baeldung/filtersinterceptors/LogFilter.java new file mode 100644 index 0000000000..dc78cfbbb9 --- /dev/null +++ b/spring-boot-modules/spring-boot-mvc-3/src/main/java/com/baeldung/filtersinterceptors/LogFilter.java @@ -0,0 +1,26 @@ +package com.baeldung.filtersinterceptors; + +import java.io.IOException; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +@Component +public class LogFilter implements Filter { + + private Logger logger = LoggerFactory.getLogger(LogFilter.class); + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + logger.info("Hello from: " + request.getLocalAddr()); + chain.doFilter(request, response); + } + +} diff --git a/spring-boot-modules/spring-boot-mvc-3/src/main/java/com/baeldung/filtersinterceptors/LogInterceptor.java b/spring-boot-modules/spring-boot-mvc-3/src/main/java/com/baeldung/filtersinterceptors/LogInterceptor.java new file mode 100644 index 0000000000..b43b69415a --- /dev/null +++ b/spring-boot-modules/spring-boot-mvc-3/src/main/java/com/baeldung/filtersinterceptors/LogInterceptor.java @@ -0,0 +1,32 @@ +package com.baeldung.filtersinterceptors; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; +import org.springframework.web.servlet.HandlerInterceptor; +import org.springframework.web.servlet.ModelAndView; + +public class LogInterceptor implements HandlerInterceptor { + + private Logger logger = LoggerFactory.getLogger(LogInterceptor.class); + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + logger.info("preHandle"); + return true; + } + + @Override + public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { + logger.info("postHandle"); + } + + @Override + public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { + logger.info("afterCompletion"); + } + +} diff --git a/spring-boot-modules/spring-boot-mvc-3/src/main/java/com/baeldung/filtersinterceptors/WebMvcConfig.java b/spring-boot-modules/spring-boot-mvc-3/src/main/java/com/baeldung/filtersinterceptors/WebMvcConfig.java new file mode 100644 index 0000000000..9f4c1c2166 --- /dev/null +++ b/spring-boot-modules/spring-boot-mvc-3/src/main/java/com/baeldung/filtersinterceptors/WebMvcConfig.java @@ -0,0 +1,15 @@ +package com.baeldung.filtersinterceptors; + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +public class WebMvcConfig implements WebMvcConfigurer { + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(new LogInterceptor()); + } + +} diff --git a/spring-boot-modules/spring-boot-mvc-3/src/main/resources/templates/hello.html b/spring-boot-modules/spring-boot-mvc-3/src/main/resources/templates/hello.html new file mode 100644 index 0000000000..9a9b0e707b --- /dev/null +++ b/spring-boot-modules/spring-boot-mvc-3/src/main/resources/templates/hello.html @@ -0,0 +1,10 @@ + + + +Spring Filters vs Interceptors + + + +

Hello

+ + \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-properties-3/src/main/resources/application.yml b/spring-boot-modules/spring-boot-properties-3/src/main/resources/application.yml index 10570bb738..0f048ffa14 100644 --- a/spring-boot-modules/spring-boot-properties-3/src/main/resources/application.yml +++ b/spring-boot-modules/spring-boot-properties-3/src/main/resources/application.yml @@ -15,6 +15,7 @@ spring: username: SA bael: property: stagingValue + stagingProperty: stagingPropertyValue --- application: servers: diff --git a/spring-boot-modules/spring-boot-properties-3/src/test/java/com/baeldung/boot/properties/multidocument/StagingMultidocumentFilesIntegrationTest.java b/spring-boot-modules/spring-boot-properties-3/src/test/java/com/baeldung/boot/properties/multidocument/StagingMultidocumentFilesIntegrationTest.java index e02d1de272..851d5e0432 100644 --- a/spring-boot-modules/spring-boot-properties-3/src/test/java/com/baeldung/boot/properties/multidocument/StagingMultidocumentFilesIntegrationTest.java +++ b/spring-boot-modules/spring-boot-properties-3/src/test/java/com/baeldung/boot/properties/multidocument/StagingMultidocumentFilesIntegrationTest.java @@ -17,14 +17,18 @@ public class StagingMultidocumentFilesIntegrationTest { @Value("${bael.property}") private String baelCustomProperty; - + + @Value("${bael.stagingProperty}") + private String baelStagingProperty; + @Value("${bael.root-level-property}") private String baelRootProperty; @Test - @Disabled("Fix and update https://www.baeldung.com/spring-boot-yaml-vs-properties article") public void givenProductionProfileActive_whenApplicationStarts_thenDefaultPropertiesUser() { - assertThat(baelCustomProperty).isEqualTo("stagingValue"); + assertThat(baelStagingProperty).isEqualTo("stagingPropertyValue"); + // application.properties is loaded after the application.yml file and overrides the values + assertThat(baelCustomProperty).isEqualTo("defaultValue"); assertThat(baelRootProperty).isEqualTo("defaultRootLevelValue"); } } diff --git a/spring-boot-modules/spring-boot-testing/README.md b/spring-boot-modules/spring-boot-testing/README.md index 1b7ad661c6..058c78c9bb 100644 --- a/spring-boot-modules/spring-boot-testing/README.md +++ b/spring-boot-modules/spring-boot-testing/README.md @@ -15,3 +15,4 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring - [Testing Spring Boot @ConfigurationProperties](https://www.baeldung.com/spring-boot-testing-configurationproperties) - [Prevent ApplicationRunner or CommandLineRunner Beans From Executing During Junit Testing](https://www.baeldung.com/spring-junit-prevent-runner-beans-testing-execution) - [Testing in Spring Boot](https://www.baeldung.com/spring-boot-testing) +- [Fixing the NoSuchMethodError JUnit Error](https://www.baeldung.com/junit-nosuchmethoderror) diff --git a/spring-boot-rest-2/README.md b/spring-boot-rest-2/README.md index f09159198c..41270d58ea 100644 --- a/spring-boot-rest-2/README.md +++ b/spring-boot-rest-2/README.md @@ -1,3 +1,4 @@ ### Relevant Article: - [Get All Endpoints in Spring Boot](https://www.baeldung.com/spring-boot-get-all-endpoints) +- [HTTP PUT vs. POST in REST API](https://www.baeldung.com/rest-http-put-vs-post) diff --git a/spring-boot-rest-2/pom.xml b/spring-boot-rest-2/pom.xml index 32eff262dd..0560d6c9c7 100644 --- a/spring-boot-rest-2/pom.xml +++ b/spring-boot-rest-2/pom.xml @@ -30,6 +30,15 @@ springfox-boot-starter 3.0.0 + + org.springframework.boot + spring-boot-starter-data-jpa + + + com.h2database + h2 + runtime + diff --git a/spring-boot-rest-2/src/main/java/com/baeldung/putvspost/Address.java b/spring-boot-rest-2/src/main/java/com/baeldung/putvspost/Address.java new file mode 100644 index 0000000000..5c005c70f0 --- /dev/null +++ b/spring-boot-rest-2/src/main/java/com/baeldung/putvspost/Address.java @@ -0,0 +1,57 @@ +package com.baeldung.putvspost; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +@Entity +public class Address { + + private @Id @GeneratedValue Long id; + private String name; + private String city; + private String postalCode; + + Address() { + } + + public Address(String name, String city, String postalCode) { + this.name = name; + this.city = city; + this.postalCode = postalCode; + } + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public String getPostalCode() { + return postalCode; + } + + public void setPostalCode(String postalCode) { + this.postalCode = postalCode; + } + + @Override + public String toString() { + return "Address [id=" + id + ", name=" + name + ", city=" + city + ", postalCode=" + postalCode + "]"; + } + +} diff --git a/spring-boot-rest-2/src/main/java/com/baeldung/putvspost/AddressController.java b/spring-boot-rest-2/src/main/java/com/baeldung/putvspost/AddressController.java new file mode 100644 index 0000000000..f989d5c211 --- /dev/null +++ b/spring-boot-rest-2/src/main/java/com/baeldung/putvspost/AddressController.java @@ -0,0 +1,57 @@ +package com.baeldung.putvspost; + +import java.util.List; +import java.util.Optional; + +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class AddressController { + + private final AddressRepository repository; + + AddressController(AddressRepository repository) { + this.repository = repository; + } + + @GetMapping("/addresses") + List
getAllAddresses() { + return repository.findAll(); + } + + @GetMapping("/addresses/{id}") + Optional
getAddressesById(@PathVariable Long id) { + return repository.findById(id); + } + + @PostMapping("/addresses") + Address createNewAddress(@RequestBody Address newAddress) { + return repository.save(newAddress); + } + + @PutMapping("/addresses/{id}") + Address replaceEmployee(@RequestBody Address newAddress, @PathVariable Long id) { + + return repository.findById(id) + .map(address -> { + address.setCity(newAddress.getCity()); + address.setPostalCode(newAddress.getPostalCode()); + return repository.save(address); + }) + .orElseGet(() -> { + return repository.save(newAddress); + }); + } + + @DeleteMapping("/addresses/{id}") + void deleteEmployee(@PathVariable Long id) { + repository.deleteById(id); + } + +} diff --git a/spring-boot-rest-2/src/main/java/com/baeldung/putvspost/AddressRepository.java b/spring-boot-rest-2/src/main/java/com/baeldung/putvspost/AddressRepository.java new file mode 100644 index 0000000000..415a3c9030 --- /dev/null +++ b/spring-boot-rest-2/src/main/java/com/baeldung/putvspost/AddressRepository.java @@ -0,0 +1,7 @@ +package com.baeldung.putvspost; + +import org.springframework.data.jpa.repository.JpaRepository; + +public interface AddressRepository extends JpaRepository { + +} diff --git a/spring-boot-rest-2/src/main/java/com/baeldung/putvspost/PutVsPostApplication.java b/spring-boot-rest-2/src/main/java/com/baeldung/putvspost/PutVsPostApplication.java new file mode 100644 index 0000000000..8cea53d269 --- /dev/null +++ b/spring-boot-rest-2/src/main/java/com/baeldung/putvspost/PutVsPostApplication.java @@ -0,0 +1,13 @@ +package com.baeldung.putvspost; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class PutVsPostApplication { + + public static void main(String[] args) { + SpringApplication.run(PutVsPostApplication.class, args); + } + +} diff --git a/spring-caching-2/README.md b/spring-caching-2/README.md new file mode 100644 index 0000000000..1375b5e8e4 --- /dev/null +++ b/spring-caching-2/README.md @@ -0,0 +1,3 @@ +### Relevant articles: + +- [Spring Boot Cache with Redis](https://www.baeldung.com/spring-boot-redis-cache) diff --git a/spring-caching-2/pom.xml b/spring-caching-2/pom.xml new file mode 100644 index 0000000000..6bb828e8bf --- /dev/null +++ b/spring-caching-2/pom.xml @@ -0,0 +1,66 @@ + + + 4.0.0 + spring-caching-2 + 0.1-SNAPSHOT + spring-caching-2 + war + + + com.baeldung + parent-boot-2 + 0.0.1-SNAPSHOT + ../parent-boot-2 + + + + 0.7.3 + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.data + spring-data-commons + + + com.h2database + h2 + runtime + + + org.projectlombok + lombok + + + org.springframework.boot + spring-boot-starter-cache + + + org.springframework.boot + spring-boot-starter-data-redis + + + + it.ozimov + embedded-redis + ${embedded.redis.version} + + + org.slf4j + slf4j-simple + + + test + + + diff --git a/spring-caching-2/src/main/java/com/baeldung/caching/redis/CacheConfig.java b/spring-caching-2/src/main/java/com/baeldung/caching/redis/CacheConfig.java new file mode 100644 index 0000000000..89bdc2779d --- /dev/null +++ b/spring-caching-2/src/main/java/com/baeldung/caching/redis/CacheConfig.java @@ -0,0 +1,33 @@ +package com.baeldung.caching.redis; + +import org.springframework.boot.autoconfigure.cache.RedisCacheManagerBuilderCustomizer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.cache.RedisCacheConfiguration; +import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; + +import java.time.Duration; + +import static org.springframework.data.redis.serializer.RedisSerializationContext.SerializationPair; + +@Configuration +public class CacheConfig { + + @Bean + public RedisCacheManagerBuilderCustomizer redisCacheManagerBuilderCustomizer() { + return (builder) -> builder + .withCacheConfiguration("itemCache", + RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(10))) + .withCacheConfiguration("customerCache", + RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(5))); + } + + @Bean + public RedisCacheConfiguration cacheConfiguration() { + return RedisCacheConfiguration.defaultCacheConfig() + .entryTtl(Duration.ofMinutes(60)) + .disableCachingNullValues() + .serializeValuesWith(SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer())); + } + +} diff --git a/spring-caching-2/src/main/java/com/baeldung/caching/redis/Item.java b/spring-caching-2/src/main/java/com/baeldung/caching/redis/Item.java new file mode 100644 index 0000000000..d6115a4833 --- /dev/null +++ b/spring-caching-2/src/main/java/com/baeldung/caching/redis/Item.java @@ -0,0 +1,21 @@ +package com.baeldung.caching.redis; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.persistence.Entity; +import javax.persistence.Id; +import java.io.Serializable; + +@Data +@Entity +@AllArgsConstructor +@NoArgsConstructor +public class Item implements Serializable { + + @Id + String id; + + String description; +} diff --git a/spring-caching-2/src/main/java/com/baeldung/caching/redis/ItemController.java b/spring-caching-2/src/main/java/com/baeldung/caching/redis/ItemController.java new file mode 100644 index 0000000000..63122c5938 --- /dev/null +++ b/spring-caching-2/src/main/java/com/baeldung/caching/redis/ItemController.java @@ -0,0 +1,19 @@ +package com.baeldung.caching.redis; + +import lombok.AllArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@AllArgsConstructor +public class ItemController { + + private final ItemService itemService; + + @GetMapping("/item/{id}") + public Item getItemById(@PathVariable String id) { + return itemService.getItemForId(id); + } + +} diff --git a/spring-caching-2/src/main/java/com/baeldung/caching/redis/ItemRepository.java b/spring-caching-2/src/main/java/com/baeldung/caching/redis/ItemRepository.java new file mode 100644 index 0000000000..d6222de621 --- /dev/null +++ b/spring-caching-2/src/main/java/com/baeldung/caching/redis/ItemRepository.java @@ -0,0 +1,6 @@ +package com.baeldung.caching.redis; + +import org.springframework.data.repository.CrudRepository; + +public interface ItemRepository extends CrudRepository { +} diff --git a/spring-caching-2/src/main/java/com/baeldung/caching/redis/ItemService.java b/spring-caching-2/src/main/java/com/baeldung/caching/redis/ItemService.java new file mode 100644 index 0000000000..6a59c7d74e --- /dev/null +++ b/spring-caching-2/src/main/java/com/baeldung/caching/redis/ItemService.java @@ -0,0 +1,19 @@ +package com.baeldung.caching.redis; + +import lombok.AllArgsConstructor; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; + +@Service +@AllArgsConstructor +public class ItemService { + + private final ItemRepository itemRepository; + + @Cacheable(value = "itemCache") + public Item getItemForId(String id) { + return itemRepository.findById(id) + .orElseThrow(RuntimeException::new); + } + +} diff --git a/spring-caching-2/src/main/java/com/baeldung/caching/redis/RedisCacheApplication.java b/spring-caching-2/src/main/java/com/baeldung/caching/redis/RedisCacheApplication.java new file mode 100644 index 0000000000..3b337def01 --- /dev/null +++ b/spring-caching-2/src/main/java/com/baeldung/caching/redis/RedisCacheApplication.java @@ -0,0 +1,14 @@ +package com.baeldung.caching.redis; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cache.annotation.EnableCaching; + +@SpringBootApplication +@EnableCaching +public class RedisCacheApplication { + + public static void main(String[] args) { + SpringApplication.run(RedisCacheApplication.class, args); + } +} diff --git a/spring-caching-2/src/main/resources/application.properties b/spring-caching-2/src/main/resources/application.properties new file mode 100644 index 0000000000..080185b620 --- /dev/null +++ b/spring-caching-2/src/main/resources/application.properties @@ -0,0 +1,12 @@ +spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_ON_EXIT=FALSE +spring.datasource.driverClassName=org.h2.Driver +spring.datasource.username=sa +spring.datasource.password= + +# Enabling H2 Console +spring.h2.console.enabled=true +spring.h2.console.path=/h2 + +# Connection details +#spring.redis.host=localhost +#spring.redis.port=6379 diff --git a/spring-caching-2/src/main/resources/data.sql b/spring-caching-2/src/main/resources/data.sql new file mode 100644 index 0000000000..74e359b877 --- /dev/null +++ b/spring-caching-2/src/main/resources/data.sql @@ -0,0 +1 @@ +INSERT INTO ITEM VALUES('abc','ITEM1'); \ No newline at end of file diff --git a/spring-caching-2/src/test/java/com/baeldung/caching/redis/ItemServiceCachingIntegrationTest.java b/spring-caching-2/src/test/java/com/baeldung/caching/redis/ItemServiceCachingIntegrationTest.java new file mode 100644 index 0000000000..71a9729efd --- /dev/null +++ b/spring-caching-2/src/test/java/com/baeldung/caching/redis/ItemServiceCachingIntegrationTest.java @@ -0,0 +1,84 @@ +package com.baeldung.caching.redis; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; +import org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration; +import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.cache.CacheManager; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.annotation.Import; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import redis.embedded.RedisServer; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +@Import({ CacheConfig.class, ItemService.class }) +@ExtendWith(SpringExtension.class) +@ImportAutoConfiguration(classes = { CacheAutoConfiguration.class, RedisAutoConfiguration.class }) +@EnableCaching +class ItemServiceCachingIntegrationTest { + + private static final String AN_ID = "id-1"; + private static final String A_DESCRIPTION = "an item"; + + @MockBean + private ItemRepository mockItemRepository; + + @Autowired + private ItemService itemService; + + @Autowired + private CacheManager cacheManager; + + @Test + void givenRedisCaching_whenFindItemById_thenItemReturnedFromCache() { + Item anItem = new Item(AN_ID, A_DESCRIPTION); + given(mockItemRepository.findById(AN_ID)) + .willReturn(Optional.of(anItem)); + + Item itemCacheMiss = itemService.getItemForId(AN_ID); + Item itemCacheHit = itemService.getItemForId(AN_ID); + + assertThat(itemCacheMiss).isEqualTo(anItem); + assertThat(itemCacheHit).isEqualTo(anItem); + + verify(mockItemRepository, times(1)).findById(AN_ID); + assertThat(itemFromCache()).isEqualTo(anItem); + } + + private Object itemFromCache() { + return cacheManager.getCache("itemCache").get(AN_ID).get(); + } + + @TestConfiguration + static class EmbeddedRedisConfiguration { + + private final RedisServer redisServer; + + public EmbeddedRedisConfiguration() { + this.redisServer = new RedisServer(); + } + + @PostConstruct + public void startRedis() { + redisServer.start(); + } + + @PreDestroy + public void stopRedis() { + this.redisServer.stop(); + } + } + +} diff --git a/spring-caching-2/src/test/resources/logback-test.xml b/spring-caching-2/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..215403c6a5 --- /dev/null +++ b/spring-caching-2/src/test/resources/logback-test.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/spring-cloud/spring-cloud-circuit-breaker/pom.xml b/spring-cloud/spring-cloud-circuit-breaker/pom.xml index f30c764d9b..ebf89d671c 100644 --- a/spring-cloud/spring-cloud-circuit-breaker/pom.xml +++ b/spring-cloud/spring-cloud-circuit-breaker/pom.xml @@ -14,20 +14,6 @@ .. - - - spring-release - Spring Release - https://repo.spring.io/release - - false - - - true - - - - diff --git a/spring-mobile/pom.xml b/spring-mobile/pom.xml index 8b98e6d429..1593de27a8 100644 --- a/spring-mobile/pom.xml +++ b/spring-mobile/pom.xml @@ -32,19 +32,8 @@ - - - spring-milestones - Spring Milestones - https://repo.spring.io/libs-milestone - - false - - - - - 2.0.0.M3 + 1.1.5.RELEASE \ No newline at end of file diff --git a/spring-roo/pom.xml b/spring-roo/pom.xml index 2c5d5590fa..d1cf3e6412 100644 --- a/spring-roo/pom.xml +++ b/spring-roo/pom.xml @@ -391,18 +391,6 @@ - - - maven-snapshot-repository - Maven Snapshot Repository - https://oss.sonatype.org/content/repositories/snapshots - - false - - - true - - spring-roo-repository diff --git a/spring-web-modules/spring-resttemplate-3/src/test/java/com/baeldung/largefile/LargeFileDownloadIntegrationTest.java b/spring-web-modules/spring-resttemplate-3/src/test/java/com/baeldung/largefile/LargeFileDownloadIntegrationTest.java index d8fc58319f..687203d21a 100644 --- a/spring-web-modules/spring-resttemplate-3/src/test/java/com/baeldung/largefile/LargeFileDownloadIntegrationTest.java +++ b/spring-web-modules/spring-resttemplate-3/src/test/java/com/baeldung/largefile/LargeFileDownloadIntegrationTest.java @@ -14,7 +14,7 @@ import org.springframework.web.client.RestTemplate; public class LargeFileDownloadIntegrationTest { - static String FILE_URL = "http://ovh.net/files/1Mio.dat"; + static String FILE_URL = "https://s3.amazonaws.com/baeldung.com/Do+JSON+with+Jackson+by+Baeldung.pdf"; RestTemplate restTemplate; diff --git a/testing-modules/testing-libraries-2/pom.xml b/testing-modules/testing-libraries-2/pom.xml index e7016a2387..5a57dc0958 100644 --- a/testing-modules/testing-libraries-2/pom.xml +++ b/testing-modules/testing-libraries-2/pom.xml @@ -72,6 +72,36 @@ testing-libraries-2 + + + maven-war-plugin + 2.4 + + false + + + + + org.jacoco + jacoco-maven-plugin + ${jacoco.version} + + + jacoco-initialize + + prepare-agent + + + + jacoco-site + package + + report + + + + + src/test/resources @@ -81,11 +111,12 @@ + 0.8.6 1.19.0 1.0.0 1.1.0 5.6.2 3.16.1 - - \ No newline at end of file + + diff --git a/testing-modules/testing-libraries-2/src/main/java/com/baeldung/sonarqubeandjacoco/product/Product.java b/testing-modules/testing-libraries-2/src/main/java/com/baeldung/sonarqubeandjacoco/product/Product.java new file mode 100644 index 0000000000..42f103a317 --- /dev/null +++ b/testing-modules/testing-libraries-2/src/main/java/com/baeldung/sonarqubeandjacoco/product/Product.java @@ -0,0 +1,54 @@ +package com.baeldung.sonarqubeandjacoco.product; + +public class Product { + + private int id; + private String name; + private int units; + private double price; + + public Product() { + super(); + } + + public Product(int id, String name, int units, double price) { + super(); + this.id = id; + this.name = name; + this.units = units; + this.price = price; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getUnits() { + return units; + } + + public void setUnits(int units) { + this.units = units; + } + + public double getPrice() { + return price; + } + + public void setPrice(double price) { + this.price = price; + } + +} \ No newline at end of file diff --git a/testing-modules/testing-libraries-2/src/test/java/com/baeldung/sonarqubeandjacoco/product/ProductUnitTest.java b/testing-modules/testing-libraries-2/src/test/java/com/baeldung/sonarqubeandjacoco/product/ProductUnitTest.java new file mode 100644 index 0000000000..da649851e0 --- /dev/null +++ b/testing-modules/testing-libraries-2/src/test/java/com/baeldung/sonarqubeandjacoco/product/ProductUnitTest.java @@ -0,0 +1,26 @@ +package com.baeldung.sonarqubeandjacoco.product; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import org.junit.Test; + +import com.baeldung.sonarqubeandjacoco.product.Product; + +public class ProductUnitTest { + + @Test + public void test() { + Product product = new Product(); + product.setId(1); + assertNull(product.getName()); + assert (product.getId() == 1); + } + + @Test + public void testProduct() { + Product product = new Product(1, "product", 1, 2.0); + assertNotNull(product.getName()); + } + +}