Merge branch 'master' into JAVA-2399-Update_spring-security-rest_module_to_use_Swagger_3.0.0
This commit is contained in:
commit
42a0c6d966
|
@ -7,3 +7,4 @@ This module contains articles about Java 11 core features
|
|||
- [Guide to Java Reflection](http://www.baeldung.com/java-reflection)
|
||||
- [Guide to Java 8’s Collectors](https://www.baeldung.com/java-8-collectors)
|
||||
- [New Features in Java 11](https://www.baeldung.com/java-11-new-features)
|
||||
- [Getting the Java Version at Runtime](https://www.baeldung.com/get-java-version-runtime)
|
||||
|
|
|
@ -34,4 +34,4 @@
|
|||
<maven.compiler.target>1.9</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
</project>
|
|
@ -7,7 +7,7 @@
|
|||
<version>0.1.0-SNAPSHOT</version>
|
||||
<name>core-java-9-streams</name>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung.core-java-modules</groupId>
|
||||
<artifactId>core-java-modules</artifactId>
|
||||
|
@ -25,4 +25,4 @@
|
|||
</resources>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
</project>
|
|
@ -0,0 +1,8 @@
|
|||
package com.baeldung.exceptions.illegalaccesserror;
|
||||
|
||||
public class Class1 {
|
||||
|
||||
public void bar() {
|
||||
System.out.println("SUCCESS");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package com.baeldung.exceptions.illegalaccesserror;
|
||||
|
||||
public class Class2 {
|
||||
|
||||
public void foo() {
|
||||
Class1 c1 = new Class1();
|
||||
c1.bar();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package com.baeldung.exceptions.illegalaccesserror;
|
||||
|
||||
public class IllegalAccessErrorExample {
|
||||
|
||||
interface Baeldung {
|
||||
public default void foobar() {
|
||||
System.out.println("This is a default method.");
|
||||
}
|
||||
}
|
||||
|
||||
class Super {
|
||||
private void foobar() {
|
||||
System.out.println("SuperClass method foobar");
|
||||
}
|
||||
}
|
||||
|
||||
class MySubClass extends Super implements Baeldung {
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package com.baeldung.exceptions.illegalaccesserror;
|
||||
|
||||
public class IllegalAccessErrorSolved {
|
||||
|
||||
interface BaeldungSolved {
|
||||
public default void foobar() {
|
||||
System.out.println("This is a default method.");
|
||||
}
|
||||
}
|
||||
|
||||
class SuperSolved {
|
||||
public void foobar() {
|
||||
System.out.println("SuperClass method foobar");
|
||||
}
|
||||
}
|
||||
|
||||
class MySubClassSolved extends SuperSolved implements BaeldungSolved {
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package com.baeldung.exceptions.illegalaccesserror;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class IllegalAccessErrorExampleUnitTest {
|
||||
|
||||
@Test()
|
||||
public void givenInterfaceDefaultMethOverriddenPrivateAccess_whenInvoked_thenIllegalAccessError() {
|
||||
Assertions.assertThrows(IllegalAccessError.class, () -> {
|
||||
new IllegalAccessErrorExample().new MySubClass().foobar();
|
||||
});
|
||||
}
|
||||
|
||||
@Test()
|
||||
public void givenClass1Class2_whenSameClassDefintion_thenNoIllegalAccessError() {
|
||||
Assertions.assertDoesNotThrow(() -> {
|
||||
new Class2().foo();
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package com.baeldung.exceptions.illegalaccesserror;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class IllegalAccessErrorSolvedUnitTest {
|
||||
|
||||
@Test()
|
||||
public void givenInterfaceDefaultMethOverriddenNonPrivateAccess_whenInvoked_thenNoIllegalAccessError() {
|
||||
Assertions.assertDoesNotThrow(() -> {
|
||||
new IllegalAccessErrorSolved().new MySubClassSolved().foobar();
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package com.baeldung.deserialization.vulnerabilities;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class BadThing implements Serializable {
|
||||
private static final long serialVersionUID = 0L;
|
||||
|
||||
Object looselyDefinedThing;
|
||||
String methodName;
|
||||
|
||||
private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
|
||||
ois.defaultReadObject();
|
||||
try {
|
||||
Method method = looselyDefinedThing.getClass().getMethod(methodName);
|
||||
method.invoke(looselyDefinedThing);
|
||||
} catch (Exception e) {
|
||||
// handle error...
|
||||
}
|
||||
}
|
||||
|
||||
private void writeObject(ObjectOutputStream oos) throws IOException {
|
||||
oos.defaultWriteObject();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package com.baeldung.deserialization.vulnerabilities;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
|
||||
public class MyCustomAttackObject implements Serializable {
|
||||
public static void methodThatTriggersAttack() {
|
||||
try {
|
||||
Runtime.getRuntime().exec("echo \"Oh, no! I've been hacked\"");
|
||||
} catch (IOException e) {
|
||||
// handle error...
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package com.baeldung.deserialization.vulnerabilities;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
|
||||
public class BadThingUnitTest {
|
||||
|
||||
@Test
|
||||
@DisplayName("When a BadThing object is deserialized, then code execution in MyCustomAttackObject is run.")
|
||||
public void givenABadThingObject_whenItsDeserialized_thenExecutionIsRun() throws Exception {
|
||||
BadThing bt = new BadThing();
|
||||
|
||||
bt.looselyDefinedThing = new MyCustomAttackObject();
|
||||
bt.methodName = "methodThatTriggersAttack";
|
||||
|
||||
byte[] serializedObject = serialize(bt);
|
||||
|
||||
try (InputStream bis = new ByteArrayInputStream(serializedObject);
|
||||
ObjectInputStream ois = new ObjectInputStream(bis)) {
|
||||
|
||||
ois.readObject(); // malicious code is run
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] serialize(Object object) throws Exception {
|
||||
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
ObjectOutputStream oos = new ObjectOutputStream(bos)) {
|
||||
|
||||
oos.writeObject(object);
|
||||
oos.flush();
|
||||
return bos.toByteArray();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -45,4 +45,4 @@
|
|||
<providermodule.version>1.0</providermodule.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
</project>
|
||||
|
|
|
@ -5,3 +5,4 @@ This module contains articles about core features in the Java language
|
|||
- [The Java final Keyword – Impact on Performance](https://www.baeldung.com/java-final-performance)
|
||||
- [The package-info.java File](https://www.baeldung.com/java-package-info)
|
||||
- [What are Compile-time Constants in Java?](https://www.baeldung.com/java-compile-time-constants)
|
||||
- [Java Objects.hash() vs Objects.hashCode()](https://www.baeldung.com/java-objects-hash-vs-objects-hashcode)
|
||||
|
|
|
@ -7,3 +7,4 @@ This module contains articles about Object-oriented programming (OOP) patterns i
|
|||
- [Inheritance and Composition (Is-a vs Has-a relationship) in Java](https://www.baeldung.com/java-inheritance-composition)
|
||||
- [Immutable Objects in Java](https://www.baeldung.com/java-immutable-object)
|
||||
- [How to Make a Deep Copy of an Object in Java](https://www.baeldung.com/java-deep-copy)
|
||||
- [Using an Interface vs. Abstract Class in Java](https://www.baeldung.com/java-interface-vs-abstract-class)
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
package com.baeldung.ignore.pattern.metacharacters;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class IgnoringPatternMetacharactersUnitTest {
|
||||
private static final String dollarAmounts = "$100.25, $100.50, $150.50, $100.50, $100.75";
|
||||
private static final String patternStr = "$100.50";
|
||||
|
||||
@Test
|
||||
public void givenPatternStringHasMetacharacters_whenPatternMatchedWithoutEscapingMetacharacters_thenNoMatchesFound() {
|
||||
Pattern pattern = Pattern.compile(patternStr);
|
||||
Matcher matcher = pattern.matcher(dollarAmounts);
|
||||
|
||||
int matches = 0;
|
||||
while (matcher.find()) {
|
||||
matches++;
|
||||
}
|
||||
|
||||
assertEquals(0, matches);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenPatternStringHasMetacharacters_whenPatternCompiledUsingManuallyMetaEscapedPattern_thenMatchingSuccessful() {
|
||||
String metaEscapedPatternStr = "\\Q" + patternStr + "\\E";
|
||||
Pattern pattern = Pattern.compile(metaEscapedPatternStr);
|
||||
Matcher matcher = pattern.matcher(dollarAmounts);
|
||||
|
||||
int matches = 0;
|
||||
while (matcher.find()) {
|
||||
matches++;
|
||||
}
|
||||
|
||||
assertEquals(2, matches);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenPatternStringHasMetacharacters_whenPatternCompiledUsingLiteralPatternFromQuote_thenMatchingSuccessful() {
|
||||
String literalPatternStr = Pattern.quote(patternStr);
|
||||
Pattern pattern = Pattern.compile(literalPatternStr);
|
||||
Matcher matcher = pattern.matcher(dollarAmounts);
|
||||
|
||||
int matches = 0;
|
||||
while (matcher.find()) {
|
||||
matches++;
|
||||
}
|
||||
|
||||
assertEquals(2, matches);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package com.baeldung.secretkeyandstringconversion;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.security.spec.KeySpec;
|
||||
import java.util.Base64;
|
||||
|
||||
import javax.crypto.KeyGenerator;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.SecretKeyFactory;
|
||||
import javax.crypto.spec.PBEKeySpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
public class ConversionClassUtil {
|
||||
|
||||
/* Generating Secret key */
|
||||
|
||||
// Generating Secret Key using KeyGenerator class with 256
|
||||
public static SecretKey generateKey(int n) throws NoSuchAlgorithmException {
|
||||
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
|
||||
keyGenerator.init(n);
|
||||
SecretKey originalKey = keyGenerator.generateKey();
|
||||
return originalKey;
|
||||
}
|
||||
|
||||
// Generating Secret Key using password and salt
|
||||
public static SecretKey getKeyFromPassword(String password, String salt)
|
||||
throws NoSuchAlgorithmException, InvalidKeySpecException {
|
||||
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
|
||||
KeySpec spec = new PBEKeySpec(password.toCharArray(), salt.getBytes(), 65536, 256);
|
||||
SecretKey originalKey = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES");
|
||||
return originalKey;
|
||||
}
|
||||
|
||||
/* Converting Secret key into String */
|
||||
public static String convertSecretKeyToString(SecretKey secretKey) throws NoSuchAlgorithmException {
|
||||
// Converting the Secret Key into byte array
|
||||
byte[] rawData = secretKey.getEncoded();
|
||||
// Getting String - Base64 encoded version of the Secret Key
|
||||
String encodedKey = Base64.getEncoder().encodeToString(rawData);
|
||||
return encodedKey;
|
||||
}
|
||||
|
||||
/* Converting String into Secret key into */
|
||||
public static SecretKey convertStringToSecretKeyto(String encodedKey) {
|
||||
// Decoding the Base64 encoded string into byte array
|
||||
byte[] decodedKey = Base64.getDecoder().decode(encodedKey);
|
||||
// Rebuilding the Secret Key using SecretKeySpec Class
|
||||
SecretKey originalKey = new SecretKeySpec(decodedKey, 0, decodedKey.length, "AES");
|
||||
return originalKey;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package com.baeldung.secretkeyandstringconversion;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class ConversionClassUtilUnitTest {
|
||||
|
||||
@Test
|
||||
void givenPasswordAndSalt_whenCreateSecreKeyCheckConversion_thenSuccess()
|
||||
throws NoSuchAlgorithmException, InvalidKeySpecException {
|
||||
// given
|
||||
String password = "Baeldung@2021";
|
||||
String salt = "@$#baelDunG@#^$*";
|
||||
|
||||
// when
|
||||
SecretKey encodedKey = ConversionClassUtil.getKeyFromPassword(password, salt);
|
||||
String encodedString = ConversionClassUtil.convertSecretKeyToString(encodedKey);
|
||||
SecretKey decodeKey = ConversionClassUtil.convertStringToSecretKeyto(encodedString);
|
||||
|
||||
// then
|
||||
Assertions.assertEquals(encodedKey, decodeKey);
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenSize_whenCreateSecreKeyCheckConversion_thenSuccess()
|
||||
throws NoSuchAlgorithmException, InvalidKeySpecException {
|
||||
// given
|
||||
int size = 256;
|
||||
|
||||
// when
|
||||
SecretKey encodedKey = ConversionClassUtil.generateKey(size);
|
||||
String encodedString = ConversionClassUtil.convertSecretKeyToString(encodedKey);
|
||||
SecretKey decodeKey = ConversionClassUtil.convertStringToSecretKeyto(encodedString);
|
||||
|
||||
// then
|
||||
Assertions.assertEquals(encodedKey, decodeKey);
|
||||
}
|
||||
|
||||
}
|
|
@ -12,4 +12,5 @@ This module contains articles about the Stream API in Java.
|
|||
- [Should We Close a Java Stream?](https://www.baeldung.com/java-stream-close)
|
||||
- [Returning Stream vs. Collection](https://www.baeldung.com/java-return-stream-collection)
|
||||
- [Convert a Java Enumeration Into a Stream](https://www.baeldung.com/java-enumeration-to-stream)
|
||||
- [When to Use a Parallel Stream in Java](https://www.baeldung.com/java-when-to-use-parallel-stream)
|
||||
- More articles: [[<-- prev>]](/../core-java-streams-2)
|
||||
|
|
|
@ -27,6 +27,17 @@
|
|||
<version>${lombok.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjdk.jmh</groupId>
|
||||
<artifactId>jmh-core</artifactId>
|
||||
<version>${jmh.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjdk.jmh</groupId>
|
||||
<artifactId>jmh-generator-annprocess</artifactId>
|
||||
<version>${jmh.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- test scoped -->
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
|
@ -44,11 +55,30 @@
|
|||
<filtering>true</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
<annotationProcessorPaths>
|
||||
<path>
|
||||
<groupId>org.openjdk.jmh</groupId>
|
||||
<artifactId>jmh-generator-annprocess</artifactId>
|
||||
<version>${jmh.version}</version>
|
||||
</path>
|
||||
</annotationProcessorPaths>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<properties>
|
||||
<lombok.version>1.18.20</lombok.version>
|
||||
<!-- testing -->
|
||||
<assertj.version>3.6.1</assertj.version>
|
||||
<jmh.version>1.29</jmh.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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<Integer> arrayListOfNumbers = new ArrayList<>();
|
||||
private static final List<Integer> 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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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<Integer> 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());
|
||||
}
|
||||
|
||||
}
|
|
@ -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<Integer> listOfNumbers = Arrays.asList(1, 2, 3, 4);
|
||||
listOfNumbers.parallelStream().forEach(number ->
|
||||
System.out.println(number + " " + Thread.currentThread().getName())
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -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<Integer> listOfNumbers = Arrays.asList(1, 2, 3, 4);
|
||||
listOfNumbers.stream().forEach(number ->
|
||||
System.out.println(number + " " + Thread.currentThread().getName())
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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<Integer> 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<Integer> 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<Integer> 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<Integer> 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);
|
||||
}
|
||||
|
||||
}
|
|
@ -6,4 +6,5 @@ This module contains articles about string conversions from/to another type.
|
|||
- [Java String Conversions](https://www.baeldung.com/java-string-conversions)
|
||||
- [Convert String to Byte Array and Reverse in Java](https://www.baeldung.com/java-string-to-byte-array)
|
||||
- [Convert Character Array to String in Java](https://www.baeldung.com/java-char-array-to-string)
|
||||
- [Converting String to BigDecimal in Java](https://www.baeldung.com/java-string-to-bigdecimal)
|
||||
- More articles: [[<-- prev]](/core-java-string-conversions)
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
package com.baeldung.stringtobigdecimal;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.DecimalFormatSymbols;
|
||||
import java.text.ParseException;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class StringToBigDecimalConversionUnitTest {
|
||||
|
||||
@Test
|
||||
public void givenValidString_WhenBigDecimalObjectWithStringParameter_ThenResultIsDecimalObject() {
|
||||
BigDecimal bigDecimal = new BigDecimal("123");
|
||||
assertEquals(new BigDecimal(123), bigDecimal);
|
||||
}
|
||||
|
||||
@Test(expected = NullPointerException.class)
|
||||
public void givenNullString_WhenBigDecimalObjectWithStringParameter_ThenNullPointerExceptionIsThrown() {
|
||||
String bigDecimal = null;
|
||||
new BigDecimal(bigDecimal);
|
||||
}
|
||||
|
||||
@Test(expected = NumberFormatException.class)
|
||||
public void givenInalidString_WhenBigDecimalObjectWithStringParameter_ThenNumberFormatExceptionIsThrown() {
|
||||
new BigDecimal("&");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenValidString_WhenValueOfDoubleFromString_ThenResultIsDecimalObject() {
|
||||
BigDecimal bigDecimal = BigDecimal.valueOf(Double.valueOf("123.42"));
|
||||
assertEquals(new BigDecimal(123.42).setScale(2, BigDecimal.ROUND_HALF_UP), bigDecimal);
|
||||
}
|
||||
|
||||
@Test(expected = NullPointerException.class)
|
||||
public void givenNullString_WhenValueOfDoubleFromString_ThenNullPointerExceptionIsThrown() {
|
||||
BigDecimal.valueOf(Double.valueOf(null));
|
||||
}
|
||||
|
||||
@Test(expected = NumberFormatException.class)
|
||||
public void givenInalidString_WhenValueOfDoubleFromString_ThenNumberFormatExceptionIsThrown() {
|
||||
BigDecimal.valueOf(Double.valueOf("&"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenValidString_WhenDecimalFormatOfString_ThenResultIsDecimalObject() throws ParseException {
|
||||
BigDecimal bigDecimal = new BigDecimal(10692467440017.111).setScale(3, BigDecimal.ROUND_HALF_UP);
|
||||
|
||||
DecimalFormatSymbols symbols = new DecimalFormatSymbols();
|
||||
symbols.setGroupingSeparator(',');
|
||||
symbols.setDecimalSeparator('.');
|
||||
String pattern = "#,##0.0#";
|
||||
DecimalFormat decimalFormat = new DecimalFormat(pattern, symbols);
|
||||
decimalFormat.setParseBigDecimal(true);
|
||||
|
||||
// parse the string value
|
||||
BigDecimal parsedStringValue = (BigDecimal) decimalFormat.parse("10,692,467,440,017.111");
|
||||
|
||||
assertEquals(bigDecimal, parsedStringValue);
|
||||
}
|
||||
|
||||
@Test(expected = NullPointerException.class)
|
||||
public void givenNullString_WhenDecimalFormatOfString_ThenNullPointerExceptionIsThrown() throws ParseException {
|
||||
new DecimalFormat("#").parse(null);
|
||||
}
|
||||
|
||||
@Test(expected = ParseException.class)
|
||||
public void givenInalidString_WhenDecimalFormatOfString_ThenNumberFormatExceptionIsThrown() throws ParseException {
|
||||
new DecimalFormat("#").parse("&");
|
||||
}
|
||||
|
||||
}
|
|
@ -3,3 +3,4 @@
|
|||
- [Version Comparison in Java](https://www.baeldung.com/java-comparing-versions)
|
||||
- [Java (String) or .toString()?](https://www.baeldung.com/java-string-casting-vs-tostring)
|
||||
- [Split Java String by Newline](https://www.baeldung.com/java-string-split-by-newline)
|
||||
- [Split a String in Java and Keep the Delimiters](https://www.baeldung.com/java-split-string-keep-delimiters)
|
||||
|
|
|
@ -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");
|
||||
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.example</groupId>
|
||||
<artifactId>jws</artifactId>
|
||||
|
@ -66,4 +67,4 @@
|
|||
<maven-jar-plugin.version>3.0.2</maven-jar-plugin.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
</project>
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>libraries-4</artifactId>
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>libraries-5</artifactId>
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>libraries-6</artifactId>
|
||||
|
||||
|
@ -112,12 +112,12 @@
|
|||
<artifactId>renjin-script-engine</artifactId>
|
||||
<version>${renjin.version}</version>
|
||||
</dependency>
|
||||
<!-- libphonenumber -->
|
||||
<!-- libphonenumber -->
|
||||
<dependency>
|
||||
<groupId>com.googlecode.libphonenumber</groupId>
|
||||
<artifactId>libphonenumber</artifactId>
|
||||
<version>${libphonenumber.version}</version>
|
||||
</dependency>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<repositories>
|
||||
|
|
|
@ -21,7 +21,12 @@ public class ErrorResponseInterceptor implements Interceptor {
|
|||
Gson gson = new Gson();
|
||||
String body = gson.toJson(new ErrorMessage(response.code(), "The response from the server was not OK"));
|
||||
ResponseBody responseBody = ResponseBody.create(body, APPLICATION_JSON);
|
||||
|
||||
|
||||
ResponseBody originalBody = response.body();
|
||||
if (originalBody != null) {
|
||||
originalBody.close();
|
||||
}
|
||||
|
||||
return response.newBuilder()
|
||||
.body(responseBody)
|
||||
.build();
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>libraries</artifactId>
|
||||
<name>libraries</name>
|
||||
|
@ -335,7 +336,8 @@
|
|||
<configuration>
|
||||
<finalName>benchmarks</finalName>
|
||||
<transformers>
|
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||
<mainClass>org.openjdk.jmh.Main</mainClass>
|
||||
</transformer>
|
||||
</transformers>
|
||||
|
|
|
@ -73,8 +73,6 @@
|
|||
</build>
|
||||
|
||||
<properties>
|
||||
<!-- lombok: https://projectlombok.org/changelog.html -->
|
||||
<lombok.version>1.18.10</lombok.version>
|
||||
<!-- various -->
|
||||
<hibernate-jpa-2.1-api.version>1.0.0.Final</hibernate-jpa-2.1-api.version>
|
||||
<!-- delombok maven plugin -->
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
package com.baeldung.mapper;
|
||||
|
||||
import com.baeldung.dto.SimpleSource;
|
||||
import com.baeldung.entity.SimpleDestination;
|
||||
import com.baeldung.service.SimpleService;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
@Mapper(componentModel = "spring")
|
||||
public abstract class SimpleDestinationMapperUsingInjectedService {
|
||||
|
||||
@Autowired
|
||||
protected SimpleService simpleService;
|
||||
|
||||
@Mapping(target = "name", expression = "java(simpleService.enrichName(source.getName()))")
|
||||
public abstract SimpleDestination sourceToDestination(SimpleSource source);
|
||||
|
||||
public abstract SimpleSource destinationToSource(SimpleDestination destination);
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package com.baeldung.service;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class SimpleService {
|
||||
|
||||
public String enrichName(String name) {
|
||||
return "-:: " + name + " ::-";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package com.baeldung.mapper;
|
||||
|
||||
import com.baeldung.dto.SimpleSource;
|
||||
import com.baeldung.entity.SimpleDestination;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration("classpath:applicationContext.xml")
|
||||
public class SimpleDestinationMapperUsingInjectedIntegrationTest {
|
||||
|
||||
@Autowired
|
||||
private SimpleDestinationMapperUsingInjectedService mapper;
|
||||
|
||||
@Test
|
||||
public void givenSourceToDestination_whenMaps_thenNameEnriched() {
|
||||
// Given
|
||||
SimpleSource source = new SimpleSource();
|
||||
source.setName("Bob");
|
||||
source.setDescription("The Builder");
|
||||
|
||||
// When
|
||||
SimpleDestination destination = mapper.sourceToDestination(source);
|
||||
|
||||
// Then
|
||||
assertThat(destination).isNotNull();
|
||||
assertThat(destination.getName()).isEqualTo("-:: Bob ::-");
|
||||
assertThat(destination.getDescription()).isEqualTo("The Builder");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
### Relevant Articles:
|
||||
|
||||
- [Copying Files With Maven](https://www.baeldung.com/maven-copy-files)
|
|
@ -0,0 +1,7 @@
|
|||
## Maven Printing Plugins
|
||||
|
||||
This module contains articles about printing from Maven plugins.
|
||||
|
||||
### Relevant Articles
|
||||
|
||||
- [How to Display a Message in Maven](https://www.baeldung.com/maven-print-message-during-execution)
|
|
@ -49,9 +49,11 @@
|
|||
<goal>echo</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<message>Hello, world</message>
|
||||
<message>Embed a line break: ${line.separator}</message>
|
||||
<message>ArtifactId is ${project.artifactId}</message>
|
||||
<message>
|
||||
Hello, world
|
||||
Embed a line break: ${line.separator}
|
||||
ArtifactId is ${project.artifactId}
|
||||
</message>
|
||||
<level>INFO</level>
|
||||
<toFile>/logs/log-echo.txt</toFile>
|
||||
<append>true</append>
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
<version>2.1.3.RELEASE</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.mantisrx</groupId>
|
||||
|
@ -35,36 +34,31 @@
|
|||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>2.10.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.andreinc.mockneat</groupId>
|
||||
<artifactId>mockneat</artifactId>
|
||||
<version>0.3.8</version>
|
||||
<version>0.4.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.12</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-webflux</artifactId>
|
||||
<version>5.0.9.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.projectreactor.netty</groupId>
|
||||
<artifactId>reactor-netty</artifactId>
|
||||
<version>0.9.12.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>SpringLibReleaseRepo</id>
|
||||
<url>https://repo.spring.io/libs-release/</url>
|
||||
<id>jcenter</id>
|
||||
<url>https://jcenter.bintray.com/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
|
|
|
@ -26,6 +26,11 @@
|
|||
<version>${lombok.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.code.findbugs</groupId>
|
||||
<artifactId>annotations</artifactId>
|
||||
<version>${findbugs.annotations.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
|
@ -41,6 +46,7 @@
|
|||
|
||||
<properties>
|
||||
<intellij.annotations.version>16.0.2</intellij.annotations.version>
|
||||
<findbugs.annotations.version>3.0.1</findbugs.annotations.version>
|
||||
<assertj-core.version>3.9.1</assertj-core.version>
|
||||
</properties>
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -10,3 +10,4 @@ This module contains articles about the Java Persistence API (JPA) in Java.
|
|||
- [JPA CascadeType.REMOVE vs orphanRemoval](https://www.baeldung.com/jpa-cascade-remove-vs-orphanremoval)
|
||||
- [A Guide to MultipleBagFetchException in Hibernate](https://www.baeldung.com/java-hibernate-multiplebagfetchexception)
|
||||
- [How to Convert a Hibernate Proxy to a Real Entity Object](https://www.baeldung.com/hibernate-proxy-to-real-entity-object)
|
||||
- [Returning an Auto-Generated Id with JPA](https://www.baeldung.com/jpa-get-auto-generated-id)
|
||||
|
|
|
@ -68,6 +68,12 @@
|
|||
<version>${assertj.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>${junit.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -97,4 +97,20 @@
|
|||
<property name="hibernate.temp.use_jdbc_metadata_defaults" value="false"/>
|
||||
</properties>
|
||||
</persistence-unit>
|
||||
|
||||
<persistence-unit name="jpa-h2-id-generation">
|
||||
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
|
||||
<class>com.baeldung.jpa.IdGeneration.User</class>
|
||||
<exclude-unlisted-classes>true</exclude-unlisted-classes>
|
||||
<properties>
|
||||
<property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
|
||||
<property name="javax.persistence.jdbc.url" value="jdbc:h2:mem:idGen"/>
|
||||
<property name="javax.persistence.jdbc.user" value="sa"/>
|
||||
<property name="javax.persistence.jdbc.password" value=""/>
|
||||
<property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
|
||||
<property name="hibernate.hbm2ddl.auto" value="create-drop"/>
|
||||
<property name="hibernate.format_sql" value="true"/>
|
||||
<property name="hibernate.temp.use_jdbc_metadata_defaults" value="false"/>
|
||||
</properties>
|
||||
</persistence-unit>
|
||||
</persistence>
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -9,6 +9,7 @@ This module contains articles about annotations used in Spring Data JPA
|
|||
- [Spring JPA @Embedded and @EmbeddedId](https://www.baeldung.com/spring-jpa-embedded-method-parameters)
|
||||
- [Programmatic Transaction Management in Spring](https://www.baeldung.com/spring-programmatic-transaction-management)
|
||||
- [JPA Entity Lifecycle Events](https://www.baeldung.com/jpa-entity-lifecycle-events)
|
||||
- [Overriding Column Definition With @AttributeOverride](https://www.baeldung.com/jpa-attributeoverride)
|
||||
|
||||
### Eclipse Config
|
||||
After importing the project into Eclipse, you may see the following error:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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<Owner, Address> 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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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<Car, Integer> {
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@ This module contains articles about CRUD operations in Spring Data JPA
|
|||
- [Batch Insert/Update with Hibernate/JPA](https://www.baeldung.com/jpa-hibernate-batch-insert-update)
|
||||
- [Difference Between save() and saveAndFlush() in Spring Data JPA](https://www.baeldung.com/spring-data-jpa-save-saveandflush)
|
||||
- [Generate Database Schema with Spring Data JPA](https://www.baeldung.com/spring-data-jpa-generate-db-schema)
|
||||
- [How to Implement a Soft Delete with Spring JPA](https://www.baeldung.com/spring-jpa-soft-delete)
|
||||
|
||||
### Eclipse Config
|
||||
After importing the project into Eclipse, you may see the following error:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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<Product> findAll(@RequestParam(value = "isDeleted", required = false, defaultValue = "false") boolean isDeleted) {
|
||||
return productService.findAll(isDeleted);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package com.baeldung.softdelete;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
|
||||
public interface ProductRepository extends CrudRepository<Product, Long>{
|
||||
|
||||
}
|
|
@ -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<Product> findAll(boolean isDeleted){
|
||||
Session session = entityManager.unwrap(Session.class);
|
||||
Filter filter = session.enableFilter("deletedProductFilter");
|
||||
filter.setParameter("isDeleted", isDeleted);
|
||||
Iterable<Product> products = productRepository.findAll();
|
||||
session.disableFilter("deletedProductFilter");
|
||||
return products;
|
||||
}
|
||||
}
|
|
@ -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
|
||||
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
|
||||
|
||||
|
|
3
pom.xml
3
pom.xml
|
@ -1276,6 +1276,7 @@
|
|||
</build>
|
||||
|
||||
<modules>
|
||||
<module>spring-boot-modules/spring-boot-cassandre</module>
|
||||
<module>core-java-modules/core-java-9</module>
|
||||
<module>core-java-modules/core-java-9-improvements</module>
|
||||
<module>core-java-modules/core-java-9-jigsaw</module>
|
||||
|
@ -1404,7 +1405,7 @@
|
|||
<maven-jxr-plugin.version>3.0.0</maven-jxr-plugin.version>
|
||||
<!-- <maven-pmd-plugin.version>3.9.0</maven-pmd-plugin.version> -->
|
||||
<maven-pmd-plugin.version>3.13.0</maven-pmd-plugin.version>
|
||||
<lombok.version>1.16.12</lombok.version>
|
||||
<lombok.version>1.18.20</lombok.version>
|
||||
<h2.version>1.4.197</h2.version>
|
||||
</properties>
|
||||
|
||||
|
|
|
@ -146,7 +146,7 @@ public class WebClientLoggingIntegrationTest {
|
|||
.exchange()
|
||||
.block();
|
||||
|
||||
verify(mockAppender).doAppend(argThat(argument -> (((LoggingEvent) argument).getFormattedMessage()).contains("domain=.typicode.com;")));
|
||||
verify(mockAppender).doAppend(argThat(argument -> (((LoggingEvent) argument).getFormattedMessage()).contains(sampleUrl)));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -70,7 +70,6 @@
|
|||
<module>spring-boot-swagger-jwt</module>
|
||||
<module>spring-boot-testing</module>
|
||||
<module>spring-boot-vue</module>
|
||||
<module>spring-boot-xml</module>
|
||||
<module>spring-boot-actuator</module>
|
||||
<module>spring-boot-data-2</module>
|
||||
<module>spring-boot-react</module>
|
||||
|
|
|
@ -60,7 +60,7 @@
|
|||
</build>
|
||||
|
||||
<properties>
|
||||
<spring-boot-admin-starter-client.version>2.4.0</spring-boot-admin-starter-client.version>
|
||||
<spring-boot-admin-starter-client.version>2.4.1</spring-boot-admin-starter-client.version>
|
||||
<spring-boot-maven-plugin.version>2.0.4.RELEASE</spring-boot-maven-plugin.version>
|
||||
</properties>
|
||||
|
||||
|
|
|
@ -76,8 +76,8 @@
|
|||
</build>
|
||||
|
||||
<properties>
|
||||
<spring-boot-admin-server.version>2.4.0</spring-boot-admin-server.version>
|
||||
<spring-boot-admin-starter-client.version>2.4.0</spring-boot-admin-starter-client.version>
|
||||
<spring-boot-admin-server.version>2.4.1</spring-boot-admin-server.version>
|
||||
<spring-boot-admin-starter-client.version>2.4.1</spring-boot-admin-starter-client.version>
|
||||
<spring-boot-admin-server-ui-login.version>1.5.7</spring-boot-admin-server-ui-login.version>
|
||||
<spring-boot-maven-plugin.version>2.0.4.RELEASE</spring-boot-maven-plugin.version>
|
||||
</properties>
|
||||
|
|
|
@ -5,3 +5,4 @@ This module contains articles about Spring Boot customization 2
|
|||
### Relevant Articles:
|
||||
|
||||
- [DispatcherServlet and web.xml in Spring Boot](https://www.baeldung.com/spring-boot-dispatcherservlet-web-xml)
|
||||
- [XML Defined Beans in Spring Boot](https://www.baeldung.com/spring-boot-xml-beans)
|
|
@ -23,7 +23,10 @@
|
|||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
sample=string loaded from properties!
|
|
@ -1,5 +1,6 @@
|
|||
package com.baeldung.springbootxml;
|
||||
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
@ -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/cassandre-spring-boot-trading-bot)
|
|
@ -0,0 +1,68 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.4.5</version>
|
||||
<relativePath /> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<groupId>com.example</groupId>
|
||||
<artifactId>demo</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>Cassandre trading bot tutorial</name>
|
||||
<description>Cassandre trading bot tutorial</description>
|
||||
<properties>
|
||||
<java.version>11</java.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Cassandre dependencies -->
|
||||
<dependency>
|
||||
<groupId>tech.cassandre.trading.bot</groupId>
|
||||
<artifactId>cassandre-trading-bot-spring-boot-starter</artifactId>
|
||||
<version>4.2.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.knowm.xchange</groupId>
|
||||
<artifactId>xchange-kucoin</artifactId>
|
||||
<version>5.0.7</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hsqldb</groupId>
|
||||
<artifactId>hsqldb</artifactId>
|
||||
<version>2.5.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- Cassandre dependencies -->
|
||||
<dependency>
|
||||
<groupId>tech.cassandre.trading.bot</groupId>
|
||||
<artifactId>cassandre-trading-bot-spring-boot-starter-test</artifactId>
|
||||
<version>4.2.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<version>2.4.5</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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<CurrencyPairDTO> getRequestedCurrencyPairs() {
|
||||
return Set.of(new CurrencyPairDTO(BTC, USDT));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<AccountDTO> getTradeAccount(Set<AccountDTO> 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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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=
|
|
@ -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() {
|
||||
}
|
||||
|
||||
}
|
|
@ -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<CurrencyDTO, GainDTO> 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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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=
|
|
@ -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
|
|
|
@ -0,0 +1,3 @@
|
|||
BTC 1
|
||||
USDT 100000
|
||||
ETH 10
|
|
|
@ -8,6 +8,8 @@ import java.security.Principal;
|
|||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
@Controller
|
||||
public class WebController {
|
||||
|
||||
|
@ -19,6 +21,12 @@ public class WebController {
|
|||
return "external";
|
||||
}
|
||||
|
||||
@GetMapping("/logout")
|
||||
public String logout(HttpServletRequest request) throws Exception {
|
||||
request.logout();
|
||||
return "redirect:/";
|
||||
}
|
||||
|
||||
@GetMapping(path = "/customers")
|
||||
public String customers(Principal principal, Model model) {
|
||||
addCustomers();
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
</table>
|
||||
<div id="pagefoot" th:include="layout :: footerFragment">Footer
|
||||
</div>
|
||||
<a href="/logout">Logout</a>
|
||||
</div>
|
||||
<!-- container -->
|
||||
</body>
|
||||
|
|
|
@ -9,4 +9,5 @@ This module contains articles about Spring Web MVC in Spring Boot projects.
|
|||
- [Spring MVC Async vs Spring WebFlux](https://www.baeldung.com/spring-mvc-async-vs-webflux)
|
||||
- [Differences in @Valid and @Validated Annotations in Spring](https://www.baeldung.com/spring-valid-vs-validated)
|
||||
- [CharacterEncodingFilter In SpringBoot](https://www.baeldung.com/spring-boot-characterencodingfilter)
|
||||
- [HandlerInterceptors vs. Filters in Spring MVC](https://www.baeldung.com/spring-mvc-handlerinterceptor-vs-filter)
|
||||
- More articles: [[prev -->]](/spring-boot-modules/spring-boot-mvc-2)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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";
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>Spring Filters vs Interceptors</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h3>Hello</h3>
|
||||
</body>
|
||||
</html>
|
|
@ -1,3 +0,0 @@
|
|||
### Relevant Articles:
|
||||
|
||||
- [XML Defined Beans in Spring Boot](https://www.baeldung.com/spring-boot-xml-beans)
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue