Merge pull request #75 from eugenp/master

update
This commit is contained in:
Maiklins 2020-10-23 21:24:53 +02:00 committed by GitHub
commit 470ccf8c9a
119 changed files with 1501 additions and 206 deletions

View File

@ -10,4 +10,4 @@ This module contains articles about algorithms. Some classes of algorithms, e.g.
- [Introduction to Minimax Algorithm](https://www.baeldung.com/java-minimax-algorithm) - [Introduction to Minimax Algorithm](https://www.baeldung.com/java-minimax-algorithm)
- [How to Calculate Levenshtein Distance in Java?](https://www.baeldung.com/java-levenshtein-distance) - [How to Calculate Levenshtein Distance in Java?](https://www.baeldung.com/java-levenshtein-distance)
- [How to Find the Kth Largest Element in Java](https://www.baeldung.com/java-kth-largest-element) - [How to Find the Kth Largest Element in Java](https://www.baeldung.com/java-kth-largest-element)
- More articles: [[next -->]](/../algorithms-miscellaneous-2) - More articles: [[next -->]](/algorithms-miscellaneous-2)

View File

@ -14,4 +14,4 @@ This module contains articles about algorithms. Some classes of algorithms, e.g.
- [Displaying Money Amounts in Words](https://www.baeldung.com/java-money-into-words) - [Displaying Money Amounts in Words](https://www.baeldung.com/java-money-into-words)
- [A Collaborative Filtering Recommendation System in Java](https://www.baeldung.com/java-collaborative-filtering-recommendations) - [A Collaborative Filtering Recommendation System in Java](https://www.baeldung.com/java-collaborative-filtering-recommendations)
- [Implementing A* Pathfinding in Java](https://www.baeldung.com/java-a-star-pathfinding) - [Implementing A* Pathfinding in Java](https://www.baeldung.com/java-a-star-pathfinding)
- More articles: [[<-- prev]](/../algorithms-miscellaneous-1) [[next -->]](/../algorithms-miscellaneous-3) - More articles: [[<-- prev]](/algorithms-miscellaneous-1) [[next -->]](/algorithms-miscellaneous-3)

View File

@ -15,5 +15,5 @@ This module contains articles about algorithms. Some classes of algorithms, e.g.
- [Maximum Subarray Problem](https://www.baeldung.com/java-maximum-subarray) - [Maximum Subarray Problem](https://www.baeldung.com/java-maximum-subarray)
- [How to Merge Two Sorted Arrays](https://www.baeldung.com/java-merge-sorted-arrays) - [How to Merge Two Sorted Arrays](https://www.baeldung.com/java-merge-sorted-arrays)
- [Median of Stream of Integers using Heap](https://www.baeldung.com/java-stream-integers-median-using-heap) - [Median of Stream of Integers using Heap](https://www.baeldung.com/java-stream-integers-median-using-heap)
- More articles: [[<-- prev]](/../algorithms-miscellaneous-4) [[next -->]](/../algorithms-miscellaneous-6) - More articles: [[<-- prev]](/algorithms-miscellaneous-4) [[next -->]](/algorithms-miscellaneous-6)

View File

@ -10,4 +10,4 @@
- [Implementing a 2048 Solver in Java](https://www.baeldung.com/2048-java-solver) - [Implementing a 2048 Solver in Java](https://www.baeldung.com/2048-java-solver)
- [Finding Top K Elements in an Array](https://www.baeldung.com/java-array-top-elements) - [Finding Top K Elements in an Array](https://www.baeldung.com/java-array-top-elements)
- [Reversing a Linked List in Java](https://www.baeldung.com/java-reverse-linked-list) - [Reversing a Linked List in Java](https://www.baeldung.com/java-reverse-linked-list)
- More articles: [[<-- prev]](/../algorithms-miscellaneous-5) - More articles: [[<-- prev]](/algorithms-miscellaneous-5)

View File

@ -8,3 +8,4 @@ This module contains articles about Apache Spark
- [Building a Data Pipeline with Kafka, Spark Streaming and Cassandra](https://www.baeldung.com/kafka-spark-data-pipeline) - [Building a Data Pipeline with Kafka, Spark Streaming and Cassandra](https://www.baeldung.com/kafka-spark-data-pipeline)
- [Machine Learning with Spark MLlib](https://www.baeldung.com/spark-mlib-machine-learning) - [Machine Learning with Spark MLlib](https://www.baeldung.com/spark-mlib-machine-learning)
- [Introduction to Spark Graph Processing with GraphFrames](https://www.baeldung.com/spark-graph-graphframes) - [Introduction to Spark Graph Processing with GraphFrames](https://www.baeldung.com/spark-graph-graphframes)
- [Apache Spark: Differences between Dataframes, Datasets and RDDs](https://www.baeldung.com/java-spark-dataframe-dataset-rdd)

View File

@ -19,12 +19,12 @@ public class StudentDbService implements StudentService {
} }
public Student update(Student student) { public Student update(Student student) {
logger.log(Level.INFO, "Updating sutdent in DB..."); logger.log(Level.INFO, "Updating student in DB...");
return student; return student;
} }
public String delete(String registrationId) { public String delete(String registrationId) {
logger.log(Level.INFO, "Deleteing sutdent in DB..."); logger.log(Level.INFO, "Deleting student in DB...");
return registrationId; return registrationId;
} }
} }

View File

@ -33,11 +33,15 @@ public class HashSetBenchmark {
private List<Employee> employeeList1 = new ArrayList<>(); private List<Employee> employeeList1 = new ArrayList<>();
private Set<Employee> employeeSet2 = new HashSet<>(); private Set<Employee> employeeSet2 = new HashSet<>();
private List<Employee> employeeList2 = new ArrayList<>(); private List<Employee> employeeList2 = new ArrayList<>();
private Set<Employee> employeeSet3 = new HashSet<>();
private Set<Employee> employeeSet4 = new HashSet<>();
private long set1Size = 60000; private long set1Size = 60000;
private long list1Size = 50000; private long list1Size = 50000;
private long set2Size = 50000; private long set2Size = 50000;
private long list2Size = 60000; private long list2Size = 60000;
private long set3Size = 50000;
private long set4Size = 60000;
@Setup(Level.Trial) @Setup(Level.Trial)
public void setUp() { public void setUp() {
@ -58,6 +62,14 @@ public class HashSetBenchmark {
employeeList2.add(new Employee(i, RandomStringUtils.random(7, true, false))); employeeList2.add(new Employee(i, RandomStringUtils.random(7, true, false)));
} }
for (long i = 0; i < set3Size; i++) {
employeeSet3.add(new Employee(i, RandomStringUtils.random(7, true, false)));
}
for (long i = 0; i < set4Size; i++) {
employeeSet4.add(new Employee(i, RandomStringUtils.random(7, true, false)));
}
} }
} }
@ -72,6 +84,11 @@ public class HashSetBenchmark {
return state.employeeSet2.removeAll(state.employeeList2); return state.employeeSet2.removeAll(state.employeeList2);
} }
@Benchmark
public boolean given_SizeOfHashsetSmallerThanSizeOfAnotherHashSet_When_RemoveAllFromHashSet_Then_GoodPerformance(MyState state) {
return state.employeeSet3.removeAll(state.employeeSet4);
}
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
Options options = new OptionsBuilder().include(HashSetBenchmark.class.getSimpleName()) Options options = new OptionsBuilder().include(HashSetBenchmark.class.getSimpleName())
.threads(1) .threads(1)

View File

@ -73,7 +73,7 @@ public class LivelockExample {
public void tryLock(Lock lock, long millis) { public void tryLock(Lock lock, long millis) {
try { try {
lock.tryLock(10, TimeUnit.MILLISECONDS); lock.tryLock(millis, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) { } catch (InterruptedException e) {
e.printStackTrace(); e.printStackTrace();
} }

View File

@ -0,0 +1,6 @@
package com.baeldung.exceptions.classcastexception;
public interface Animal {
String getName();
}

View File

@ -0,0 +1,14 @@
package com.baeldung.exceptions.classcastexception;
public class Box<T> {
private T content;
public T getContent() {
return content;
}
public void setContent(T content) {
this.content = content;
}
}

View File

@ -0,0 +1,9 @@
package com.baeldung.exceptions.classcastexception;
public class Frog extends Reptile {
@Override
public String getName() {
return super.getName() + ": Frog";
}
}

View File

@ -0,0 +1,9 @@
package com.baeldung.exceptions.classcastexception;
public class Mammal implements Animal {
@Override
public String getName() {
return "Mammal";
}
}

View File

@ -0,0 +1,9 @@
package com.baeldung.exceptions.classcastexception;
public class Reptile implements Animal {
@Override
public String getName() {
return "Reptile";
}
}

View File

@ -0,0 +1,40 @@
package com.baeldung.exceptions.classcastexception;
import org.junit.Test;
import java.io.Serializable;
public class CheckedCastsUnitTest {
@Test(expected = ClassCastException.class)
public void givenBaseTypeVariableReferencingChildInstance_whenCastToIncompatibleSubtype_thenClassCastException() {
Animal animal = new Frog();
//A checked downcast to Mammal is incompatible from Frog because Frog is not a subtype of Mammal.
Mammal mammal = (Mammal) animal;
}
@Test(expected = ClassCastException.class)
public void givenBaseTypeVariableReferencingChildInstance_whenCastToIncompatibleInterface_thenClassCastException() {
Animal animal = new Frog();
//A checked cast to Serializable is incompatible from Frog because Frog is not a subtype of Serializable.
Serializable serial = (Serializable) animal;
}
@Test(expected = ClassCastException.class)
public void givenObjectVariableReferencingPrimitiveArray_whenCastToBoxedTypeArray_thenClassCastException() {
Object primitives = new int[1];
//A checked cast to Integer[] is incompatible from primitive arrays. Auto-boxing does not work for arrays.
Integer[] integers = (Integer[]) primitives;
}
@Test(expected = ClassCastException.class)
public void givenObjectVariableReferencingPrimitiveArray_whenCastToPromotedTypeArray_thenClassCastException() {
Object primitives = new int[1];
//A checked cast to long[] is incompatible from int[]. Type promotion does not work for arrays.
long[] longs = (long[]) primitives;
}
}

View File

@ -0,0 +1,21 @@
package com.baeldung.exceptions.classcastexception;
import org.junit.Test;
public class GenericConversionUnitTest {
@Test(expected = ClassCastException.class)
public void givenIncompatibleType_whenConvertInstanceOfObject_thenClassCastException() {
// Should have been null, but due to type erasure, inside convertInstanceOfObject,
// it will attempt to cast to Object instead of String, so it casts to Object, which is always possible.
String shouldBeNull = convertInstanceOfObject(123);
}
public static <T> T convertInstanceOfObject(Object o) {
try {
return (T) o; // Casts to Object due to type erasure
} catch (ClassCastException e) {
return null; // Will never reach this
}
}
}

View File

@ -0,0 +1,17 @@
package com.baeldung.exceptions.classcastexception;
import org.junit.Test;
public class UncheckedConversionUnitTest {
@Test(expected = ClassCastException.class)
public void givenPollutedGenericType_whenGetProperty_thenClassCastException() {
Box<Long> originalBox = new Box<>();
Box raw = originalBox;
raw.setContent(2.5);
Box<Long> bound = (Box<Long>) raw;
//An incompatible element was found in the raw box.
Long content = bound.getContent();
}
}

View File

@ -7,4 +7,5 @@ This module contains articles about core features in the Java language
- [When are Static Variables Initialized in Java?](https://www.baeldung.com/java-static-variables-initialization) - [When are Static Variables Initialized in Java?](https://www.baeldung.com/java-static-variables-initialization)
- [Checking if a Class Exists in Java](https://www.baeldung.com/java-check-class-exists) - [Checking if a Class Exists in Java](https://www.baeldung.com/java-check-class-exists)
- [The Difference Between a.getClass() and A.class in Java](https://www.baeldung.com/java-getclass-vs-class) - [The Difference Between a.getClass() and A.class in Java](https://www.baeldung.com/java-getclass-vs-class)
- [Constants in Java: Patterns and Anti-Patterns](https://www.baeldung.com/java-constants-good-practices)
- [[<-- Prev]](/core-java-modules/core-java-lang-2) - [[<-- Prev]](/core-java-modules/core-java-lang-2)

View File

@ -0,0 +1,37 @@
package com.baeldung.constantspatterns;
public class Calculator {
public static final double PI = 3.14159265359;
private static final double UPPER_LIMIT = 0x1.fffffffffffffP+1023;
public enum Operation {
ADD, SUBTRACT, DIVIDE, MULTIPLY
}
public double operateOnTwoNumbers(double numberOne, double numberTwo, Operation operation) {
if (numberOne > UPPER_LIMIT) {
throw new IllegalArgumentException("'numberOne' is too large");
}
if (numberTwo > UPPER_LIMIT) {
throw new IllegalArgumentException("'numberTwo' is too large");
}
double answer = 0;
switch (operation) {
case ADD:
answer = numberOne + numberTwo;
break;
case SUBTRACT:
answer = numberOne - numberTwo;
break;
case DIVIDE:
answer = numberOne / numberTwo;
break;
case MULTIPLY:
answer = numberOne * numberTwo;
break;
}
return answer;
}
}

View File

@ -0,0 +1,10 @@
package com.baeldung.constantspatterns;
public interface CalculatorConstants {
double PI = 3.14159265359;
double UPPER_LIMIT = 0x1.fffffffffffffP+1023;
enum Operation {
ADD, SUBTRACT, MULTIPLY, DIVIDE
};
}

View File

@ -0,0 +1,32 @@
package com.baeldung.constantspatterns;
public class GeometryCalculator implements CalculatorConstants {
public static final double UPPER_LIMIT = 100000000000000000000.0;
public double operateOnTwoNumbers(double numberOne, double numberTwo, Operation operation) {
if (numberOne > UPPER_LIMIT) {
throw new IllegalArgumentException("'numberOne' is too large");
}
if (numberTwo > UPPER_LIMIT) {
throw new IllegalArgumentException("'numberTwo' is too large");
}
double answer = 0;
switch (operation) {
case ADD:
answer = numberOne + numberTwo;
break;
case SUBTRACT:
answer = numberOne - numberTwo;
break;
case DIVIDE:
answer = numberOne / numberTwo;
break;
case MULTIPLY:
answer = numberOne * numberTwo;
break;
}
return answer;
}
}

View File

@ -0,0 +1,16 @@
package com.baeldung.constantspatterns.calculations;
public final class MathConstants {
public static final double PI = 3.14159265359;
static final double GOLDEN_RATIO = 1.6180;
static final double GRAVITATIONAL_ACCELERATION = 9.8;
static final double EULERS_NUMBER = 2.7182818284590452353602874713527;
public enum Operation {
ADD, SUBTRACT, DIVIDE, MULTIPLY
}
private MathConstants() {
}
}

View File

@ -0,0 +1,23 @@
package com.baeldung.constantspatterns;
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.Test;
public class ConstantPatternUnitTest {
@Test
public void givenTwoNumbersAndAdd_whenCallingCalculatorOperatOneTwoNumbers_thenCorrectAnswerReturned() {
Calculator calculator = new Calculator();
double expected = 4;
double answer = calculator.operateOnTwoNumbers(2, 2, Calculator.Operation.ADD);
assertEquals(expected, answer);
}
@Test
public void givenTwoNumbersAndAdd_whenCallingGeometryCalculatorOperatOneTwoNumbers_thenCorrectAnswerReturned() {
GeometryCalculator calculator = new GeometryCalculator();
double expected = 4;
double answer = calculator.operateOnTwoNumbers(2, 2, GeometryCalculator.Operation.ADD);
assertEquals(expected, answer);
}
}

View File

@ -14,4 +14,5 @@ This module contains articles about networking in Java
- [Handling java.net.ConnectException](https://www.baeldung.com/java-net-connectexception) - [Handling java.net.ConnectException](https://www.baeldung.com/java-net-connectexception)
- [Getting MAC addresses in Java](https://www.baeldung.com/java-mac-address) - [Getting MAC addresses in Java](https://www.baeldung.com/java-mac-address)
- [Sending Emails with Attachments in Java](https://www.baeldung.com/java-send-emails-attachments) - [Sending Emails with Attachments in Java](https://www.baeldung.com/java-send-emails-attachments)
- [Finding a Free Port in Java](https://www.baeldung.com/java-free-port)
- [[<-- Prev]](/core-java-modules/core-java-networking) - [[<-- Prev]](/core-java-modules/core-java-networking)

View File

@ -3,7 +3,7 @@ package com.baeldung.hashing;
class SHACommonUtils { class SHACommonUtils {
public static String bytesToHex(byte[] hash) { public static String bytesToHex(byte[] hash) {
StringBuffer hexString = new StringBuffer(); StringBuilder hexString = new StringBuilder(2 * hash.length);
for (byte h : hash) { for (byte h : hash) {
String hex = Integer.toHexString(0xff & h); String hex = Integer.toHexString(0xff & h);
if (hex.length() == 1) if (hex.length() == 1)

View File

@ -104,16 +104,12 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId> <artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
</plugin> </plugin>
</plugins> </plugins>
</build> </build>
<properties> <properties>
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
<joda-money.version>1.0.1</joda-money.version> <joda-money.version>1.0.1</joda-money.version>
<junit-jupiter.version>5.6.2</junit-jupiter.version>
</properties> </properties>
</project> </project>

View File

@ -0,0 +1,78 @@
<?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">
<modelVersion>4.0.0</modelVersion>
<artifactId>mantis</artifactId>
<name>Mantis</name>
<packaging>jar</packaging>
<description>Sample project for Netflix Mantis</description>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-boot-2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../../parent-boot-2</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.1.3.RELEASE</version>
</dependency>
<dependency>
<groupId>io.mantisrx</groupId>
<artifactId>mantis-runtime</artifactId>
<version>1.2.63</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
<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>
</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>
</repository>
</repositories>
</project>

View File

@ -0,0 +1,23 @@
package com.baeldung.netflix.mantis;
import com.baeldung.netflix.mantis.job.LogAggregationJob;
import io.mantisrx.runtime.executor.LocalJobExecutorNetworked;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@Slf4j
@SpringBootApplication
public class MantisApplication implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication.run(MantisApplication.class, args);
}
@Override
public void run(String... args) {
LocalJobExecutorNetworked.execute(new LogAggregationJob().getJobInstance());
}
}

View File

@ -0,0 +1,37 @@
package com.baeldung.netflix.mantis.job;
import com.baeldung.netflix.mantis.model.LogAggregate;
import com.baeldung.netflix.mantis.source.RandomLogSource;
import com.baeldung.netflix.mantis.stage.CountLogStage;
import com.baeldung.netflix.mantis.stage.GroupLogStage;
import com.baeldung.netflix.mantis.stage.TransformLogStage;
import io.mantisrx.runtime.Job;
import io.mantisrx.runtime.MantisJob;
import io.mantisrx.runtime.MantisJobProvider;
import io.mantisrx.runtime.Metadata;
import io.mantisrx.runtime.sink.Sink;
import io.mantisrx.runtime.sink.Sinks;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
@NoArgsConstructor
@AllArgsConstructor
public class LogAggregationJob extends MantisJobProvider<LogAggregate> {
private Sink<LogAggregate> sink = Sinks.eagerSubscribe(Sinks.sse(LogAggregate::toJsonString));
@Override
public Job<LogAggregate> getJobInstance() {
return MantisJob
.source(new RandomLogSource())
.stage(new TransformLogStage(), TransformLogStage.stageConfig())
.stage(new GroupLogStage(), GroupLogStage.config())
.stage(new CountLogStage(), CountLogStage.config())
.sink(sink)
.metadata(new Metadata.Builder().build())
.create();
}
}

View File

@ -0,0 +1,34 @@
package com.baeldung.netflix.mantis.job;
import com.baeldung.netflix.mantis.model.LogEvent;
import com.baeldung.netflix.mantis.sink.LogSink;
import com.baeldung.netflix.mantis.source.RandomLogSource;
import com.baeldung.netflix.mantis.stage.TransformLogStage;
import io.mantisrx.runtime.Job;
import io.mantisrx.runtime.MantisJob;
import io.mantisrx.runtime.MantisJobProvider;
import io.mantisrx.runtime.Metadata;
import io.mantisrx.runtime.ScalarToScalar;
import io.mantisrx.runtime.sink.Sink;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
@NoArgsConstructor
@AllArgsConstructor
public class LogCollectingJob extends MantisJobProvider<LogEvent> {
private Sink<LogEvent> sink = new LogSink();
@Override
public Job<LogEvent> getJobInstance() {
return MantisJob
.source(new RandomLogSource())
.stage(new TransformLogStage(), new ScalarToScalar.Config<>())
.sink(sink)
.metadata(new Metadata.Builder().build())
.create();
}
}

View File

@ -0,0 +1,28 @@
package com.baeldung.netflix.mantis.model;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.mantisrx.runtime.codec.JsonType;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class LogAggregate implements JsonType {
private static final ObjectMapper mapper = new ObjectMapper();
private Integer count;
private String level;
public String toJsonString() {
try {
return mapper.writeValueAsString(this);
} catch (JsonProcessingException e) {
return null;
}
}
}

View File

@ -0,0 +1,35 @@
package com.baeldung.netflix.mantis.model;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.mantisrx.runtime.codec.JsonType;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@NoArgsConstructor
public class LogEvent implements JsonType {
private static final ObjectMapper mapper = new ObjectMapper();
private Long index;
private String level;
private String message;
public LogEvent(String[] parts) {
this.index = Long.valueOf(parts[0]);
this.level = parts[1];
this.message = parts[2];
}
public String toJsonString() {
try {
return mapper.writeValueAsString(this);
} catch (JsonProcessingException e) {
return null;
}
}
}

View File

@ -0,0 +1,37 @@
package com.baeldung.netflix.mantis.sink;
import com.baeldung.netflix.mantis.model.LogEvent;
import io.mantisrx.runtime.Context;
import io.mantisrx.runtime.PortRequest;
import io.mantisrx.runtime.sink.SelfDocumentingSink;
import io.mantisrx.runtime.sink.ServerSentEventsSink;
import io.mantisrx.runtime.sink.Sink;
import io.mantisrx.runtime.sink.predicate.Predicate;
import rx.Observable;
public class LogSink implements Sink<LogEvent> {
@Override
public void call(Context context, PortRequest portRequest, Observable<LogEvent> logEventObservable) {
SelfDocumentingSink<LogEvent> sink = new ServerSentEventsSink.Builder<LogEvent>()
.withEncoder(LogEvent::toJsonString)
.withPredicate(filterByLogMessage())
.build();
logEventObservable.subscribe();
sink.call(context, portRequest, logEventObservable);
}
private Predicate<LogEvent> filterByLogMessage() {
return new Predicate<>("filter by message",
parameters -> {
if (parameters != null && parameters.containsKey("filter")) {
return logEvent -> logEvent.getMessage().contains(parameters.get("filter").get(0));
}
return logEvent -> true;
});
}
}

View File

@ -0,0 +1,46 @@
package com.baeldung.netflix.mantis.source;
import io.mantisrx.runtime.Context;
import io.mantisrx.runtime.source.Index;
import io.mantisrx.runtime.source.Source;
import lombok.extern.slf4j.Slf4j;
import net.andreinc.mockneat.MockNeat;
import rx.Observable;
import java.util.Date;
import java.util.concurrent.TimeUnit;
@Slf4j
public class RandomLogSource implements Source<String> {
private MockNeat mockDataGenerator;
@Override
public void init(Context context, Index index) {
mockDataGenerator = MockNeat.threadLocal();
}
@Override
public Observable<Observable<String>> call(Context context, Index index) {
return Observable.just(
Observable
.interval(250, TimeUnit.MILLISECONDS)
.map(this::createRandomLogEvent));
}
private String createRandomLogEvent(Long tick) {
String level = mockDataGenerator.probabilites(String.class)
.add(0.5, "INFO")
.add(0.3, "WARN")
.add(0.2, "ERROR")
.get();
String message = mockDataGenerator.probabilites(String.class)
.add(0.5, "login attempt")
.add(0.5, "user created")
.get();
return tick + "#" + level + "#" + message;
}
}

View File

@ -0,0 +1,58 @@
package com.baeldung.netflix.mantis.stage;
import com.baeldung.netflix.mantis.model.LogAggregate;
import com.baeldung.netflix.mantis.model.LogEvent;
import io.mantisrx.common.MantisGroup;
import io.mantisrx.runtime.Context;
import io.mantisrx.runtime.GroupToScalar;
import io.mantisrx.runtime.codec.JacksonCodecs;
import io.mantisrx.runtime.computation.GroupToScalarComputation;
import io.mantisrx.runtime.parameter.ParameterDefinition;
import io.mantisrx.runtime.parameter.type.IntParameter;
import io.mantisrx.runtime.parameter.validator.Validators;
import rx.Observable;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
public class CountLogStage implements GroupToScalarComputation<String, LogEvent, LogAggregate> {
private int duration;
@Override
public void init(Context context) {
duration = (int)context.getParameters().get("LogAggregationDuration", 1000);
}
@Override
public Observable<LogAggregate> call(Context context, Observable<MantisGroup<String, LogEvent>> mantisGroup) {
return mantisGroup
.window(duration, TimeUnit.MILLISECONDS)
.flatMap(o -> o.groupBy(MantisGroup::getKeyValue)
.flatMap(group -> group.reduce(0, (count, value) -> count = count + 1)
.map((count) -> new LogAggregate(count, group.getKey()))
));
}
public static GroupToScalar.Config<String, LogEvent, LogAggregate> config(){
return new GroupToScalar.Config<String, LogEvent, LogAggregate>()
.description("sum events for a log level")
.codec(JacksonCodecs.pojo(LogAggregate.class))
.withParameters(getParameters());
}
public static List<ParameterDefinition<?>> getParameters() {
List<ParameterDefinition<?>> params = new ArrayList<>();
params.add(new IntParameter()
.name("LogAggregationDuration")
.description("window size for aggregation in milliseconds")
.validator(Validators.range(100, 10000))
.defaultValue(5000)
.build()) ;
return params;
}
}

View File

@ -0,0 +1,25 @@
package com.baeldung.netflix.mantis.stage;
import com.baeldung.netflix.mantis.model.LogEvent;
import io.mantisrx.common.MantisGroup;
import io.mantisrx.runtime.Context;
import io.mantisrx.runtime.ScalarToGroup;
import io.mantisrx.runtime.codec.JacksonCodecs;
import io.mantisrx.runtime.computation.ToGroupComputation;
import rx.Observable;
public class GroupLogStage implements ToGroupComputation<LogEvent, String, LogEvent> {
@Override
public Observable<MantisGroup<String, LogEvent>> call(Context context, Observable<LogEvent> logEvent) {
return logEvent.map(log -> new MantisGroup<>(log.getLevel(), log));
}
public static ScalarToGroup.Config<LogEvent, String, LogEvent> config(){
return new ScalarToGroup.Config<LogEvent, String, LogEvent>()
.description("Group event data by level")
.codec(JacksonCodecs.pojo(LogEvent.class))
.concurrentInput();
}
}

View File

@ -0,0 +1,24 @@
package com.baeldung.netflix.mantis.stage;
import com.baeldung.netflix.mantis.model.LogEvent;
import io.mantisrx.runtime.Context;
import io.mantisrx.runtime.ScalarToScalar;
import io.mantisrx.runtime.codec.JacksonCodecs;
import io.mantisrx.runtime.computation.ScalarComputation;
import rx.Observable;
public class TransformLogStage implements ScalarComputation<String, LogEvent> {
@Override
public Observable<LogEvent> call(Context context, Observable<String> logEntry) {
return logEntry
.map(log -> log.split("#"))
.filter(parts -> parts.length == 3)
.map(LogEvent::new);
}
public static ScalarToScalar.Config<String, LogEvent> stageConfig() {
return new ScalarToScalar.Config<String, LogEvent>()
.codec(JacksonCodecs.pojo(LogEvent.class));
}
}

View File

@ -0,0 +1,56 @@
package com.baeldung.netflix.mantis.job;
import com.baeldung.netflix.mantis.model.LogAggregate;
import io.mantisrx.runtime.PortRequest;
import io.mantisrx.runtime.sink.Sinks;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import static java.util.Arrays.asList;
import static java.util.Optional.of;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
class LogAggregationJobIntegrationTest extends MantisJobTestBase<LogAggregate> {
private final static int PORT = 7382;
private final static String SINK_URL = "http://localhost:" + PORT;
@BeforeAll
static void beforeAll() {
start(new LogAggregationJob((context, portRequest, logAggregateObservable) -> {
logAggregateObservable.subscribe();
Sinks.sse(LogAggregate::toJsonString).call(context, new PortRequest(PORT), logAggregateObservable);
}));
}
@Override
public String getSinkUrl() {
return SINK_URL;
}
@Override
public Class<LogAggregate> getEventType() {
return LogAggregate.class;
}
@Test
void whenReadingFromSink_thenShouldRetrieveCorrectNumberOfLogAggregates() {
assertEquals(of(5L), sinkStream.take(5).count().blockOptional());
}
@Test
void whenReadingFromSink_thenShouldRetrieveLogAggregate() {
assertNotNull(sinkStream.take(1).blockFirst());
}
@Test
void whenReadingFromSink_thenShouldRetrieveValidLogAggregate() {
LogAggregate logAggregate = sinkStream.take(1).blockFirst();
assertTrue(asList("ERROR", "WARN", "INFO").contains(logAggregate.getLevel()));
assertTrue(logAggregate.getCount() > 0);
}
}

View File

@ -0,0 +1,73 @@
package com.baeldung.netflix.mantis.job;
import com.baeldung.netflix.mantis.model.LogEvent;
import com.baeldung.netflix.mantis.sink.LogSink;
import io.mantisrx.runtime.Context;
import io.mantisrx.runtime.PortRequest;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import rx.Observable;
import static java.util.Arrays.asList;
import static java.util.Optional.of;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
class LogCollectingJobIntegrationTest extends MantisJobTestBase<LogEvent> {
private final static int PORT = 7381;
private final static String SINK_URL = "http://localhost:" + PORT;
@BeforeAll
static void beforeAll() {
start(new LogCollectingJob(new LogSink() {
@Override
public void call(Context context, PortRequest portRequest, Observable<LogEvent> observable) {
super.call(context, new PortRequest(PORT), observable);
}
}));
}
@Override
public String getSinkUrl() {
return SINK_URL;
}
@Override
public Class<LogEvent> getEventType() {
return LogEvent.class;
}
@Test
void whenReadingFromSink_thenShouldRetrieveCorrectNumberOfLogEvents() {
assertEquals(of(5L), sinkStream.take(5).count().blockOptional());
}
@Test
void whenReadingFromSink_thenShouldRetrieveLogEvent() {
assertNotNull(sinkStream.take(1).blockFirst());
}
@Test
void whenReadingFromSink_thenShouldRetrieveValidLogEvent() {
LogEvent logEvent = sinkStream.take(1).blockFirst();
assertTrue(asList("ERROR", "WARN", "INFO").contains(logEvent.getLevel()));
assertTrue(asList("login attempt", "user created").contains(logEvent.getMessage()));
}
@Test
void whenReadingFromSink_thenShouldRetrieveFilteredLogEvents() {
getSinkStream(SINK_URL + "?filter=login")
.take(7)
.toStream().forEach(
logEvent -> assertEquals("login attempt", logEvent.getMessage())
);
}
}

View File

@ -0,0 +1,49 @@
package com.baeldung.netflix.mantis.job;
import io.mantisrx.runtime.Job;
import io.mantisrx.runtime.MantisJobProvider;
import io.mantisrx.runtime.executor.LocalJobExecutorNetworked;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeEach;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Flux;
import reactor.util.retry.Retry;
import java.time.Duration;
public abstract class MantisJobTestBase<T> {
private static Job jobInstance;
Flux<T> sinkStream;
public abstract String getSinkUrl();
public abstract Class<T> getEventType();
@BeforeEach
void setUp() {
sinkStream = getSinkStream(getSinkUrl());
}
@AfterAll
static void afterAll() {
stopJob();
}
protected Flux<T> getSinkStream(String sinkUrl) {
return WebClient.builder().build().get()
.uri(sinkUrl)
.retrieve()
.bodyToFlux(getEventType())
.retryWhen(Retry.fixedDelay(10, Duration.ofMillis(2000)));
}
static <T> void start(MantisJobProvider<T> job) {
jobInstance = job.getJobInstance();
new Thread(() -> LocalJobExecutorNetworked.execute(jobInstance)).start();
}
static void stopJob() {
jobInstance.getLifecycle().shutdown();
}
}

View File

@ -15,6 +15,7 @@
<modules> <modules>
<module>genie</module> <module>genie</module>
<module>mantis</module>
</modules> </modules>
</project> </project>

View File

@ -0,0 +1,3 @@
### Relevant Articles:
- [Getting Database URL From JDBC Connection Object](https://www.baeldung.com/jdbc-get-url-from-connection)

View File

@ -0,0 +1,29 @@
<?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">
<modelVersion>4.0.0</modelVersion>
<groupId>com.baeldung.core-java-persistence-2</groupId>
<artifactId>core-java-persistence-2</artifactId>
<version>0.1.0-SNAPSHOT</version>
<name>core-java-persistence-2</name>
<packaging>jar</packaging>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>persistence-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>${h2.version}</version>
</dependency>
</dependencies>
<properties>
<h2.version>1.4.200</h2.version>
</properties>
</project>

View File

@ -0,0 +1,13 @@
package com.baeldung.getdburl;
import java.sql.Connection;
import java.sql.DriverManager;
public class DBConfiguration {
public static Connection getConnection() throws Exception {
Class.forName("org.h2.Driver");
String url = "jdbc:h2:mem:testdb";
return DriverManager.getConnection(url, "user", "password");
}
}

View File

@ -0,0 +1,18 @@
package com.baeldung.getdburl;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.sql.Connection;
import org.junit.jupiter.api.Test;
class DBConfigurationUnitTest {
@Test
void givenConnectionObject_whenExtractMetaData_thenGetDbURL() throws Exception {
Connection connection = DBConfiguration.getConnection();
String dbUrl = connection.getMetaData().getURL();
assertEquals("jdbc:h2:mem:testdb", dbUrl);
}
}

View File

@ -76,10 +76,6 @@
<properties> <properties>
<flyway.configFiles>src/main/resources/application-${spring-boot.run.profiles}.properties</flyway.configFiles> <flyway.configFiles>src/main/resources/application-${spring-boot.run.profiles}.properties</flyway.configFiles>
<!-- testing -->
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
<junit-jupiter.version>5.6.2</junit-jupiter.version>
<junit.version>4.13</junit.version>
</properties> </properties>
</project> </project>

View File

@ -66,10 +66,6 @@
<flyway-core.version>5.2.3</flyway-core.version> <flyway-core.version>5.2.3</flyway-core.version>
<flyway-maven-plugin.version>5.0.2</flyway-maven-plugin.version> <flyway-maven-plugin.version>5.0.2</flyway-maven-plugin.version>
<!-- testing -->
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
<junit-jupiter.version>5.6.2</junit-jupiter.version>
<junit.version>4.13</junit.version>
</properties> </properties>
</project> </project>

View File

@ -8,7 +8,7 @@ public class Application {
public static void main(String[] args) { public static void main(String[] args) {
EntityManager entityManager = getJpaEntityManager(); EntityManager entityManager = getJpaEntityManager();
User user = entityManager.find(User.class, 1); User user = entityManager.find(User.class, 1l);
System.out.println(user); System.out.println(user);
entityManager.getTransaction().begin(); entityManager.getTransaction().begin();
user.setName("John"); user.setName("John");

View File

@ -1,9 +1,9 @@
package com.baeldung.hibernate.onetoone.sharedkeybased; package com.baeldung.hibernate.onetoone.sharedkeybased;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.Id; import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.MapsId; import javax.persistence.MapsId;
import javax.persistence.OneToOne; import javax.persistence.OneToOne;
import javax.persistence.Table; import javax.persistence.Table;
@ -13,7 +13,7 @@ import javax.persistence.Table;
public class Address { public class Address {
@Id @Id
@Column(name = "id") @Column(name = "user_id")
private Long id; private Long id;
@Column(name = "street") @Column(name = "street")
@ -24,6 +24,7 @@ public class Address {
@OneToOne @OneToOne
@MapsId @MapsId
@JoinColumn(name = "user_id")
private User user; private User user;
public Long getId() { public Long getId() {

View File

@ -8,6 +8,7 @@ import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType; import javax.persistence.GenerationType;
import javax.persistence.Id; import javax.persistence.Id;
import javax.persistence.OneToOne; import javax.persistence.OneToOne;
import javax.persistence.PrimaryKeyJoinColumn;
import javax.persistence.Table; import javax.persistence.Table;
@Entity @Entity
@ -22,6 +23,7 @@ public class User {
private String userName; private String userName;
@OneToOne(mappedBy = "user", cascade = CascadeType.ALL) @OneToOne(mappedBy = "user", cascade = CascadeType.ALL)
@PrimaryKeyJoinColumn
private Address address; private Address address;
public Long getId() { public Long getId() {

View File

@ -17,6 +17,7 @@
<module>apache-bookkeeper</module><!-- BAEL-2322 --> <module>apache-bookkeeper</module><!-- BAEL-2322 -->
<module>apache-cayenne</module> <module>apache-cayenne</module>
<module>core-java-persistence</module> <module>core-java-persistence</module>
<module>core-java-persistence-2</module>
<module>deltaspike</module> <module>deltaspike</module>
<module>elasticsearch</module> <module>elasticsearch</module>
<module>flyway</module> <module>flyway</module>

View File

@ -69,10 +69,6 @@
<r2dbc-h2.version>0.8.1.RELEASE</r2dbc-h2.version> <r2dbc-h2.version>0.8.1.RELEASE</r2dbc-h2.version>
<h2.version>1.4.200</h2.version> <h2.version>1.4.200</h2.version>
<!-- testing -->
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
<junit-jupiter.version>5.6.2</junit-jupiter.version>
<junit.version>4.13</junit.version>
</properties> </properties>
</project> </project>

View File

@ -62,10 +62,6 @@
<jedis.version>3.3.0</jedis.version> <jedis.version>3.3.0</jedis.version>
<epoll.version>4.1.50.Final</epoll.version> <epoll.version>4.1.50.Final</epoll.version>
<!-- testing -->
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
<junit-jupiter.version>5.6.2</junit-jupiter.version>
<junit.version>4.13</junit.version>
</properties> </properties>
</project> </project>

View File

@ -40,10 +40,6 @@
<properties> <properties>
<mysql-connector-java.version>8.0.12</mysql-connector-java.version> <mysql-connector-java.version>8.0.12</mysql-connector-java.version>
<!-- testing -->
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
<junit-jupiter.version>5.6.2</junit-jupiter.version>
<junit.version>4.13</junit.version>
</properties> </properties>
</project> </project>

View File

@ -5,4 +5,5 @@
- [Integrating Spring Boot with HSQLDB](https://www.baeldung.com/spring-boot-hsqldb) - [Integrating Spring Boot with HSQLDB](https://www.baeldung.com/spring-boot-hsqldb)
- [List of In-Memory Databases](https://www.baeldung.com/java-in-memory-databases) - [List of In-Memory Databases](https://www.baeldung.com/java-in-memory-databases)
- [Oracle Connection Pooling With Spring](https://www.baeldung.com/spring-oracle-connection-pooling) - [Oracle Connection Pooling With Spring](https://www.baeldung.com/spring-oracle-connection-pooling)
- [Object States in Hibernates Session](https://www.baeldung.com/hibernate-session-object-states)
- More articles: [[<-- prev]](../spring-boot-persistence) - More articles: [[<-- prev]](../spring-boot-persistence)

View File

@ -47,10 +47,6 @@
<start-class>com.baeldung.h2db.demo.server.SpringBootApp</start-class> <start-class>com.baeldung.h2db.demo.server.SpringBootApp</start-class>
<db-util.version>1.0.4</db-util.version> <db-util.version>1.0.4</db-util.version>
<!-- testing -->
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
<junit-jupiter.version>5.6.2</junit-jupiter.version>
<junit.version>4.13</junit.version>
</properties> </properties>
</project> </project>

View File

@ -37,9 +37,5 @@
</dependencies> </dependencies>
<properties> <properties>
<!-- testing -->
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
<junit-jupiter.version>5.6.2</junit-jupiter.version>
<junit.version>4.13</junit.version>
</properties> </properties>
</project> </project>

View File

@ -76,11 +76,6 @@
<properties> <properties>
<mockito.version>2.23.0</mockito.version> <mockito.version>2.23.0</mockito.version>
<validation-api.version>2.0.1.Final</validation-api.version> <validation-api.version>2.0.1.Final</validation-api.version>
<!-- testing -->
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
<junit-jupiter.version>5.6.2</junit-jupiter.version>
<junit.version>4.13</junit.version>
</properties> </properties>
</project> </project>

View File

@ -54,10 +54,6 @@
<spring-boot.version>2.2.6.RELEASE</spring-boot.version> <spring-boot.version>2.2.6.RELEASE</spring-boot.version>
<cassandra-unit-spring.version>3.11.2.0</cassandra-unit-spring.version> <cassandra-unit-spring.version>3.11.2.0</cassandra-unit-spring.version>
<!-- testing -->
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
<junit-jupiter.version>5.6.2</junit-jupiter.version>
<junit.version>4.13</junit.version>
</properties> </properties>
</project> </project>

View File

@ -105,10 +105,6 @@
<cassandra-unit-shaded.version>2.1.9.2</cassandra-unit-shaded.version> <cassandra-unit-shaded.version>2.1.9.2</cassandra-unit-shaded.version>
<hector-core.version>2.0-0</hector-core.version> <hector-core.version>2.0-0</hector-core.version>
<!-- testing -->
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
<junit-jupiter.version>5.6.2</junit-jupiter.version>
<junit.version>4.13</junit.version>
</properties> </properties>
</project> </project>

View File

@ -17,10 +17,6 @@
<java.version>1.8</java.version> <java.version>1.8</java.version>
<cosmodb.version>2.3.0</cosmodb.version> <cosmodb.version>2.3.0</cosmodb.version>
<!-- testing -->
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
<junit-jupiter.version>5.6.2</junit-jupiter.version>
<junit.version>4.13</junit.version>
</properties> </properties>
<dependencies> <dependencies>

View File

@ -182,11 +182,6 @@
<dynamodblocal.version>1.11.86</dynamodblocal.version> <dynamodblocal.version>1.11.86</dynamodblocal.version>
<dynamodblocal.repository.url>https://s3-us-west-2.amazonaws.com/dynamodb-local/release</dynamodblocal.repository.url> <dynamodblocal.repository.url>https://s3-us-west-2.amazonaws.com/dynamodb-local/release</dynamodblocal.repository.url>
<maven-dependency-plugin.version>3.1.1</maven-dependency-plugin.version> <maven-dependency-plugin.version>3.1.1</maven-dependency-plugin.version>
<!-- testing -->
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
<junit-jupiter.version>5.6.2</junit-jupiter.version>
<junit.version>4.13</junit.version>
</properties> </properties>
</project> </project>

View File

@ -69,10 +69,5 @@
<fastjson.version>1.2.47</fastjson.version> <fastjson.version>1.2.47</fastjson.version>
<spatial4j.version>0.7</spatial4j.version> <spatial4j.version>0.7</spatial4j.version>
<jts.version>1.15.0</jts.version> <jts.version>1.15.0</jts.version>
<!-- testing -->
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
<junit-jupiter.version>5.6.2</junit-jupiter.version>
<junit.version>4.13</junit.version>
</properties> </properties>
</project> </project>

View File

@ -28,9 +28,5 @@
</dependencies> </dependencies>
<properties> <properties>
<!-- testing -->
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
<junit-jupiter.version>5.6.2</junit-jupiter.version>
<junit.version>4.13</junit.version>
</properties> </properties>
</project> </project>

View File

@ -73,10 +73,6 @@
<postgresql.version>42.2.5</postgresql.version> <postgresql.version>42.2.5</postgresql.version>
<guava.version>21.0</guava.version> <guava.version>21.0</guava.version>
<!-- testing -->
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
<junit-jupiter.version>5.6.2</junit-jupiter.version>
<junit.version>4.13</junit.version>
</properties> </properties>
</project> </project>

View File

@ -16,10 +16,6 @@
<dependencies> <dependencies>
<!-- Prod Dependencies --> <!-- Prod Dependencies -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId> <artifactId>spring-boot-starter-data-jpa</artifactId>
@ -66,11 +62,6 @@
<datasource-proxy.version>1.4.1</datasource-proxy.version> <datasource-proxy.version>1.4.1</datasource-proxy.version>
<guava.version>21.0</guava.version> <guava.version>21.0</guava.version>
<testcontainers.version>1.12.2</testcontainers.version> <testcontainers.version>1.12.2</testcontainers.version>
<!-- testing -->
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
<junit-jupiter.version>5.6.2</junit-jupiter.version>
<junit.version>4.13</junit.version>
</properties> </properties>
</project> </project>

View File

@ -99,10 +99,6 @@
<guava.version>21.0</guava.version> <guava.version>21.0</guava.version>
<testcontainers.version>1.12.2</testcontainers.version> <testcontainers.version>1.12.2</testcontainers.version>
<!-- testing -->
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
<junit-jupiter.version>5.6.2</junit-jupiter.version>
<junit.version>4.13</junit.version>
</properties> </properties>
</project> </project>

View File

@ -73,10 +73,6 @@
<postgresql.version>42.2.5</postgresql.version> <postgresql.version>42.2.5</postgresql.version>
<guava.version>21.0</guava.version> <guava.version>21.0</guava.version>
<!-- testing -->
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
<junit-jupiter.version>5.6.2</junit-jupiter.version>
<junit.version>4.13</junit.version>
</properties> </properties>
</project> </project>

View File

@ -84,10 +84,6 @@
</dependencies> </dependencies>
<properties> <properties>
<!-- testing -->
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
<junit-jupiter.version>5.6.2</junit-jupiter.version>
<junit.version>4.13</junit.version>
<tomcat-dbcp.version>9.0.0.M26</tomcat-dbcp.version> <tomcat-dbcp.version>9.0.0.M26</tomcat-dbcp.version>
<jta.version>1.1</jta.version> <jta.version>1.1</jta.version>
<guava.version>21.0</guava.version> <guava.version>21.0</guava.version>

View File

@ -44,10 +44,6 @@
<properties> <properties>
<datasource-proxy.version>1.4.1</datasource-proxy.version> <datasource-proxy.version>1.4.1</datasource-proxy.version>
<!-- testing -->
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
<junit-jupiter.version>5.6.2</junit-jupiter.version>
<junit.version>4.13</junit.version>
</properties> </properties>
</project> </project>

View File

@ -44,9 +44,5 @@
<properties> <properties>
<guava.version>29.0-jre</guava.version> <guava.version>29.0-jre</guava.version>
<!-- testing -->
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
<junit-jupiter.version>5.6.2</junit-jupiter.version>
<junit.version>4.13</junit.version>
</properties> </properties>
</project> </project>

View File

@ -50,9 +50,6 @@
</dependencies> </dependencies>
<properties> <properties>
<!-- testing -->
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
<junit-jupiter.version>5.6.2</junit-jupiter.version>
<junit.version>4.13</junit.version>
</properties> </properties>
</project> </project>

View File

@ -29,9 +29,6 @@
</dependencies> </dependencies>
<properties> <properties>
<!-- testing -->
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
<junit-jupiter.version>5.6.2</junit-jupiter.version>
<junit.version>4.13</junit.version>
</properties> </properties>
</project> </project>

View File

@ -108,10 +108,6 @@
<projectreactor.version>3.2.0.RELEASE</projectreactor.version> <projectreactor.version>3.2.0.RELEASE</projectreactor.version>
<mongodb-driver.version>4.0.5</mongodb-driver.version> <mongodb-driver.version>4.0.5</mongodb-driver.version>
<!-- testing -->
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
<junit-jupiter.version>5.6.2</junit-jupiter.version>
<junit.version>4.13</junit.version>
</properties> </properties>
</project> </project>

View File

@ -98,11 +98,6 @@
<cglib.version>3.2.4</cglib.version> <cglib.version>3.2.4</cglib.version>
<nosqlunit.version>0.10.0</nosqlunit.version> <nosqlunit.version>0.10.0</nosqlunit.version>
<embedded-redis.version>0.6</embedded-redis.version> <embedded-redis.version>0.6</embedded-redis.version>
<!-- testing -->
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
<junit-jupiter.version>5.6.2</junit-jupiter.version>
<junit.version>4.13</junit.version>
</properties> </properties>
</project> </project>

View File

@ -5,7 +5,6 @@ import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource; import org.springframework.context.annotation.PropertySource;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.listener.ChannelTopic; import org.springframework.data.redis.listener.ChannelTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer; import org.springframework.data.redis.listener.RedisMessageListenerContainer;

View File

@ -1,16 +1,32 @@
package com.baeldung; package com.baeldung;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ContextConfiguration; import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.annotation.DirtiesContext.ClassMode;
import com.baeldung.spring.data.redis.config.RedisConfig; import com.baeldung.spring.data.redis.SpringRedisApplication;
@RunWith(SpringJUnit4ClassRunner.class) import redis.embedded.RedisServerBuilder;
@ContextConfiguration(classes = RedisConfig.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = SpringRedisApplication.class)
@DirtiesContext(classMode = ClassMode.BEFORE_CLASS)
public class SpringContextTest { public class SpringContextTest {
private static redis.embedded.RedisServer redisServer;
@BeforeClass
public static void startRedisServer() {
redisServer = new RedisServerBuilder().port(6379).setting("maxmemory 256M").build();
redisServer.start();
}
@AfterClass
public static void stopRedisServer() {
redisServer.stop();
}
@Test @Test
public void whenSpringContextIsBootstrapped_thenNoExceptions() { public void whenSpringContextIsBootstrapped_thenNoExceptions() {
} }

View File

@ -46,10 +46,6 @@
<properties> <properties>
<spring-data-solr.version>2.0.5.RELEASE</spring-data-solr.version> <spring-data-solr.version>2.0.5.RELEASE</spring-data-solr.version>
<!-- testing -->
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
<junit-jupiter.version>5.6.2</junit-jupiter.version>
<junit.version>4.13</junit.version>
</properties> </properties>
</project> </project>

View File

@ -18,7 +18,6 @@
<dependency> <dependency>
<groupId>org.springframework.data</groupId> <groupId>org.springframework.data</groupId>
<artifactId>spring-data-jdbc</artifactId> <artifactId>spring-data-jdbc</artifactId>
<version>${spring-data-jdbc.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
@ -36,11 +35,5 @@
</dependencies> </dependencies>
<properties> <properties>
<spring-data-jdbc.version>2.0.3.RELEASE</spring-data-jdbc.version>
<!-- testing -->
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
<junit-jupiter.version>5.6.2</junit-jupiter.version>
<junit.version>4.13</junit.version>
</properties> </properties>
</project> </project>

View File

@ -7,6 +7,7 @@
- [Transaction Propagation and Isolation in Spring @Transactional](https://www.baeldung.com/spring-transactional-propagation-isolation) - [Transaction Propagation and Isolation in Spring @Transactional](https://www.baeldung.com/spring-transactional-propagation-isolation)
- [JTA Transaction with Spring](https://www.baeldung.com/spring-vs-jta-transactional) - [JTA Transaction with Spring](https://www.baeldung.com/spring-vs-jta-transactional)
- [Test a Mock JNDI Datasource with Spring](https://www.baeldung.com/spring-mock-jndi-datasource) - [Test a Mock JNDI Datasource with Spring](https://www.baeldung.com/spring-mock-jndi-datasource)
- [Detecting If a Spring Transaction Is Active](https://www.baeldung.com/spring-transaction-active)
### Eclipse Config ### Eclipse Config
After importing the project into Eclipse, you may see the following error: After importing the project into Eclipse, you may see the following error:

View File

@ -9,3 +9,4 @@ This module contains articles about Spring Boot annotations
- [Spring Web Annotations](https://www.baeldung.com/spring-mvc-annotations) - [Spring Web Annotations](https://www.baeldung.com/spring-mvc-annotations)
- [Spring Core Annotations](https://www.baeldung.com/spring-core-annotations) - [Spring Core Annotations](https://www.baeldung.com/spring-core-annotations)
- [Spring Bean Annotations](https://www.baeldung.com/spring-bean-annotations) - [Spring Bean Annotations](https://www.baeldung.com/spring-bean-annotations)
- [Difference Between @ComponentScan and @EnableAutoConfiguration in Spring Boot](https://www.baeldung.com/spring-componentscan-vs-enableautoconfiguration)

View File

@ -4,11 +4,12 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 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> <modelVersion>4.0.0</modelVersion>
<!-- this module should use the Boot parent directly to avoid inherit the logback dependency from our other parents -->
<parent> <parent>
<groupId>com.baeldung.spring-boot-modules</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-modules</artifactId> <artifactId>spring-boot-starter-parent</artifactId>
<version>1.0.0-SNAPSHOT</version> <version>2.1.1.RELEASE</version>
<relativePath>../</relativePath> <relativePath/> <!-- lookup parent from repository -->
</parent> </parent>
<artifactId>spring-boot-mvc-birt</artifactId> <artifactId>spring-boot-mvc-birt</artifactId>
@ -19,10 +20,6 @@
<description>Module For Spring Boot Integration with BIRT</description> <description>Module For Spring Boot Integration with BIRT</description>
<dependencies> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
@ -51,17 +48,14 @@
<artifactId>org.eclipse.birt.runtime_4.8.0-20180626</artifactId> <artifactId>org.eclipse.birt.runtime_4.8.0-20180626</artifactId>
<version>${eclipse.birt.runtime.version}</version> <version>${eclipse.birt.runtime.version}</version>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency> <dependency>
<groupId>log4j</groupId> <groupId>log4j</groupId>
<artifactId>log4j</artifactId> <artifactId>log4j</artifactId>
<version>${log4j.version}</version> <version>${log4j.version}</version>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency> <dependency>
<groupId>org.projectlombok</groupId> <groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId> <artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
@ -81,6 +75,7 @@
<maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target> <maven.compiler.target>1.8</maven.compiler.target>
<eclipse.birt.runtime.version>4.8.0</eclipse.birt.runtime.version> <eclipse.birt.runtime.version>4.8.0</eclipse.birt.runtime.version>
<log4j.version>1.2.17</log4j.version>
</properties> </properties>
</project> </project>

View File

@ -0,0 +1,9 @@
# Set root logger level to DEBUG and its only appender to A1.
log4j.rootLogger=DEBUG, A1
# A1 is set to be a ConsoleAppender.
log4j.appender.A1=org.apache.log4j.ConsoleAppender
# A1 uses PatternLayout.
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n

View File

@ -0,0 +1,13 @@
package com.baeldung.birt.engine;
import org.junit.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class SpringContextTest {
@Test
public void whenSpringContextIsBootstrapped_thenNoExceptions() {
}
}

View File

@ -2,6 +2,7 @@ package com.baeldung.cloud.openfeign.config;
import feign.Logger; import feign.Logger;
import feign.RequestInterceptor; import feign.RequestInterceptor;
import feign.auth.BasicAuthRequestInterceptor;
import feign.codec.ErrorDecoder; import feign.codec.ErrorDecoder;
import feign.okhttp.OkHttpClient; import feign.okhttp.OkHttpClient;
import org.apache.http.entity.ContentType; import org.apache.http.entity.ContentType;
@ -34,4 +35,9 @@ public class ClientConfiguration {
requestTemplate.header("Accept", ContentType.APPLICATION_JSON.getMimeType()); requestTemplate.header("Accept", ContentType.APPLICATION_JSON.getMimeType());
}; };
} }
// @Bean - uncomment to use this interceptor and remove @Bean from the requestInterceptor()
public BasicAuthRequestInterceptor basicAuthRequestInterceptor() {
return new BasicAuthRequestInterceptor("ajeje", "brazof");
}
} }

View File

@ -226,7 +226,7 @@
<httpcore.version>4.4.9</httpcore.version> <httpcore.version>4.4.9</httpcore.version>
<httpclient.version>4.5.5</httpclient.version> <httpclient.version>4.5.5</httpclient.version>
<javax.servlet-api.version>4.0.0</javax.servlet-api.version> <javax.servlet-api.version>4.0.0</javax.servlet-api.version>
<wiremock.version>2.25.1</wiremock.version> <wiremock.version>2.27.2</wiremock.version>
<assertj-core.version>3.10.0</assertj-core.version> <assertj-core.version>3.10.0</assertj-core.version>
<spring-boot.version>1.5.10.RELEASE</spring-boot.version> <spring-boot.version>1.5.10.RELEASE</spring-boot.version>
</properties> </properties>

View File

@ -206,7 +206,7 @@
<lifecycle-mapping.version>1.0.0</lifecycle-mapping.version> <lifecycle-mapping.version>1.0.0</lifecycle-mapping.version>
<sql-maven-plugin.version>1.5</sql-maven-plugin.version> <sql-maven-plugin.version>1.5</sql-maven-plugin.version>
<properties-maven-plugin.version>1.0.0</properties-maven-plugin.version> <properties-maven-plugin.version>1.0.0</properties-maven-plugin.version>
<start-class>org.jooq.example.spring.Application</start-class> <h2.version>1.4.198</h2.version>
</properties> </properties>
</project> </project>

View File

@ -119,7 +119,7 @@ public class EmailConfiguration {
@Bean @Bean
public ResourceBundleMessageSource emailMessageSource() { public ResourceBundleMessageSource emailMessageSource() {
final ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource(); final ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("/mailMessages"); messageSource.setBasename("mailMessages");
return messageSource; return messageSource;
} }

View File

@ -11,11 +11,7 @@ public class MaxSizeConstraintValidator implements ConstraintValidator<MaxSizeCo
@Override @Override
public boolean isValid(List<Movie> values, ConstraintValidatorContext context) { public boolean isValid(List<Movie> values, ConstraintValidatorContext context) {
boolean isValid = true; return values.size() <= 4;
if (values.size() > 4) {
isValid = false;
}
return isValid;
} }
} }

View File

@ -1,7 +1,6 @@
package com.baeldung.resttemplate; package com.baeldung.resttemplate;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication @SpringBootApplication

View File

@ -1,14 +0,0 @@
package com.baeldung.resttemplate.logging;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@EnableAutoConfiguration
public class RestTemplateConfigurationApplication {
public static void main(String[] args) {
SpringApplication.run(RestTemplateConfigurationApplication.class, args);
}
}

View File

@ -14,16 +14,18 @@ import org.springframework.http.client.ClientHttpResponse;
public class LoggingInterceptor implements ClientHttpRequestInterceptor { public class LoggingInterceptor implements ClientHttpRequestInterceptor {
final static Logger log = LoggerFactory.getLogger(LoggingInterceptor.class); final static Logger LOGGER = LoggerFactory.getLogger(LoggingInterceptor.class);
@Override @Override
public ClientHttpResponse intercept(HttpRequest req, byte[] reqBody, ClientHttpRequestExecution ex) throws IOException { public ClientHttpResponse intercept(HttpRequest req, byte[] reqBody, ClientHttpRequestExecution ex) throws IOException {
log.debug("Request body: {}", new String(reqBody, StandardCharsets.UTF_8)); LOGGER.debug("Request body: {}", new String(reqBody, StandardCharsets.UTF_8));
ClientHttpResponse response = ex.execute(req, reqBody); ClientHttpResponse response = ex.execute(req, reqBody);
InputStreamReader isr = new InputStreamReader(response.getBody(), StandardCharsets.UTF_8); if (LOGGER.isDebugEnabled()) {
String body = new BufferedReader(isr).lines() InputStreamReader isr = new InputStreamReader(response.getBody(), StandardCharsets.UTF_8);
.collect(Collectors.joining("\n")); String body = new BufferedReader(isr).lines()
log.debug("Response body: {}", body); .collect(Collectors.joining("\n"));
LOGGER.debug("Response body: {}", body);
}
return response; return response;
} }
} }

View File

@ -1,18 +1,21 @@
package com.baeldung.resttemplate.logging; package com.baeldung.resttemplate.logging;
import static org.hamcrest.CoreMatchers.equalTo; import static org.junit.Assert.assertEquals;
import static org.hamcrest.MatcherAssert.assertThat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.ClientHttpRequestInterceptor; import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.http.client.BufferingClientHttpRequestFactory;
import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
@ -22,6 +25,7 @@ import org.springframework.web.client.RestTemplate;
public class RestTemplateLoggingLiveTest { public class RestTemplateLoggingLiveTest {
private static final String baseUrl = "http://localhost:8080/spring-rest"; private static final String baseUrl = "http://localhost:8080/spring-rest";
private static final Logger LOGGER = LoggerFactory.getLogger(RestTemplateLoggingLiveTest.class);
@Test @Test
public void givenHttpClientConfiguration_whenSendGetForRequestEntity_thenRequestResponseFullLog() { public void givenHttpClientConfiguration_whenSendGetForRequestEntity_thenRequestResponseFullLog() {
@ -30,13 +34,22 @@ public class RestTemplateLoggingLiveTest {
restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory()); restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory());
final ResponseEntity<String> response = restTemplate.postForEntity(baseUrl + "/persons", "my request body", String.class); final ResponseEntity<String> response = restTemplate.postForEntity(baseUrl + "/persons", "my request body", String.class);
assertThat(response.getStatusCode(), equalTo(HttpStatus.OK)); assertEquals(HttpStatus.OK, response.getStatusCode());
assertEquals("[\"Lucie\",\"Jackie\",\"Danesh\",\"Tao\"]", response.getBody());
} }
@Test @Test
public void givenLoggingInterceptorConfiguration_whenSendGetForRequestEntity_thenRequestResponseCustomLog() { public void givenLoggingInterceptorConfiguration_whenSendGetForRequestEntity_thenRequestResponseCustomLog() {
RestTemplate restTemplate = new RestTemplate(); RestTemplate restTemplate = null;
if (LOGGER.isDebugEnabled()) {
ClientHttpRequestFactory factory = new BufferingClientHttpRequestFactory(
new SimpleClientHttpRequestFactory());
restTemplate = new RestTemplate(factory);
} else {
restTemplate = new RestTemplate();
}
List<ClientHttpRequestInterceptor> interceptors = restTemplate.getInterceptors(); List<ClientHttpRequestInterceptor> interceptors = restTemplate.getInterceptors();
if (CollectionUtils.isEmpty(interceptors)) { if (CollectionUtils.isEmpty(interceptors)) {
interceptors = new ArrayList<>(); interceptors = new ArrayList<>();
@ -45,6 +58,7 @@ public class RestTemplateLoggingLiveTest {
restTemplate.setInterceptors(interceptors); restTemplate.setInterceptors(interceptors);
final ResponseEntity<String> response = restTemplate.postForEntity(baseUrl + "/persons", "my request body", String.class); final ResponseEntity<String> response = restTemplate.postForEntity(baseUrl + "/persons", "my request body", String.class);
assertThat(response.getStatusCode(), equalTo(HttpStatus.OK)); assertEquals(HttpStatus.OK, response.getStatusCode());
assertEquals("[\"Lucie\",\"Jackie\",\"Danesh\",\"Tao\"]", response.getBody());
} }
} }

View File

@ -1,5 +1,5 @@
logging.level.org.springframework.web.client.RestTemplate=DEBUG logging.level.org.springframework.web.client.RestTemplate=DEBUG
logging.level.com.baeldung.resttemplate.logging.LoggingInterceptor=DEBUG logging.level.com.baeldung.resttemplate.logging=DEBUG
logging.level.org.apache.http=DEBUG logging.level.org.apache.http=DEBUG
logging.level.httpclient.wire=DEBUG logging.level.httpclient.wire=DEBUG
logging.pattern.console=%20logger{20} - %msg%n logging.pattern.console=%20logger{20} - %msg%n

View File

@ -28,6 +28,7 @@
<module>spring-security-web-login</module> <module>spring-security-web-login</module>
<module>spring-security-web-persisted-remember-me</module> <module>spring-security-web-persisted-remember-me</module>
<module>spring-security-web-sockets</module> <module>spring-security-web-sockets</module>
<module>spring-security-legacy-oidc</module>
<module>spring-security-oidc</module> <module>spring-security-oidc</module>
<module>spring-security-okta</module> <module>spring-security-okta</module>
<module>spring-security-web-react</module> <module>spring-security-web-react</module>

View File

@ -0,0 +1,23 @@
## Spring Security OpenID
This module contains articles about OpenID with Spring Security
### Relevant articles
- [Spring Security and OpenID Connect (Legacy)](https://www.baeldung.com/spring-security-openid-connect-legacy)
### OpenID Connect with Spring Security
### Run the Project
```
mvn spring-boot:run
```
### Obtain Google App - Client ID, Secret
- We need to get client id and client secret by creating a new project at [Google Developer Console](https://console.developers.google.com/project/_/apiui/credential?pli=1)
- We can follow these instructions to register our client application on their platform
- Once we have the client id and secret, we have to make sure we add them to the application.properties file.

View File

@ -0,0 +1,58 @@
<?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">
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-security-legacy-oidc</artifactId>
<name>spring-security-legacy-oidc</name>
<packaging>war</packaging>
<description>Spring OpenID Connect sample project</description>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-boot-2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../../parent-boot-2</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>${spring-security-oauth2.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-jwt</artifactId>
<version>${spring-security-jwt.version}</version>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>jwks-rsa</artifactId>
<version>${jwks-rsa.version}</version>
</dependency>
</dependencies>
<properties>
<spring-security-oauth2.version>2.2.1.RELEASE</spring-security-oauth2.version>
<spring-security-jwt.version>1.0.9.RELEASE</spring-security-jwt.version>
<jwks-rsa.version>0.3.0</jwks-rsa.version>
</properties>
</project>

View File

@ -0,0 +1,51 @@
package com.baeldung.openid.oidc;
import java.util.Arrays;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.client.OAuth2ClientContext;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableOAuth2Client;
@Configuration
@EnableOAuth2Client
public class GoogleOpenIdConnectConfig {
@Value("${google.clientId}")
private String clientId;
@Value("${google.clientSecret}")
private String clientSecret;
@Value("${google.accessTokenUri}")
private String accessTokenUri;
@Value("${google.userAuthorizationUri}")
private String userAuthorizationUri;
@Value("${google.redirectUri}")
private String redirectUri;
@Bean
public OAuth2ProtectedResourceDetails googleOpenId() {
final AuthorizationCodeResourceDetails details = new AuthorizationCodeResourceDetails();
details.setClientId(clientId);
details.setClientSecret(clientSecret);
details.setAccessTokenUri(accessTokenUri);
details.setUserAuthorizationUri(userAuthorizationUri);
details.setScope(Arrays.asList("openid", "email"));
details.setPreEstablishedRedirectUri(redirectUri);
details.setUseCurrentUri(false);
return details;
}
@Bean
public OAuth2RestTemplate googleOpenIdTemplate(final OAuth2ClientContext clientContext) {
final OAuth2RestTemplate template = new OAuth2RestTemplate(googleOpenId(), clientContext);
return template;
}
}

View File

@ -0,0 +1,22 @@
package com.baeldung.openid.oidc;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class HomeController {
private final Logger logger = LoggerFactory.getLogger(getClass());
@RequestMapping("/")
@ResponseBody
public final String home() {
final String username = SecurityContextHolder.getContext().getAuthentication().getName();
logger.info(username);
return "Welcome, " + username;
}
}

View File

@ -0,0 +1,103 @@
package com.baeldung.openid.oidc;
import java.io.IOException;
import java.net.URL;
import java.security.interfaces.RSAPublicKey;
import java.util.Date;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.jwt.Jwt;
import org.springframework.security.jwt.JwtHelper;
import org.springframework.security.jwt.crypto.sign.RsaVerifier;
import org.springframework.security.oauth2.client.OAuth2RestOperations;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import com.auth0.jwk.Jwk;
import com.auth0.jwk.JwkProvider;
import com.auth0.jwk.UrlJwkProvider;
import com.fasterxml.jackson.databind.ObjectMapper;
public class OpenIdConnectFilter extends AbstractAuthenticationProcessingFilter {
@Value("${google.clientId}")
private String clientId;
@Value("${google.issuer}")
private String issuer;
@Value("${google.jwkUrl}")
private String jwkUrl;
public OAuth2RestOperations restTemplate;
public OpenIdConnectFilter(String defaultFilterProcessesUrl) {
super(defaultFilterProcessesUrl);
setAuthenticationManager(new NoopAuthenticationManager());
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
OAuth2AccessToken accessToken;
try {
accessToken = restTemplate.getAccessToken();
} catch (final OAuth2Exception e) {
throw new BadCredentialsException("Could not obtain access token", e);
}
try {
final String idToken = accessToken.getAdditionalInformation().get("id_token").toString();
String kid = JwtHelper.headers(idToken)
.get("kid");
final Jwt tokenDecoded = JwtHelper.decodeAndVerify(idToken, verifier(kid));
final Map<String, String> authInfo = new ObjectMapper().readValue(tokenDecoded.getClaims(), Map.class);
verifyClaims(authInfo);
final OpenIdConnectUserDetails user = new OpenIdConnectUserDetails(authInfo, accessToken);
return new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());
} catch (final Exception e) {
throw new BadCredentialsException("Could not obtain user details from token", e);
}
}
public void verifyClaims(Map claims) {
int exp = (int) claims.get("exp");
Date expireDate = new Date(exp * 1000L);
Date now = new Date();
if (expireDate.before(now) || !claims.get("iss").equals(issuer) || !claims.get("aud").equals(clientId)) {
throw new RuntimeException("Invalid claims");
}
}
private RsaVerifier verifier(String kid) throws Exception {
JwkProvider provider = new UrlJwkProvider(new URL(jwkUrl));
Jwk jwk = provider.get(kid);
return new RsaVerifier((RSAPublicKey) jwk.getPublicKey());
}
public void setRestTemplate(OAuth2RestTemplate restTemplate2) {
restTemplate = restTemplate2;
}
private static class NoopAuthenticationManager implements AuthenticationManager {
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
throw new UnsupportedOperationException("No authentication should be done with this AuthenticationManager");
}
}
}

View File

@ -0,0 +1,81 @@
package com.baeldung.openid.oidc;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
public class OpenIdConnectUserDetails implements UserDetails {
private static final long serialVersionUID = 1L;
private String userId;
private String username;
private OAuth2AccessToken token;
public OpenIdConnectUserDetails(Map<String, String> userInfo, OAuth2AccessToken token) {
this.userId = userInfo.get("sub");
this.username = userInfo.get("email");
this.token = token;
}
@Override
public String getUsername() {
return username;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return Arrays.asList(new SimpleGrantedAuthority("ROLE_USER"));
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public OAuth2AccessToken getToken() {
return token;
}
public void setToken(OAuth2AccessToken token) {
this.token = token;
}
public void setUsername(String username) {
this.username = username;
}
@Override
public String getPassword() {
return null;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}

Some files were not shown because too many files have changed in this diff Show More