Merge branch 'master' into study-groovy
This commit is contained in:
commit
dd1613669e
|
@ -72,6 +72,13 @@ Building a single module
|
||||||
To build a specific module, run the command: `mvn clean install` in the module directory.
|
To build a specific module, run the command: `mvn clean install` in the module directory.
|
||||||
|
|
||||||
|
|
||||||
|
Building modules from the root of the repository
|
||||||
|
====================
|
||||||
|
To build specific modules from the root of the repository, run the command: `mvn clean install --pl asm,atomikos -Pdefault-first` in the root directory.
|
||||||
|
|
||||||
|
Here `asm` and `atomikos` are the modules that we want to build and `default-first` is the maven profile in which these modules are present.
|
||||||
|
|
||||||
|
|
||||||
Running a Spring Boot module
|
Running a Spring Boot module
|
||||||
====================
|
====================
|
||||||
To run a Spring Boot module, run the command: `mvn spring-boot:run` in the module directory.
|
To run a Spring Boot module, run the command: `mvn spring-boot:run` in the module directory.
|
||||||
|
|
|
@ -1,36 +1,41 @@
|
||||||
package com.baeldung.httpclient.cookies;
|
package com.baeldung.httpclient.cookies;
|
||||||
|
|
||||||
import org.apache.http.client.CookieStore;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
|
||||||
import org.apache.http.client.methods.HttpGet;
|
import org.apache.hc.client5.http.classic.methods.HttpGet;
|
||||||
import org.apache.http.client.protocol.HttpClientContext;
|
import org.apache.hc.client5.http.cookie.BasicCookieStore;
|
||||||
import org.apache.http.cookie.ClientCookie;
|
import org.apache.hc.client5.http.cookie.Cookie;
|
||||||
import org.apache.http.cookie.Cookie;
|
import org.apache.hc.client5.http.cookie.CookieStore;
|
||||||
import org.apache.http.impl.client.BasicCookieStore;
|
|
||||||
import org.apache.http.impl.client.CloseableHttpClient;
|
import org.apache.hc.client5.http.impl.classic.BasicHttpClientResponseHandler;
|
||||||
import org.apache.http.impl.client.HttpClients;
|
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
|
||||||
import org.apache.http.impl.cookie.BasicClientCookie;
|
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
|
||||||
|
|
||||||
|
import org.apache.hc.client5.http.impl.cookie.BasicClientCookie;
|
||||||
|
import org.apache.hc.client5.http.protocol.HttpClientContext;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
class HttpClientGettingCookieValueUnitTest {
|
||||||
|
|
||||||
|
|
||||||
public class HttpClientGettingCookieValueUnitTest {
|
|
||||||
private static Logger log = LoggerFactory.getLogger(HttpClientGettingCookieValueUnitTest.class);
|
private static Logger log = LoggerFactory.getLogger(HttpClientGettingCookieValueUnitTest.class);
|
||||||
|
|
||||||
private static final String SAMPLE_URL = "http://www.baeldung.com/";
|
private static final String SAMPLE_URL = "http://www.baeldung.com/";
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public final void whenSettingCustomCookieOnTheRequest_thenGettingTheSameCookieFromTheResponse() throws IOException {
|
void whenSettingCustomCookieOnTheRequest_thenGettingTheSameCookieFromTheResponse() throws IOException {
|
||||||
|
|
||||||
HttpClientContext context = HttpClientContext.create();
|
HttpClientContext context = HttpClientContext.create();
|
||||||
context.setAttribute(HttpClientContext.COOKIE_STORE, createCustomCookieStore());
|
context.setAttribute(HttpClientContext.COOKIE_STORE, createCustomCookieStore());
|
||||||
|
|
||||||
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
|
final HttpGet request = new HttpGet(SAMPLE_URL);
|
||||||
try (CloseableHttpResponse response = httpClient.execute(new HttpGet(SAMPLE_URL), context)) {
|
|
||||||
|
try (CloseableHttpClient client = HttpClientBuilder.create()
|
||||||
|
.build()) {
|
||||||
|
client.execute(request, context, new BasicHttpClientResponseHandler());
|
||||||
CookieStore cookieStore = context.getCookieStore();
|
CookieStore cookieStore = context.getCookieStore();
|
||||||
Cookie customCookie = cookieStore.getCookies()
|
Cookie customCookie = cookieStore.getCookies()
|
||||||
.stream()
|
.stream()
|
||||||
|
@ -42,13 +47,12 @@ public class HttpClientGettingCookieValueUnitTest {
|
||||||
assertEquals("test_value", customCookie.getValue());
|
assertEquals("test_value", customCookie.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private BasicCookieStore createCustomCookieStore() {
|
private BasicCookieStore createCustomCookieStore() {
|
||||||
BasicCookieStore cookieStore = new BasicCookieStore();
|
BasicCookieStore cookieStore = new BasicCookieStore();
|
||||||
BasicClientCookie cookie = new BasicClientCookie("custom_cookie", "test_value");
|
BasicClientCookie cookie = new BasicClientCookie("custom_cookie", "test_value");
|
||||||
cookie.setDomain("baeldung.com");
|
cookie.setDomain("baeldung.com");
|
||||||
cookie.setAttribute(ClientCookie.DOMAIN_ATTR, "true");
|
cookie.setAttribute("domain", "true");
|
||||||
cookie.setPath("/");
|
cookie.setPath("/");
|
||||||
cookieStore.addCookie(cookie);
|
cookieStore.addCookie(cookie);
|
||||||
return cookieStore;
|
return cookieStore;
|
||||||
|
|
|
@ -11,4 +11,5 @@ This module contains articles about Java 8 core features
|
||||||
- [Finding Min/Max in an Array with Java](https://www.baeldung.com/java-array-min-max)
|
- [Finding Min/Max in an Array with Java](https://www.baeldung.com/java-array-min-max)
|
||||||
- [Internationalization and Localization in Java 8](https://www.baeldung.com/java-8-localization)
|
- [Internationalization and Localization in Java 8](https://www.baeldung.com/java-8-localization)
|
||||||
- [Generalized Target-Type Inference in Java](https://www.baeldung.com/java-generalized-target-type-inference)
|
- [Generalized Target-Type Inference in Java](https://www.baeldung.com/java-generalized-target-type-inference)
|
||||||
|
- [Monads in Java](https://www.baeldung.com/java-monads)
|
||||||
- [[More -->]](/core-java-modules/core-java-8-2)
|
- [[More -->]](/core-java-modules/core-java-8-2)
|
||||||
|
|
|
@ -28,30 +28,16 @@ class MonadSample1 extends MonadBaseExample {
|
||||||
public double apply(double n) {
|
public double apply(double n) {
|
||||||
return subtract1(add3(divideBy2(multiplyBy2(multiplyBy2(2)))));
|
return subtract1(add3(divideBy2(multiplyBy2(multiplyBy2(2)))));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
final MonadSample1 test = new MonadSample1();
|
|
||||||
System.out.println(test.apply(2));
|
|
||||||
//6.0
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class MonadSample2 extends MonadBaseExample {
|
class MonadSample2 extends MonadBaseExample {
|
||||||
public double apply(double n) {
|
public double apply(double n) {
|
||||||
final double n1 = multiplyBy2(n);
|
double n1 = multiplyBy2(n);
|
||||||
final double n2 = multiplyBy2(n1);
|
double n2 = multiplyBy2(n1);
|
||||||
final double n3 = divideBy2(n2);
|
double n3 = divideBy2(n2);
|
||||||
final double n4 = add3(n3);
|
double n4 = add3(n3);
|
||||||
return subtract1(n4);
|
return subtract1(n4);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
final MonadSample2 test = new MonadSample2();
|
|
||||||
System.out.println(test.apply(2));
|
|
||||||
//6.0
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class MonadSample3 extends MonadBaseExample {
|
class MonadSample3 extends MonadBaseExample {
|
||||||
|
@ -66,11 +52,6 @@ class MonadSample3 extends MonadBaseExample {
|
||||||
.get();
|
.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
final MonadSample3 test = new MonadSample3();
|
|
||||||
System.out.println(test.apply(2));
|
|
||||||
//6.0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class MonadSample4 extends MonadBaseExample {
|
class MonadSample4 extends MonadBaseExample {
|
||||||
|
@ -90,13 +71,6 @@ class MonadSample3 extends MonadBaseExample {
|
||||||
return leftSide.equals(rightSide);
|
return leftSide.equals(rightSide);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
final MonadSample4 test = new MonadSample4();
|
|
||||||
|
|
||||||
System.out.println(test.leftIdentity()); //true
|
|
||||||
System.out.println(test.rightIdentity()); //true
|
|
||||||
System.out.println(test.associativity()); //true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class MonadSample5 extends MonadBaseExample {
|
class MonadSample5 extends MonadBaseExample {
|
||||||
|
@ -104,10 +78,5 @@ class MonadSample5 extends MonadBaseExample {
|
||||||
Function<Integer, Optional<Integer>> mapping = value -> Optional.of(value == null ? -1 : value + 1);
|
Function<Integer, Optional<Integer>> mapping = value -> Optional.of(value == null ? -1 : value + 1);
|
||||||
return Optional.ofNullable((Integer) null).flatMap(mapping).equals(mapping.apply(null));
|
return Optional.ofNullable((Integer) null).flatMap(mapping).equals(mapping.apply(null));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
final MonadSample5 test = new MonadSample5();
|
|
||||||
System.out.println(test.fail());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,3 +9,6 @@ This module contains articles about the Java ArrayList collection
|
||||||
- [Multi Dimensional ArrayList in Java](https://www.baeldung.com/java-multi-dimensional-arraylist)
|
- [Multi Dimensional ArrayList in Java](https://www.baeldung.com/java-multi-dimensional-arraylist)
|
||||||
- [Removing an Element From an ArrayList](https://www.baeldung.com/java-arraylist-remove-element)
|
- [Removing an Element From an ArrayList](https://www.baeldung.com/java-arraylist-remove-element)
|
||||||
- [The Capacity of an ArrayList vs the Size of an Array in Java](https://www.baeldung.com/java-list-capacity-array-size)
|
- [The Capacity of an ArrayList vs the Size of an Array in Java](https://www.baeldung.com/java-list-capacity-array-size)
|
||||||
|
- [Case-Insensitive Searching in ArrayList](https://www.baeldung.com/java-arraylist-case-insensitive-search)
|
||||||
|
- [Storing Data Triple in a List in Java](https://www.baeldung.com/java-list-storing-triple)
|
||||||
|
- [Convert an ArrayList of Object to an ArrayList of String Elements](https://www.baeldung.com/java-object-list-to-strings)
|
||||||
|
|
|
@ -5,6 +5,33 @@
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<artifactId>core-java-collections-array-list</artifactId>
|
<artifactId>core-java-collections-array-list</artifactId>
|
||||||
<version>0.1.0-SNAPSHOT</version>
|
<version>0.1.0-SNAPSHOT</version>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<source>${maven-compiler-plugin.source}</source>
|
||||||
|
<target>${maven-compiler-plugin.target}</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<version>${surefire.plugin.version}</version>
|
||||||
|
<configuration>
|
||||||
|
<argLine>
|
||||||
|
--add-opens java.base/java.util=ALL-UNNAMED
|
||||||
|
</argLine>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
<properties>
|
||||||
|
<maven-compiler-plugin.source>16</maven-compiler-plugin.source>
|
||||||
|
<maven-compiler-plugin.target>16</maven-compiler-plugin.target>
|
||||||
|
<surefire.plugin.version>3.0.0-M3</surefire.plugin.version>
|
||||||
|
</properties>
|
||||||
<name>core-java-collections-array-list</name>
|
<name>core-java-collections-array-list</name>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
@ -20,6 +47,12 @@
|
||||||
<artifactId>commons-collections4</artifactId>
|
<artifactId>commons-collections4</artifactId>
|
||||||
<version>${commons-collections4.version}</version>
|
<version>${commons-collections4.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.guava</groupId>
|
||||||
|
<artifactId>guava</artifactId>
|
||||||
|
<version>31.1-jre</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
|
@ -0,0 +1,14 @@
|
||||||
|
package com.baeldung.list.ignorecase;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class IgnoreCaseSearchUtil {
|
||||||
|
public static boolean ignoreCaseContains(List<String> theList, String searchStr) {
|
||||||
|
for (String s : theList) {
|
||||||
|
if (searchStr.equalsIgnoreCase(s)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
package com.baeldung.list.ignorecase;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
public class IgnoreCaseStringList extends ArrayList<String> {
|
||||||
|
|
||||||
|
public IgnoreCaseStringList() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public IgnoreCaseStringList(Collection<? extends String> c) {
|
||||||
|
super(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean contains(Object o) {
|
||||||
|
String searchStr = (String) o;
|
||||||
|
// Using Stream API:
|
||||||
|
// return this.stream().anyMatch(searchStr::equalsIgnoreCase);
|
||||||
|
for (String s : this) {
|
||||||
|
if (searchStr.equalsIgnoreCase(s)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
package com.baeldung.listofobjectstolistofstring;
|
||||||
|
|
||||||
|
public class Node {
|
||||||
|
|
||||||
|
private final int x;
|
||||||
|
private final int y;
|
||||||
|
|
||||||
|
public Node(int x, int y) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Node (" + "x=" + x + ", y=" + y + ')';
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
package com.baeldung.listofobjectstolistofstring;
|
||||||
|
|
||||||
|
public class User {
|
||||||
|
private final String fullName;
|
||||||
|
|
||||||
|
public User(String fullName) {
|
||||||
|
this.fullName = fullName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "User (" + "full name='" + fullName + ')';
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
package com.baeldung.triple;
|
||||||
|
|
||||||
|
public class Triple<L, M, R> {
|
||||||
|
|
||||||
|
private final L left;
|
||||||
|
private final M middle;
|
||||||
|
private final R right;
|
||||||
|
|
||||||
|
public Triple(L left, M middle, R right) {
|
||||||
|
this.left = left;
|
||||||
|
this.middle = middle;
|
||||||
|
this.right = right;
|
||||||
|
}
|
||||||
|
|
||||||
|
public L getLeft() {
|
||||||
|
return left;
|
||||||
|
}
|
||||||
|
|
||||||
|
public M getMiddle() {
|
||||||
|
return middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public R getRight() {
|
||||||
|
return right;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
package com.baeldung.list.ignorecase;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
public class IgnoreCaseContainsUnitTest {
|
||||||
|
private static final List<String> LANGUAGES = Arrays.asList("Java", "Python", "Kotlin", "Ruby", "Javascript", "Go");
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenStringList_whenCallTheStandardContains_shouldReturnFalse() {
|
||||||
|
String searchStr = "jAvA";
|
||||||
|
boolean result = LANGUAGES.contains(searchStr);
|
||||||
|
assertFalse(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenStringList_whenSearchIgnoreCaseUsingStreamAPI_shouldReturnTrue() {
|
||||||
|
String searchStr = "koTliN";
|
||||||
|
boolean result = LANGUAGES.stream().anyMatch(searchStr::equalsIgnoreCase);
|
||||||
|
assertTrue(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenStringList_whenUsingUtilClass_shouldReturnTrue() {
|
||||||
|
String searchStr = "ruBY";
|
||||||
|
boolean result = IgnoreCaseSearchUtil.ignoreCaseContains(LANGUAGES, searchStr);
|
||||||
|
assertTrue(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenStringList_whenUsingIgnoreCaseStringList_shouldReturnTrue() {
|
||||||
|
String searchStr = "pYtHoN";
|
||||||
|
List<String> ignoreCaseList = new IgnoreCaseStringList(LANGUAGES);
|
||||||
|
boolean result = ignoreCaseList.contains(searchStr);
|
||||||
|
assertTrue(result);
|
||||||
|
|
||||||
|
boolean resultContainAll = ignoreCaseList.containsAll(Arrays.asList("pYtHon", "jAvA", "koTliN", "ruBY"));
|
||||||
|
assertTrue(resultContainAll);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,92 @@
|
||||||
|
package com.baeldung.listofobjectstolistofstring;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class ConvertObjectListToStringListUnitTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenObjectList_whenForEachUsedToConvert_thenReturnSuccess() {
|
||||||
|
List<String> outputList = new ArrayList<>(objectListWithNull().size());
|
||||||
|
for (Object obj : objectListWithNull()) {
|
||||||
|
outputList.add(Objects.toString(obj, null));
|
||||||
|
}
|
||||||
|
Assert.assertEquals(expectedStringListWithNull(), outputList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenObjectList_whenUsingStreamsToConvert_thenReturnSuccess() {
|
||||||
|
List<String> outputList;
|
||||||
|
outputList = objectListWithNull().stream()
|
||||||
|
.map((obj) -> Objects.toString(obj, null))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
Assert.assertEquals(expectedStringListWithNull(), outputList);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenObjectList_whenUsingStreamsUnmodifiableListToConvert_thenReturnSuccess() {
|
||||||
|
List<String> outputList;
|
||||||
|
outputList = objectListWithNull().stream()
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.map((obj) -> Objects.toString(obj, null))
|
||||||
|
.collect(Collectors.toUnmodifiableList());
|
||||||
|
Assert.assertEquals(expectedStringListWithoutNull(), outputList);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenObjectList_whenUsingGuavaTransform_thenReturnSuccess() {
|
||||||
|
List<String> outputList;
|
||||||
|
outputList = Lists.transform(objectListWithNull(), obj -> Objects.toString(obj, null));
|
||||||
|
Assert.assertEquals(expectedStringListWithNull(), outputList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenObjectListWithNoNull_whenUsingToList_thenReturnSuccess() {
|
||||||
|
List<String> outputList;
|
||||||
|
outputList = objectListWithoutNull().stream()
|
||||||
|
.map((obj) -> Objects.toString(obj, null))
|
||||||
|
.toList();
|
||||||
|
Assert.assertEquals(expectedStringListWithoutNull(), outputList);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> expectedStringListWithNull() {
|
||||||
|
List<String> listOfStrings = new ArrayList<>();
|
||||||
|
listOfStrings.add("1");
|
||||||
|
listOfStrings.add("true");
|
||||||
|
listOfStrings.add("hello");
|
||||||
|
listOfStrings.add(Double.toString(273773.98));
|
||||||
|
listOfStrings.add(null);
|
||||||
|
listOfStrings.add(new Node(2, 4).toString());
|
||||||
|
listOfStrings.add(new User("John Doe").toString());
|
||||||
|
return listOfStrings;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Object> objectListWithNull() {
|
||||||
|
List<Object> listOfStrings = new ArrayList<>();
|
||||||
|
listOfStrings.add(1);
|
||||||
|
listOfStrings.add(true);
|
||||||
|
listOfStrings.add("hello");
|
||||||
|
listOfStrings.add(Double.valueOf(273773.98));
|
||||||
|
listOfStrings.add(null);
|
||||||
|
listOfStrings.add(new Node(2, 4));
|
||||||
|
listOfStrings.add(new User("John Doe"));
|
||||||
|
return listOfStrings;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> expectedStringListWithoutNull() {
|
||||||
|
return List.of("1", "true", "hello", Double.toString(273773.98), new Node(2, 4).toString(), new User("John Doe").toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Object> objectListWithoutNull() {
|
||||||
|
return List.of(1, true, "hello", Double.valueOf(273773.98), new Node(2, 4), new User("John Doe"));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,105 @@
|
||||||
|
package com.baeldung.triple;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
public class TripleInListUnitTest {
|
||||||
|
|
||||||
|
enum OP {
|
||||||
|
PLUS("+"), MINUS("-"), MULTIPLY("x");
|
||||||
|
final String opSign;
|
||||||
|
|
||||||
|
OP(String x) {
|
||||||
|
this.opSign = x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String createQuestion(Long num1, OP operator, Long num2) {
|
||||||
|
long result;
|
||||||
|
switch (operator) {
|
||||||
|
case PLUS:
|
||||||
|
result = num1 + num2;
|
||||||
|
break;
|
||||||
|
case MINUS:
|
||||||
|
result = num1 - num2;
|
||||||
|
break;
|
||||||
|
case MULTIPLY:
|
||||||
|
result = num1 * num2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Unknown operator");
|
||||||
|
}
|
||||||
|
return String.format("%d %s %d = ? ( answer: %d )", num1, operator.opSign, num2, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final List<String> EXPECTED_QUESTIONS = Arrays.asList(
|
||||||
|
"100 - 42 = ? ( answer: 58 )",
|
||||||
|
"100 + 42 = ? ( answer: 142 )",
|
||||||
|
"100 x 42 = ? ( answer: 4200 )");
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenTripleValues_whenStoreAsList_thenTypeIsNotSafe() {
|
||||||
|
|
||||||
|
List myTriple1 = new ArrayList(3);
|
||||||
|
myTriple1.add(100L);
|
||||||
|
myTriple1.add(OP.MINUS);
|
||||||
|
myTriple1.add(42L);
|
||||||
|
|
||||||
|
List myTriple2 = new ArrayList(3);
|
||||||
|
myTriple2.add(100L);
|
||||||
|
myTriple2.add(OP.PLUS);
|
||||||
|
myTriple2.add(42L);
|
||||||
|
|
||||||
|
List myTriple3 = new ArrayList(3);
|
||||||
|
myTriple3.add(100L);
|
||||||
|
myTriple3.add(OP.MULTIPLY);
|
||||||
|
myTriple3.add(42L);
|
||||||
|
|
||||||
|
List<List> listOfTriples = new ArrayList<>(Arrays.asList(myTriple1, myTriple2, myTriple3));
|
||||||
|
|
||||||
|
List oopsTriple = new ArrayList(3);
|
||||||
|
oopsTriple.add("Oops");
|
||||||
|
oopsTriple.add(911L);
|
||||||
|
oopsTriple.add("The type is wrong");
|
||||||
|
|
||||||
|
listOfTriples.add(oopsTriple);
|
||||||
|
assertEquals(4, listOfTriples.size());
|
||||||
|
|
||||||
|
List<String> questions = listOfTriples.stream()
|
||||||
|
.filter(
|
||||||
|
triple -> triple.size() == 3
|
||||||
|
&& triple.get(0) instanceof Long
|
||||||
|
&& triple.get(1) instanceof OP
|
||||||
|
&& triple.get(2) instanceof Long
|
||||||
|
).map(triple -> {
|
||||||
|
Long left = (Long) triple.get(0);
|
||||||
|
OP op = (OP) triple.get(1);
|
||||||
|
Long right = (Long) triple.get(2);
|
||||||
|
return createQuestion(left, op, right);
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
|
||||||
|
assertEquals(EXPECTED_QUESTIONS, questions);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenTripleValues_whenUsingTheTripleClass_thenTypeIsSafeAndNeat() {
|
||||||
|
Triple<Long, OP, Long> triple1 = new Triple<>(100L, OP.MINUS, 42L);
|
||||||
|
Triple<Long, OP, Long> triple2 = new Triple<>(100L, OP.PLUS, 42L);
|
||||||
|
Triple<Long, OP, Long> triple3 = new Triple<>(100L, OP.MULTIPLY, 42L);
|
||||||
|
Triple<String, Long, String> tripleOops = new Triple<>("Oops", 911L, "The type is wrong");
|
||||||
|
|
||||||
|
List<Triple<Long, OP, Long>> listOfTriples = new ArrayList<>(Arrays.asList(triple1, triple2, triple3));
|
||||||
|
// listOfTriples.add(tripleOops); // Compiler error: "java: incompatible types ... "
|
||||||
|
|
||||||
|
List<String> questions = listOfTriples.stream()
|
||||||
|
.map(triple -> createQuestion(triple.getLeft(), triple.getMiddle(), triple.getRight()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
assertEquals(EXPECTED_QUESTIONS, questions);
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,4 +5,5 @@ This module contains articles about working with the Java Virtual Machine (JVM).
|
||||||
### Relevant Articles:
|
### Relevant Articles:
|
||||||
|
|
||||||
- [Difference Between Class.getResource() and ClassLoader.getResource()](https://www.baeldung.com/java-class-vs-classloader-getresource)
|
- [Difference Between Class.getResource() and ClassLoader.getResource()](https://www.baeldung.com/java-class-vs-classloader-getresource)
|
||||||
|
- [Compiling and Executing Code From a String in Java](https://www.baeldung.com/java-string-compile-execute-code)
|
||||||
- More articles: [[<-- prev]](/core-java-modules/core-java-jvm-2)
|
- More articles: [[<-- prev]](/core-java-modules/core-java-jvm-2)
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
package com.baeldung.inmemorycompilation;
|
||||||
|
|
||||||
|
public interface InMemoryClass {
|
||||||
|
|
||||||
|
void runCode();
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
package com.baeldung.inmemorycompilation;
|
||||||
|
|
||||||
|
import static java.util.Objects.requireNonNull;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class InMemoryClassLoader extends ClassLoader {
|
||||||
|
|
||||||
|
private final InMemoryFileManager manager;
|
||||||
|
|
||||||
|
public InMemoryClassLoader(ClassLoader parent, InMemoryFileManager manager) {
|
||||||
|
super(parent);
|
||||||
|
this.manager = requireNonNull(manager, "manager must not be null");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<?> findClass(String name) throws ClassNotFoundException {
|
||||||
|
|
||||||
|
Map<String, JavaClassAsBytes> compiledClasses = manager
|
||||||
|
.getBytesMap();
|
||||||
|
|
||||||
|
if (compiledClasses.containsKey(name)) {
|
||||||
|
byte[] bytes = compiledClasses.get(name)
|
||||||
|
.getBytes();
|
||||||
|
return defineClass(name, bytes, 0, bytes.length);
|
||||||
|
} else {
|
||||||
|
throw new ClassNotFoundException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
package com.baeldung.inmemorycompilation;
|
||||||
|
|
||||||
|
import java.util.Hashtable;
|
||||||
|
import java.util.Map;
|
||||||
|
import javax.tools.FileObject;
|
||||||
|
import javax.tools.ForwardingJavaFileManager;
|
||||||
|
import javax.tools.JavaFileManager;
|
||||||
|
import javax.tools.JavaFileObject;
|
||||||
|
import javax.tools.JavaFileObject.Kind;
|
||||||
|
import javax.tools.StandardJavaFileManager;
|
||||||
|
|
||||||
|
public class InMemoryFileManager extends ForwardingJavaFileManager<JavaFileManager> {
|
||||||
|
|
||||||
|
private final Map<String, JavaClassAsBytes> compiledClasses;
|
||||||
|
private final ClassLoader loader;
|
||||||
|
|
||||||
|
public InMemoryFileManager(StandardJavaFileManager standardManager) {
|
||||||
|
super(standardManager);
|
||||||
|
this.compiledClasses = new Hashtable<>();
|
||||||
|
this.loader = new InMemoryClassLoader(this.getClass()
|
||||||
|
.getClassLoader(),
|
||||||
|
this
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to get the class loader for our compiled class. It creates an anonymous class extending
|
||||||
|
* the SecureClassLoader which uses the byte code created by the compiler and stored in the
|
||||||
|
* JavaClassObject, and returns the Class for it
|
||||||
|
*
|
||||||
|
* @param location where to place or search for file objects.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public ClassLoader getClassLoader(Location location) {
|
||||||
|
return loader;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind,
|
||||||
|
FileObject sibling) {
|
||||||
|
|
||||||
|
JavaClassAsBytes classAsBytes = new JavaClassAsBytes(
|
||||||
|
className, kind);
|
||||||
|
compiledClasses.put(className, classAsBytes);
|
||||||
|
|
||||||
|
return classAsBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, JavaClassAsBytes> getBytesMap() {
|
||||||
|
return compiledClasses;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
package com.baeldung.inmemorycompilation;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.net.URI;
|
||||||
|
import javax.tools.SimpleJavaFileObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a Java class file (compiled byte-code)
|
||||||
|
*/
|
||||||
|
public class JavaClassAsBytes extends SimpleJavaFileObject {
|
||||||
|
|
||||||
|
protected final ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
public JavaClassAsBytes(String name, Kind kind) {
|
||||||
|
super(URI.create("string:///" + name.replace('.', '/') + kind.extension), kind);
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getBytes() {
|
||||||
|
return bos.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OutputStream openOutputStream() {
|
||||||
|
return bos;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
package com.baeldung.inmemorycompilation;
|
||||||
|
|
||||||
|
import static java.util.Objects.requireNonNull;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import javax.tools.SimpleJavaFileObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a Java source code file
|
||||||
|
*/
|
||||||
|
public class JavaSourceFromString extends SimpleJavaFileObject {
|
||||||
|
|
||||||
|
private final String sourceCode;
|
||||||
|
|
||||||
|
public JavaSourceFromString(String name, String sourceCode) {
|
||||||
|
super(URI.create("string:///" + name.replace('.', '/') + Kind.SOURCE.extension),
|
||||||
|
Kind.SOURCE
|
||||||
|
);
|
||||||
|
this.sourceCode = requireNonNull(sourceCode, "sourceCode must not be null");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CharSequence getCharContent(boolean ignoreEncodingErrors) {
|
||||||
|
return sourceCode;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
package com.baeldung.inmemorycompilation;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.tools.DiagnosticCollector;
|
||||||
|
import javax.tools.JavaCompiler;
|
||||||
|
import javax.tools.JavaFileObject;
|
||||||
|
import javax.tools.ToolProvider;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class InMemoryCompilationUnitTest {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(InMemoryCompilationUnitTest.class);
|
||||||
|
|
||||||
|
final static String QUALIFIED_CLASS_NAME = "com.baeldung.inmemorycompilation.TestClass";
|
||||||
|
|
||||||
|
final static String SOURCE_CODE =
|
||||||
|
"package com.baeldung.inmemorycompilation;\n"
|
||||||
|
+ "public class TestClass implements InMemoryClass {\n"
|
||||||
|
+ "@Override\n"
|
||||||
|
+ " public void runCode() {\n"
|
||||||
|
+ " System.out.println(\"code is running...\");\n"
|
||||||
|
+ " }\n"
|
||||||
|
+ "}\n";
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenStringIsCompiled_ThenCodeShouldExecute() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
|
||||||
|
|
||||||
|
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
|
||||||
|
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>();
|
||||||
|
InMemoryFileManager manager = new InMemoryFileManager(compiler.getStandardFileManager(null, null, null));
|
||||||
|
|
||||||
|
List<JavaFileObject> sourceFiles = Collections.singletonList(new JavaSourceFromString(QUALIFIED_CLASS_NAME, SOURCE_CODE));
|
||||||
|
|
||||||
|
JavaCompiler.CompilationTask task = compiler.getTask(null, manager, diagnostics, null, null, sourceFiles);
|
||||||
|
|
||||||
|
boolean result = task.call();
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
diagnostics.getDiagnostics()
|
||||||
|
.forEach(d -> LOGGER.error(String.valueOf(d)));
|
||||||
|
} else {
|
||||||
|
ClassLoader classLoader = manager.getClassLoader(null);
|
||||||
|
Class<?> clazz = classLoader.loadClass(QUALIFIED_CLASS_NAME);
|
||||||
|
InMemoryClass instanceOfClass = (InMemoryClass) clazz.newInstance();
|
||||||
|
|
||||||
|
Assertions.assertInstanceOf(InMemoryClass.class, instanceOfClass);
|
||||||
|
|
||||||
|
instanceOfClass.runCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,10 +1,12 @@
|
||||||
package com.baeldung.resource;
|
package com.baeldung.resource;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Assertions;
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.Disabled;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
|
||||||
|
@Disabled
|
||||||
class ClassGetResourceUnitTest {
|
class ClassGetResourceUnitTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
|
@ -1,10 +1,12 @@
|
||||||
package com.baeldung.resource;
|
package com.baeldung.resource;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Assertions;
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.Disabled;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
|
||||||
|
@Disabled
|
||||||
class ClassLoaderGetResourceUnitTest {
|
class ClassLoaderGetResourceUnitTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
|
@ -2,68 +2,76 @@ package com.baeldung.convertnumberbases;
|
||||||
|
|
||||||
public class ConvertNumberBases {
|
public class ConvertNumberBases {
|
||||||
|
|
||||||
public static String convertNumberToNewBase(String number, int base, int newBase){
|
public static String convertNumberToNewBase(String number, int base, int newBase) {
|
||||||
return Integer.toString(Integer.parseInt(number, base), newBase);
|
return Integer.toString(Integer.parseInt(number, base), newBase);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String convertNumberToNewBaseCustom(String num, int base, int newBase) {
|
public static String convertNumberToNewBaseCustom(String num, int base, int newBase) {
|
||||||
int decimalNumber = convertFromAnyBaseToDecimal(num, base);
|
int decimalNumber = convertFromAnyBaseToDecimal(num, base);
|
||||||
return convertFromDecimalToBaseX(decimalNumber, newBase);
|
String targetBase = "";
|
||||||
|
try {
|
||||||
|
targetBase = convertFromDecimalToBaseX(decimalNumber, newBase);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return targetBase;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String convertFromDecimalToBaseX(int num, int newBase) {
|
public static String convertFromDecimalToBaseX(int num, int newBase) throws IllegalArgumentException {
|
||||||
|
if ((newBase < 2 || newBase > 10) && newBase != 16) {
|
||||||
|
throw new IllegalArgumentException("New base must be from 2 - 10 or 16");
|
||||||
|
}
|
||||||
|
|
||||||
String result = "";
|
String result = "";
|
||||||
int remainder;
|
int remainder;
|
||||||
while (num > 0) {
|
while (num > 0) {
|
||||||
remainder = num % newBase;
|
remainder = num % newBase;
|
||||||
if (newBase == 16) {
|
if (newBase == 16) {
|
||||||
if (remainder == 10)
|
if (remainder == 10) {
|
||||||
result += 'A';
|
result += 'A';
|
||||||
else if (remainder == 11)
|
} else if (remainder == 11) {
|
||||||
result += 'B';
|
result += 'B';
|
||||||
else if (remainder == 12)
|
} else if (remainder == 12) {
|
||||||
result += 'C';
|
result += 'C';
|
||||||
else if (remainder == 13)
|
} else if (remainder == 13) {
|
||||||
result += 'D';
|
result += 'D';
|
||||||
else if (remainder == 14)
|
} else if (remainder == 14) {
|
||||||
result += 'E';
|
result += 'E';
|
||||||
else if (remainder == 15)
|
} else if (remainder == 15) {
|
||||||
result += 'F';
|
result += 'F';
|
||||||
else
|
} else {
|
||||||
result += remainder;
|
result += remainder;
|
||||||
} else
|
}
|
||||||
|
} else {
|
||||||
result += remainder;
|
result += remainder;
|
||||||
|
}
|
||||||
num /= newBase;
|
num /= newBase;
|
||||||
}
|
}
|
||||||
return new StringBuffer(result).reverse().toString();
|
return new StringBuffer(result).reverse().toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int convertFromAnyBaseToDecimal(String num, int base) {
|
public static int convertFromAnyBaseToDecimal(String num, int base) {
|
||||||
|
if (base < 2 || (base > 10 && base != 16)) {
|
||||||
if (base < 2 || (base > 10 && base != 16))
|
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
int val = 0;
|
int val = 0;
|
||||||
int power = 1;
|
int power = 1;
|
||||||
|
|
||||||
for (int i = num.length() - 1; i >= 0; i--) {
|
for (int i = num.length() - 1; i >= 0; i--) {
|
||||||
int digit = charToDecimal(num.charAt(i));
|
int digit = charToDecimal(num.charAt(i));
|
||||||
|
if (digit < 0 || digit >= base) {
|
||||||
if (digit < 0 || digit >= base)
|
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
val += digit * power;
|
val += digit * power;
|
||||||
power = power * base;
|
power = power * base;
|
||||||
}
|
}
|
||||||
|
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int charToDecimal(char c) {
|
public static int charToDecimal(char c) {
|
||||||
if (c >= '0' && c <= '9')
|
if (c >= '0' && c <= '9') {
|
||||||
return (int) c - '0';
|
return (int) c - '0';
|
||||||
else
|
} else {
|
||||||
return (int) c - 'A' + 10;
|
return (int) c - 'A' + 10;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package com.baeldung.convertnumberbases;
|
package com.baeldung.convertnumberbases;
|
||||||
|
|
||||||
|
import static com.baeldung.convertnumberbases.ConvertNumberBases.convertFromDecimalToBaseX;
|
||||||
import static com.baeldung.convertnumberbases.ConvertNumberBases.convertNumberToNewBase;
|
import static com.baeldung.convertnumberbases.ConvertNumberBases.convertNumberToNewBase;
|
||||||
import static com.baeldung.convertnumberbases.ConvertNumberBases.convertNumberToNewBaseCustom;
|
import static com.baeldung.convertnumberbases.ConvertNumberBases.convertNumberToNewBaseCustom;
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
@ -17,4 +18,15 @@ class ConvertNumberBasesUnitTest {
|
||||||
assertEquals(convertNumberToNewBaseCustom("11001000", 2, 8), "310");
|
assertEquals(convertNumberToNewBaseCustom("11001000", 2, 8), "310");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void whenInputIsOutOfRange_thenIllegalArgumentExceptionIsThrown() {
|
||||||
|
Exception exception = assertThrows(IllegalArgumentException.class, ()-> {
|
||||||
|
convertFromDecimalToBaseX(100, 12);
|
||||||
|
});
|
||||||
|
String expectedMessage = "New base must be from 2 - 10 or 16";
|
||||||
|
String actualMessage = exception.getMessage();
|
||||||
|
|
||||||
|
assertTrue(actualMessage.contains(expectedMessage));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -6,3 +6,4 @@ This module contains articles about Object Oriented Programming (OOP) in Java
|
||||||
- [Object-Oriented-Programming Concepts in Java](https://www.baeldung.com/java-oop)
|
- [Object-Oriented-Programming Concepts in Java](https://www.baeldung.com/java-oop)
|
||||||
- [Static and Dynamic Binding in Java](https://www.baeldung.com/java-static-dynamic-binding)
|
- [Static and Dynamic Binding in Java](https://www.baeldung.com/java-static-dynamic-binding)
|
||||||
- [Pass-By-Value as a Parameter Passing Mechanism in Java](https://www.baeldung.com/java-pass-by-value-or-pass-by-reference)
|
- [Pass-By-Value as a Parameter Passing Mechanism in Java](https://www.baeldung.com/java-pass-by-value-or-pass-by-reference)
|
||||||
|
- [Check If All the Variables of an Object Are Null](https://www.baeldung.com/java-check-all-variables-object-null)
|
||||||
|
|
|
@ -5,3 +5,4 @@
|
||||||
- [Filter Java Stream to 1 and Only 1 Element](https://www.baeldung.com/java-filter-stream-unique-element)
|
- [Filter Java Stream to 1 and Only 1 Element](https://www.baeldung.com/java-filter-stream-unique-element)
|
||||||
- [Java 8 Streams: Multiple Filters vs. Complex Condition](https://www.baeldung.com/java-streams-multiple-filters-vs-condition)
|
- [Java 8 Streams: Multiple Filters vs. Complex Condition](https://www.baeldung.com/java-streams-multiple-filters-vs-condition)
|
||||||
- [Finding Max Date in List Using Streams](https://www.baeldung.com/java-max-date-list-streams)
|
- [Finding Max Date in List Using Streams](https://www.baeldung.com/java-max-date-list-streams)
|
||||||
|
- [Batch Processing of Stream Data in Java](https://www.baeldung.com/java-stream-batch-processing)
|
||||||
|
|
|
@ -59,6 +59,36 @@
|
||||||
<version>3.12.0</version>
|
<version>3.12.0</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.reactivex.rxjava3</groupId>
|
||||||
|
<artifactId>rxjava</artifactId>
|
||||||
|
<version>${rx.java3.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.vavr</groupId>
|
||||||
|
<artifactId>vavr</artifactId>
|
||||||
|
<version>${io.varv.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.projectreactor</groupId>
|
||||||
|
<artifactId>reactor-core</artifactId>
|
||||||
|
<version>${io.reactor3.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-collections4</artifactId>
|
||||||
|
<version>${apache.commons.collection4.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.guava</groupId>
|
||||||
|
<artifactId>guava</artifactId>
|
||||||
|
<version>${google.guava.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.oath.cyclops</groupId>
|
||||||
|
<artifactId>cyclops</artifactId>
|
||||||
|
<version>${cyclops.version}</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
@ -90,6 +120,12 @@
|
||||||
<maven.compiler.target>12</maven.compiler.target>
|
<maven.compiler.target>12</maven.compiler.target>
|
||||||
<rx.java.version>1.2.5</rx.java.version>
|
<rx.java.version>1.2.5</rx.java.version>
|
||||||
<rx.java2.version>2.2.2</rx.java2.version>
|
<rx.java2.version>2.2.2</rx.java2.version>
|
||||||
|
<rx.java3.version>3.1.5</rx.java3.version>
|
||||||
|
<io.varv.version>1.0.0-alpha-4</io.varv.version>
|
||||||
|
<io.reactor3.version>3.5.1</io.reactor3.version>
|
||||||
|
<apache.commons.collection4.version>4.4</apache.commons.collection4.version>
|
||||||
|
<google.guava.version>31.1-jre</google.guava.version>
|
||||||
|
<cyclops.version>10.4.1</cyclops.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
</project>
|
</project>
|
|
@ -0,0 +1,47 @@
|
||||||
|
package com.baeldung.streams.processing;
|
||||||
|
|
||||||
|
import static java.util.Spliterator.ORDERED;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Spliterators;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
import java.util.stream.StreamSupport;
|
||||||
|
|
||||||
|
public class CustomBatchIterator<T> implements Iterator<List<T>> {
|
||||||
|
private final int batchSize;
|
||||||
|
private List<T> currentBatch;
|
||||||
|
private final Iterator<T> iterator;
|
||||||
|
|
||||||
|
public CustomBatchIterator(Iterator<T> sourceIterator, int batchSize) {
|
||||||
|
this.batchSize = batchSize;
|
||||||
|
this.iterator = sourceIterator;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<T> next() {
|
||||||
|
return currentBatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
prepareNextBatch();
|
||||||
|
return currentBatch != null && !currentBatch.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> Stream<List<T>> batchStreamOf(Stream<T> stream, int batchSize) {
|
||||||
|
return stream(new CustomBatchIterator<>(stream.iterator(), batchSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T> Stream<T> stream(Iterator<T> iterator) {
|
||||||
|
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, ORDERED), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void prepareNextBatch() {
|
||||||
|
currentBatch = new ArrayList<>(batchSize);
|
||||||
|
while (iterator.hasNext() && currentBatch.size() < batchSize) {
|
||||||
|
currentBatch.add(iterator.next());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,141 @@
|
||||||
|
package com.baeldung.streams.processing;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import org.apache.commons.collections4.ListUtils;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import com.google.common.collect.Iterators;
|
||||||
|
|
||||||
|
import cyclops.data.LazySeq;
|
||||||
|
import cyclops.reactive.ReactiveSeq;
|
||||||
|
import io.reactivex.rxjava3.core.Observable;
|
||||||
|
import reactor.core.publisher.Flux;
|
||||||
|
|
||||||
|
public class StreamProcessingUnitTest {
|
||||||
|
public final int BATCH_SIZE = 10;
|
||||||
|
|
||||||
|
private final List<Integer> firstBatch = List.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
|
||||||
|
private final List<Integer> secondBatch = List.of(10, 11, 12, 13, 14, 15, 16, 17, 18, 19);
|
||||||
|
private final List<Integer> thirdBatch = List.of(20, 21, 22, 23, 24, 25, 26, 27, 28, 29);
|
||||||
|
private final List<Integer> fourthBatch = List.of(30, 31, 32, 33);
|
||||||
|
|
||||||
|
public Stream<Integer> data;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void setUp() {
|
||||||
|
data = IntStream.range(0, 34)
|
||||||
|
.boxed();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenAStreamOfData_whenIsProcessingInBatchUsingSpliterator_thenFourBatchesAreObtained() {
|
||||||
|
Collection<List<Integer>> result = new ArrayList<>();
|
||||||
|
CustomBatchIterator.batchStreamOf(data, BATCH_SIZE)
|
||||||
|
.forEach(result::add);
|
||||||
|
assertTrue(result.contains(firstBatch));
|
||||||
|
assertTrue(result.contains(secondBatch));
|
||||||
|
assertTrue(result.contains(thirdBatch));
|
||||||
|
assertTrue(result.contains(fourthBatch));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenAStreamOfData_whenIsProcessingInBatchUsingCollectionAPI_thenFourBatchesAreObtained() {
|
||||||
|
Collection<List<Integer>> result = data.collect(Collectors.groupingBy(it -> it / BATCH_SIZE))
|
||||||
|
.values();
|
||||||
|
assertTrue(result.contains(firstBatch));
|
||||||
|
assertTrue(result.contains(secondBatch));
|
||||||
|
assertTrue(result.contains(thirdBatch));
|
||||||
|
assertTrue(result.contains(fourthBatch));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenAStreamOfData_whenIsProcessingInBatchParallelUsingCollectionAPI_thenFourBatchesAreObtained() {
|
||||||
|
Collection<List<Integer>> result = data.parallel()
|
||||||
|
.collect(Collectors.groupingBy(it -> it / BATCH_SIZE))
|
||||||
|
.values();
|
||||||
|
assertTrue(result.contains(firstBatch));
|
||||||
|
assertTrue(result.contains(secondBatch));
|
||||||
|
assertTrue(result.contains(thirdBatch));
|
||||||
|
assertTrue(result.contains(fourthBatch));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenAStreamOfData_whenIsProcessingInBatchUsingRxJavaV3_thenFourBatchesAreObtained() {
|
||||||
|
// RxJava v3
|
||||||
|
Collection<List<Integer>> result = new ArrayList<>();
|
||||||
|
Observable.fromStream(data)
|
||||||
|
.buffer(BATCH_SIZE)
|
||||||
|
.subscribe(result::add);
|
||||||
|
assertTrue(result.contains(firstBatch));
|
||||||
|
assertTrue(result.contains(secondBatch));
|
||||||
|
assertTrue(result.contains(thirdBatch));
|
||||||
|
assertTrue(result.contains(fourthBatch));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenAStreamOfData_whenIsProcessingInBatchUsingReactor_thenFourBatchesAreObtained() {
|
||||||
|
Collection<List<Integer>> result = new ArrayList<>();
|
||||||
|
Flux.fromStream(data)
|
||||||
|
.buffer(BATCH_SIZE)
|
||||||
|
.subscribe(result::add);
|
||||||
|
assertTrue(result.contains(firstBatch));
|
||||||
|
assertTrue(result.contains(secondBatch));
|
||||||
|
assertTrue(result.contains(thirdBatch));
|
||||||
|
assertTrue(result.contains(fourthBatch));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenAStreamOfData_whenIsProcessingInBatchUsingApacheCommon_thenFourBatchesAreObtained() {
|
||||||
|
Collection<List<Integer>> result = new ArrayList<>(ListUtils.partition(data.collect(Collectors.toList()), BATCH_SIZE));
|
||||||
|
assertTrue(result.contains(firstBatch));
|
||||||
|
assertTrue(result.contains(secondBatch));
|
||||||
|
assertTrue(result.contains(thirdBatch));
|
||||||
|
assertTrue(result.contains(fourthBatch));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenAStreamOfData_whenIsProcessingInBatchUsingGuava_thenFourBatchesAreObtained() {
|
||||||
|
Collection<List<Integer>> result = new ArrayList<>();
|
||||||
|
Iterators.partition(data.iterator(), BATCH_SIZE)
|
||||||
|
.forEachRemaining(result::add);
|
||||||
|
assertTrue(result.contains(firstBatch));
|
||||||
|
assertTrue(result.contains(secondBatch));
|
||||||
|
assertTrue(result.contains(thirdBatch));
|
||||||
|
assertTrue(result.contains(fourthBatch));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenAStreamOfData_whenIsProcessingInBatchUsingCyclops_thenFourBatchesAreObtained() {
|
||||||
|
Collection<List<Integer>> result = new ArrayList<>();
|
||||||
|
ReactiveSeq.fromStream(data)
|
||||||
|
.grouped(BATCH_SIZE)
|
||||||
|
.toList()
|
||||||
|
.forEach(value -> result.add(value.collect(Collectors.toList())));
|
||||||
|
assertTrue(result.contains(firstBatch));
|
||||||
|
assertTrue(result.contains(secondBatch));
|
||||||
|
assertTrue(result.contains(thirdBatch));
|
||||||
|
assertTrue(result.contains(fourthBatch));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenAStreamOfData_whenIsProcessingInBatchUsingCyclopsLazy_thenFourBatchesAreObtained() {
|
||||||
|
Collection<List<Integer>> result = new ArrayList<>();
|
||||||
|
LazySeq.fromStream(data)
|
||||||
|
.grouped(BATCH_SIZE)
|
||||||
|
.toList()
|
||||||
|
.forEach(value -> result.add(value.collect(Collectors.toList())));
|
||||||
|
assertTrue(result.contains(firstBatch));
|
||||||
|
assertTrue(result.contains(secondBatch));
|
||||||
|
assertTrue(result.contains(thirdBatch));
|
||||||
|
assertTrue(result.contains(fourthBatch));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
package com.baeldung.streams.processing.vavr;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import com.baeldung.streams.processing.StreamProcessingUnitTest;
|
||||||
|
|
||||||
|
import io.vavr.collection.List;
|
||||||
|
import io.vavr.collection.Stream;
|
||||||
|
|
||||||
|
public class StreamProcessingWithVavrUnitTest extends StreamProcessingUnitTest {
|
||||||
|
|
||||||
|
private final List<Integer> firstBatch = List.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
|
||||||
|
private final List<Integer> secondBatch = List.of(10, 11, 12, 13, 14, 15, 16, 17, 18, 19);
|
||||||
|
private final List<Integer> thirdBatch = List.of(20, 21, 22, 23, 24, 25, 26, 27, 28, 29);
|
||||||
|
private final List<Integer> fourthBatch = List.of(30, 31, 32, 33);
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenAStreamOfData_whenIsProcessingInBatchUsingVavr_thenFourBatchesAreObtained() {
|
||||||
|
List<List<Integer>> result = Stream.ofAll(data)
|
||||||
|
.toList()
|
||||||
|
.grouped(BATCH_SIZE)
|
||||||
|
.toList();
|
||||||
|
assertTrue(result.contains(firstBatch));
|
||||||
|
assertTrue(result.contains(secondBatch));
|
||||||
|
assertTrue(result.contains(thirdBatch));
|
||||||
|
assertTrue(result.contains(fourthBatch));
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,17 +27,17 @@ public final class UUIDGenerator {
|
||||||
|
|
||||||
private static long get64LeastSignificantBitsForVersion1() {
|
private static long get64LeastSignificantBitsForVersion1() {
|
||||||
final long random63BitLong = new Random().nextLong() & 0x3FFFFFFFFFFFFFFFL;
|
final long random63BitLong = new Random().nextLong() & 0x3FFFFFFFFFFFFFFFL;
|
||||||
final long variant3BitFlag = 0x8000000000000000L;
|
long variant3BitFlag = 0x8000000000000000L;
|
||||||
return random63BitLong + variant3BitFlag;
|
return random63BitLong | variant3BitFlag;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static long get64MostSignificantBitsForVersion1() {
|
private static long get64MostSignificantBitsForVersion1() {
|
||||||
final long timeForUuidIn100Nanos = System.currentTimeMillis();
|
final long currentTimeMillis = System.currentTimeMillis();
|
||||||
final long time_low = (timeForUuidIn100Nanos & 0x0000_0000_FFFF_FFFFL) << 32;
|
final long time_low = (currentTimeMillis & 0x0000_0000_FFFF_FFFFL) << 32;
|
||||||
final long time_mid = ((timeForUuidIn100Nanos >> 32) & 0xFFFF) << 16;
|
final long time_mid = ((currentTimeMillis >> 32) & 0xFFFF) << 16;
|
||||||
final long version = 1 << 12;
|
final long version = 1 << 12;
|
||||||
final long time_hi = ((timeForUuidIn100Nanos >> 48) & 0x0FFF);
|
final long time_high = ((currentTimeMillis >> 48) & 0x0FFF);
|
||||||
return time_low + time_mid + version + time_hi;
|
return time_low | time_mid | version | time_high;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -9,3 +9,4 @@
|
||||||
- [A Guide to the ResourceBundle](http://www.baeldung.com/java-resourcebundle)
|
- [A Guide to the ResourceBundle](http://www.baeldung.com/java-resourcebundle)
|
||||||
- [Merging java.util.Properties Objects](https://www.baeldung.com/java-merging-properties)
|
- [Merging java.util.Properties Objects](https://www.baeldung.com/java-merging-properties)
|
||||||
- [Illegal Character Compilation Error](https://www.baeldung.com/java-illegal-character-error)
|
- [Illegal Character Compilation Error](https://www.baeldung.com/java-illegal-character-error)
|
||||||
|
- [Lambda Expression vs. Anonymous Inner Class](https://www.baeldung.com/java-lambdas-vs-anonymous-class)
|
||||||
|
|
|
@ -31,7 +31,6 @@
|
||||||
<module>core-java-collections-2</module>
|
<module>core-java-collections-2</module>
|
||||||
<module>core-java-collections-3</module>
|
<module>core-java-collections-3</module>
|
||||||
<module>core-java-collections-4</module>
|
<module>core-java-collections-4</module>
|
||||||
<module>core-java-collections-array-list</module>
|
|
||||||
<module>core-java-collections-conversions</module>
|
<module>core-java-collections-conversions</module>
|
||||||
<module>core-java-collections-conversions-2</module>
|
<module>core-java-collections-conversions-2</module>
|
||||||
<module>core-java-collections-set-2</module>
|
<module>core-java-collections-set-2</module>
|
||||||
|
|
|
@ -112,6 +112,18 @@
|
||||||
</exclusion>
|
</exclusion>
|
||||||
</exclusions>
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.httpcomponents.client5</groupId>
|
||||||
|
<artifactId>httpclient5-fluent</artifactId>
|
||||||
|
<version>${httpclient5-fluent.version}</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<artifactId>commons-logging</artifactId>
|
||||||
|
<groupId>commons-logging</groupId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
<!-- utils -->
|
<!-- utils -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.commons</groupId>
|
<groupId>org.apache.commons</groupId>
|
||||||
|
@ -308,6 +320,7 @@
|
||||||
<!-- http client & core 5 -->
|
<!-- http client & core 5 -->
|
||||||
<httpcore5.version>5.2</httpcore5.version>
|
<httpcore5.version>5.2</httpcore5.version>
|
||||||
<httpclient5.version>5.2</httpclient5.version>
|
<httpclient5.version>5.2</httpclient5.version>
|
||||||
|
<httpclient5-fluent.version>5.2</httpclient5-fluent.version>
|
||||||
<!-- maven plugins -->
|
<!-- maven plugins -->
|
||||||
<cargo-maven2-plugin.version>1.6.1</cargo-maven2-plugin.version>
|
<cargo-maven2-plugin.version>1.6.1</cargo-maven2-plugin.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
|
@ -1,74 +1,88 @@
|
||||||
package com.baeldung.httpclient;
|
package com.baeldung.httpclient;
|
||||||
|
|
||||||
import org.apache.http.HttpEntity;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import org.apache.http.HttpResponse;
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
import org.apache.http.NameValuePair;
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
import org.apache.http.auth.AuthenticationException;
|
|
||||||
import org.apache.http.auth.UsernamePasswordCredentials;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.apache.http.client.entity.UrlEncodedFormEntity;
|
|
||||||
import org.apache.http.client.fluent.Form;
|
import org.apache.hc.client5.http.auth.AuthScope;
|
||||||
import org.apache.http.client.fluent.Request;
|
import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
|
||||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
import org.apache.hc.client5.http.classic.methods.HttpPost;
|
||||||
import org.apache.http.client.methods.HttpPost;
|
import org.apache.hc.client5.http.entity.UrlEncodedFormEntity;
|
||||||
import org.apache.http.entity.ContentType;
|
import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder;
|
||||||
import org.apache.http.entity.StringEntity;
|
import org.apache.hc.client5.http.fluent.Form;
|
||||||
import org.apache.http.entity.mime.MultipartEntityBuilder;
|
import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider;
|
||||||
import org.apache.http.impl.auth.BasicScheme;
|
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
|
||||||
import org.apache.http.impl.client.CloseableHttpClient;
|
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
|
||||||
import org.apache.http.impl.client.HttpClients;
|
import org.apache.hc.client5.http.impl.classic.HttpClients;
|
||||||
import org.apache.http.message.BasicNameValuePair;
|
import org.apache.hc.core5.http.ContentType;
|
||||||
import org.junit.Test;
|
import org.apache.hc.core5.http.HttpEntity;
|
||||||
|
import org.apache.hc.core5.http.HttpResponse;
|
||||||
|
import org.apache.hc.core5.http.HttpStatus;
|
||||||
|
import org.apache.hc.core5.http.NameValuePair;
|
||||||
|
import org.apache.hc.client5.http.fluent.Request;
|
||||||
|
import org.apache.hc.core5.http.io.entity.StringEntity;
|
||||||
|
import org.apache.hc.core5.http.message.BasicNameValuePair;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
import com.baeldung.handler.CustomHttpClientResponseHandler;
|
||||||
import static org.junit.Assert.assertFalse;
|
|
||||||
import static org.junit.Assert.assertThat;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* NOTE : Need module spring-rest to be running
|
* NOTE : Need module spring-rest to be running
|
||||||
*/
|
*/
|
||||||
public class HttpClientPostingLiveTest {
|
class HttpClientPostingLiveTest {
|
||||||
private static final String SAMPLE_URL = "http://www.example.com";
|
private static final String SAMPLE_URL = "http://www.example.com";
|
||||||
private static final String URL_SECURED_BY_BASIC_AUTHENTICATION = "http://browserspy.dk/password-ok.php";
|
private static final String URL_SECURED_BY_BASIC_AUTHENTICATION = "http://browserspy.dk/password-ok.php";
|
||||||
private static final String DEFAULT_USER = "test";
|
private static final String DEFAULT_USER = "test";
|
||||||
private static final String DEFAULT_PASS = "test";
|
private static final String DEFAULT_PASS = "test";
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void whenSendPostRequestUsingHttpClient_thenCorrect() throws IOException {
|
void whenSendPostRequestUsingHttpClient_thenCorrect() throws IOException {
|
||||||
final CloseableHttpClient client = HttpClients.createDefault();
|
|
||||||
final HttpPost httpPost = new HttpPost(SAMPLE_URL);
|
final HttpPost httpPost = new HttpPost(SAMPLE_URL);
|
||||||
|
|
||||||
final List<NameValuePair> params = new ArrayList<NameValuePair>();
|
final List<NameValuePair> params = new ArrayList<NameValuePair>();
|
||||||
params.add(new BasicNameValuePair("username", DEFAULT_USER));
|
params.add(new BasicNameValuePair("username", DEFAULT_USER));
|
||||||
params.add(new BasicNameValuePair("password", DEFAULT_PASS));
|
params.add(new BasicNameValuePair("password", DEFAULT_PASS));
|
||||||
httpPost.setEntity(new UrlEncodedFormEntity(params));
|
httpPost.setEntity(new UrlEncodedFormEntity(params));
|
||||||
|
|
||||||
final CloseableHttpResponse response = client.execute(httpPost);
|
try (CloseableHttpClient client = HttpClients.createDefault();
|
||||||
assertThat(response.getStatusLine().getStatusCode(), equalTo(200));
|
CloseableHttpResponse response = (CloseableHttpResponse) client
|
||||||
client.close();
|
.execute(httpPost, new CustomHttpClientResponseHandler())) {
|
||||||
|
|
||||||
|
final int statusCode = response.getCode();
|
||||||
|
assertThat(statusCode, equalTo(HttpStatus.SC_OK));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void whenSendPostRequestWithAuthorizationUsingHttpClient_thenCorrect() throws IOException, AuthenticationException {
|
void whenSendPostRequestWithAuthorizationUsingHttpClient_thenCorrect() throws IOException {
|
||||||
final CloseableHttpClient client = HttpClients.createDefault();
|
|
||||||
final HttpPost httpPost = new HttpPost(URL_SECURED_BY_BASIC_AUTHENTICATION);
|
final HttpPost httpPost = new HttpPost(URL_SECURED_BY_BASIC_AUTHENTICATION);
|
||||||
|
|
||||||
httpPost.setEntity(new StringEntity("test post"));
|
httpPost.setEntity(new StringEntity("test post"));
|
||||||
final UsernamePasswordCredentials creds = new UsernamePasswordCredentials(DEFAULT_USER, DEFAULT_PASS);
|
|
||||||
httpPost.addHeader(new BasicScheme().authenticate(creds, httpPost, null));
|
|
||||||
|
|
||||||
final CloseableHttpResponse response = client.execute(httpPost);
|
final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
|
||||||
assertThat(response.getStatusLine().getStatusCode(), equalTo(200));
|
final UsernamePasswordCredentials credentials =
|
||||||
client.close();
|
new UsernamePasswordCredentials(DEFAULT_USER, DEFAULT_PASS.toCharArray());
|
||||||
|
|
||||||
|
credsProvider.setCredentials(new AuthScope(URL_SECURED_BY_BASIC_AUTHENTICATION, 80) ,credentials);
|
||||||
|
|
||||||
|
try (CloseableHttpClient client = HttpClients.custom()
|
||||||
|
.setDefaultCredentialsProvider(credsProvider)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
CloseableHttpResponse response = (CloseableHttpResponse) client
|
||||||
|
.execute(httpPost, new CustomHttpClientResponseHandler())) {
|
||||||
|
|
||||||
|
final int statusCode = response.getCode();
|
||||||
|
assertThat(statusCode, equalTo(HttpStatus.SC_OK));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void whenPostJsonUsingHttpClient_thenCorrect() throws IOException {
|
void whenPostJsonUsingHttpClient_thenCorrect() throws IOException {
|
||||||
final CloseableHttpClient client = HttpClients.createDefault();
|
|
||||||
final HttpPost httpPost = new HttpPost(SAMPLE_URL);
|
final HttpPost httpPost = new HttpPost(SAMPLE_URL);
|
||||||
|
|
||||||
final String json = "{\"id\":1,\"name\":\"John\"}";
|
final String json = "{\"id\":1,\"name\":\"John\"}";
|
||||||
|
@ -77,68 +91,91 @@ public class HttpClientPostingLiveTest {
|
||||||
httpPost.setHeader("Accept", "application/json");
|
httpPost.setHeader("Accept", "application/json");
|
||||||
httpPost.setHeader("Content-type", "application/json");
|
httpPost.setHeader("Content-type", "application/json");
|
||||||
|
|
||||||
final CloseableHttpResponse response = client.execute(httpPost);
|
try (CloseableHttpClient client = HttpClients.createDefault();
|
||||||
assertThat(response.getStatusLine().getStatusCode(), equalTo(200));
|
CloseableHttpResponse response = (CloseableHttpResponse) client
|
||||||
client.close();
|
.execute(httpPost, new CustomHttpClientResponseHandler())) {
|
||||||
|
|
||||||
|
final int statusCode = response.getCode();
|
||||||
|
assertThat(statusCode, equalTo(HttpStatus.SC_OK));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void whenPostFormUsingHttpClientFluentAPI_thenCorrect() throws IOException {
|
void whenPostFormUsingHttpClientFluentAPI_thenCorrect() throws IOException {
|
||||||
final HttpResponse response = Request.Post(SAMPLE_URL).bodyForm(Form.form().add("username", DEFAULT_USER).add("password", DEFAULT_PASS).build()).execute().returnResponse();
|
Request request = Request.post(SAMPLE_URL)
|
||||||
|
.bodyForm(Form.form()
|
||||||
|
.add("username", DEFAULT_USER)
|
||||||
|
.add("password", DEFAULT_PASS)
|
||||||
|
.build());
|
||||||
|
|
||||||
assertThat(response.getStatusLine().getStatusCode(), equalTo(200));
|
HttpResponse response = request.execute()
|
||||||
|
.returnResponse();
|
||||||
|
assertThat(response.getCode(), equalTo(HttpStatus.SC_OK));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void whenSendMultipartRequestUsingHttpClient_thenCorrect() throws IOException {
|
void whenSendMultipartRequestUsingHttpClient_thenCorrect() throws IOException {
|
||||||
final CloseableHttpClient client = HttpClients.createDefault();
|
|
||||||
final HttpPost httpPost = new HttpPost(SAMPLE_URL);
|
final HttpPost httpPost = new HttpPost(SAMPLE_URL);
|
||||||
|
|
||||||
final MultipartEntityBuilder builder = MultipartEntityBuilder.create();
|
final MultipartEntityBuilder builder = MultipartEntityBuilder.create();
|
||||||
builder.addTextBody("username", DEFAULT_USER);
|
builder.addTextBody("username", DEFAULT_USER);
|
||||||
builder.addTextBody("password", DEFAULT_PASS);
|
builder.addTextBody("password", DEFAULT_PASS);
|
||||||
builder.addBinaryBody("file", new File("src/test/resources/test.in"), ContentType.APPLICATION_OCTET_STREAM, "file.ext");
|
builder.addBinaryBody(
|
||||||
|
"file", new File("src/test/resources/test.in"), ContentType.APPLICATION_OCTET_STREAM, "file.ext");
|
||||||
|
|
||||||
|
final HttpEntity multipart = builder.build();
|
||||||
|
httpPost.setEntity(multipart);
|
||||||
|
|
||||||
|
try (CloseableHttpClient client = HttpClients.createDefault();
|
||||||
|
CloseableHttpResponse response = (CloseableHttpResponse) client
|
||||||
|
.execute(httpPost, new CustomHttpClientResponseHandler())) {
|
||||||
|
|
||||||
|
final int statusCode = response.getCode();
|
||||||
|
assertThat(statusCode, equalTo(HttpStatus.SC_OK));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void whenUploadFileUsingHttpClient_thenCorrect() throws IOException {
|
||||||
|
final HttpPost httpPost = new HttpPost(SAMPLE_URL);
|
||||||
|
|
||||||
|
final MultipartEntityBuilder builder = MultipartEntityBuilder.create();
|
||||||
|
builder.addBinaryBody(
|
||||||
|
"file", new File("src/test/resources/test.in"), ContentType.APPLICATION_OCTET_STREAM, "file.ext");
|
||||||
final HttpEntity multipart = builder.build();
|
final HttpEntity multipart = builder.build();
|
||||||
|
|
||||||
httpPost.setEntity(multipart);
|
httpPost.setEntity(multipart);
|
||||||
|
|
||||||
final CloseableHttpResponse response = client.execute(httpPost);
|
try (CloseableHttpClient client = HttpClients.createDefault();
|
||||||
assertThat(response.getStatusLine().getStatusCode(), equalTo(200));
|
CloseableHttpResponse response = (CloseableHttpResponse) client
|
||||||
client.close();
|
.execute(httpPost, new CustomHttpClientResponseHandler())) {
|
||||||
|
|
||||||
|
final int statusCode = response.getCode();
|
||||||
|
assertThat(statusCode, equalTo(HttpStatus.SC_OK));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void whenUploadFileUsingHttpClient_thenCorrect() throws IOException {
|
void whenGetUploadFileProgressUsingHttpClient_thenCorrect() throws IOException {
|
||||||
final CloseableHttpClient client = HttpClients.createDefault();
|
|
||||||
final HttpPost httpPost = new HttpPost(SAMPLE_URL);
|
final HttpPost httpPost = new HttpPost(SAMPLE_URL);
|
||||||
|
|
||||||
final MultipartEntityBuilder builder = MultipartEntityBuilder.create();
|
final MultipartEntityBuilder builder = MultipartEntityBuilder.create();
|
||||||
builder.addBinaryBody("file", new File("src/test/resources/test.in"), ContentType.APPLICATION_OCTET_STREAM, "file.ext");
|
builder.addBinaryBody(
|
||||||
|
"file", new File("src/test/resources/test.in"), ContentType.APPLICATION_OCTET_STREAM, "file.ext");
|
||||||
final HttpEntity multipart = builder.build();
|
final HttpEntity multipart = builder.build();
|
||||||
|
|
||||||
httpPost.setEntity(multipart);
|
final ProgressEntityWrapper.ProgressListener pListener =
|
||||||
|
percentage -> assertFalse(Float.compare(percentage, 100) > 0);
|
||||||
final CloseableHttpResponse response = client.execute(httpPost);
|
|
||||||
assertThat(response.getStatusLine().getStatusCode(), equalTo(200));
|
|
||||||
client.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void whenGetUploadFileProgressUsingHttpClient_thenCorrect() throws IOException {
|
|
||||||
final CloseableHttpClient client = HttpClients.createDefault();
|
|
||||||
final HttpPost httpPost = new HttpPost(SAMPLE_URL);
|
|
||||||
|
|
||||||
final MultipartEntityBuilder builder = MultipartEntityBuilder.create();
|
|
||||||
builder.addBinaryBody("file", new File("src/test/resources/test.in"), ContentType.APPLICATION_OCTET_STREAM, "file.ext");
|
|
||||||
final HttpEntity multipart = builder.build();
|
|
||||||
|
|
||||||
final ProgressEntityWrapper.ProgressListener pListener = percentage -> assertFalse(Float.compare(percentage, 100) > 0);
|
|
||||||
|
|
||||||
httpPost.setEntity(new ProgressEntityWrapper(multipart, pListener));
|
httpPost.setEntity(new ProgressEntityWrapper(multipart, pListener));
|
||||||
|
|
||||||
final CloseableHttpResponse response = client.execute(httpPost);
|
try (CloseableHttpClient client = HttpClients.createDefault();
|
||||||
assertThat(response.getStatusLine().getStatusCode(), equalTo(200));
|
CloseableHttpResponse response = (CloseableHttpResponse) client
|
||||||
client.close();
|
.execute(httpPost, new CustomHttpClientResponseHandler())) {
|
||||||
|
|
||||||
|
final int statusCode = response.getCode();
|
||||||
|
assertThat(statusCode, equalTo(HttpStatus.SC_OK));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -4,8 +4,8 @@ import java.io.FilterOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
|
||||||
import org.apache.http.HttpEntity;
|
import org.apache.hc.core5.http.HttpEntity;
|
||||||
import org.apache.http.entity.HttpEntityWrapper;
|
import org.apache.hc.core5.http.io.entity.HttpEntityWrapper;
|
||||||
|
|
||||||
public class ProgressEntityWrapper extends HttpEntityWrapper {
|
public class ProgressEntityWrapper extends HttpEntityWrapper {
|
||||||
private final ProgressListener listener;
|
private final ProgressListener listener;
|
||||||
|
|
|
@ -1,118 +1,119 @@
|
||||||
package com.baeldung.httpclient.sec;
|
package com.baeldung.httpclient.sec;
|
||||||
|
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
|
||||||
import org.apache.commons.codec.binary.Base64;
|
import org.apache.commons.codec.binary.Base64;
|
||||||
import org.apache.http.HttpHeaders;
|
|
||||||
import org.apache.http.HttpHost;
|
import com.baeldung.handler.CustomHttpClientResponseHandler;
|
||||||
import org.apache.http.HttpStatus;
|
|
||||||
import org.apache.http.auth.AuthScope;
|
import org.apache.hc.client5.http.auth.AuthScope;
|
||||||
import org.apache.http.auth.UsernamePasswordCredentials;
|
import org.apache.hc.client5.http.auth.AuthCache;
|
||||||
import org.apache.http.client.AuthCache;
|
import org.apache.hc.client5.http.auth.CredentialsProvider;
|
||||||
import org.apache.http.client.CredentialsProvider;
|
import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
|
||||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
import org.apache.hc.client5.http.classic.methods.HttpGet;
|
||||||
import org.apache.http.client.methods.HttpGet;
|
import org.apache.hc.client5.http.impl.auth.BasicAuthCache;
|
||||||
import org.apache.http.client.protocol.HttpClientContext;
|
import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider;
|
||||||
import org.apache.http.impl.auth.BasicScheme;
|
import org.apache.hc.client5.http.impl.auth.BasicScheme;
|
||||||
import org.apache.http.impl.client.BasicAuthCache;
|
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
|
||||||
import org.apache.http.impl.client.BasicCredentialsProvider;
|
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
|
||||||
import org.apache.http.impl.client.CloseableHttpClient;
|
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
|
||||||
import org.apache.http.impl.client.HttpClientBuilder;
|
import org.apache.hc.client5.http.protocol.HttpClientContext;
|
||||||
import org.apache.http.protocol.HttpContext;
|
import org.apache.hc.core5.http.HttpHeaders;
|
||||||
import com.baeldung.httpclient.ResponseUtil;
|
import org.apache.hc.core5.http.HttpHost;
|
||||||
import org.junit.After;
|
import org.apache.hc.core5.http.HttpStatus;
|
||||||
import org.junit.Before;
|
import org.apache.hc.core5.http.protocol.HttpContext;
|
||||||
import org.junit.Test;
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
|
||||||
import static org.junit.Assert.assertThat;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* NOTE : Need module httpclient-simple to be running
|
* NOTE : Need module httpclient-simple to be running
|
||||||
*/
|
*/
|
||||||
|
class HttpClientAuthLiveTest {
|
||||||
public class HttpClientAuthLiveTest {
|
|
||||||
|
|
||||||
private static final String URL_SECURED_BY_BASIC_AUTHENTICATION = "http://localhost:8082/httpclient-simple/api/foos/1";
|
private static final String URL_SECURED_BY_BASIC_AUTHENTICATION = "http://localhost:8082/httpclient-simple/api/foos/1";
|
||||||
private static final String DEFAULT_USER = "user1";
|
private static final String DEFAULT_USER = "user1";
|
||||||
private static final String DEFAULT_PASS = "user1Pass";
|
private static final String DEFAULT_PASS = "user1Pass";
|
||||||
|
private final char[] DEFAULT_PASS_ARRAY = DEFAULT_PASS.toCharArray() ;
|
||||||
private CloseableHttpClient client;
|
|
||||||
|
|
||||||
private CloseableHttpResponse response;
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public final void before() {
|
|
||||||
client = HttpClientBuilder.create().build();
|
|
||||||
}
|
|
||||||
|
|
||||||
@After
|
|
||||||
public final void after() throws IllegalStateException, IOException {
|
|
||||||
ResponseUtil.closeResponse(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
// tests
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public final void whenExecutingBasicGetRequestWithBasicAuthenticationEnabled_thenSuccess() throws IOException {
|
final void whenExecutingBasicGetRequestWithBasicAuthenticationEnabled_thenSuccess() throws IOException {
|
||||||
client = HttpClientBuilder.create().setDefaultCredentialsProvider(provider()).build();
|
final HttpGet request = new HttpGet(URL_SECURED_BY_BASIC_AUTHENTICATION);
|
||||||
|
try (CloseableHttpClient client = HttpClientBuilder.create()
|
||||||
|
.setDefaultCredentialsProvider(provider())
|
||||||
|
.build();
|
||||||
|
|
||||||
response = client.execute(new HttpGet(URL_SECURED_BY_BASIC_AUTHENTICATION));
|
CloseableHttpResponse response = (CloseableHttpResponse) client
|
||||||
|
.execute(request, new CustomHttpClientResponseHandler())) {
|
||||||
final int statusCode = response.getStatusLine().getStatusCode();
|
final int statusCode = response.getCode();
|
||||||
assertThat(statusCode, equalTo(HttpStatus.SC_OK));
|
assertThat(statusCode, equalTo(HttpStatus.SC_OK));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public final void givenAuthenticationIsPreemptive_whenExecutingBasicGetRequestWithBasicAuthenticationEnabled_thenSuccess() throws IOException {
|
|
||||||
client = HttpClientBuilder.create().build();
|
|
||||||
response = client.execute(new HttpGet(URL_SECURED_BY_BASIC_AUTHENTICATION), context());
|
|
||||||
|
|
||||||
final int statusCode = response.getStatusLine().getStatusCode();
|
|
||||||
assertThat(statusCode, equalTo(HttpStatus.SC_OK));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public final void givenAuthorizationHeaderIsSetManually_whenExecutingGetRequest_thenSuccess() throws IOException {
|
final void givenAuthenticationIsPreemptive_whenExecutingBasicGetRequestWithBasicAuthenticationEnabled_thenSuccess() throws IOException {
|
||||||
client = HttpClientBuilder.create().build();
|
final HttpGet request = new HttpGet(URL_SECURED_BY_BASIC_AUTHENTICATION);
|
||||||
|
try (CloseableHttpClient client = HttpClientBuilder.create()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
CloseableHttpResponse response = (CloseableHttpResponse) client
|
||||||
|
.execute(request, context(), new CustomHttpClientResponseHandler())) {
|
||||||
|
final int statusCode = response.getCode();
|
||||||
|
assertThat(statusCode, equalTo(200));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
final void givenAuthorizationHeaderIsSetManually_whenExecutingGetRequest_thenSuccess() throws IOException {
|
||||||
final HttpGet request = new HttpGet(URL_SECURED_BY_BASIC_AUTHENTICATION);
|
final HttpGet request = new HttpGet(URL_SECURED_BY_BASIC_AUTHENTICATION);
|
||||||
request.setHeader(HttpHeaders.AUTHORIZATION, authorizationHeader(DEFAULT_USER, DEFAULT_PASS));
|
request.setHeader(HttpHeaders.AUTHORIZATION, authorizationHeader(DEFAULT_USER, DEFAULT_PASS));
|
||||||
response = client.execute(request);
|
try (CloseableHttpClient client = HttpClientBuilder.create()
|
||||||
|
.build();
|
||||||
|
|
||||||
final int statusCode = response.getStatusLine().getStatusCode();
|
CloseableHttpResponse response = (CloseableHttpResponse) client
|
||||||
|
.execute(request, context(), new CustomHttpClientResponseHandler())) {
|
||||||
|
final int statusCode = response.getCode();
|
||||||
assertThat(statusCode, equalTo(HttpStatus.SC_OK));
|
assertThat(statusCode, equalTo(HttpStatus.SC_OK));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public final void givenAuthorizationHeaderIsSetManually_whenExecutingGetRequest_thenSuccess2() throws IOException {
|
final void givenAuthorizationHeaderIsSetManually_whenExecutingGetRequest_thenSuccess2() throws IOException {
|
||||||
final HttpGet request = new HttpGet(URL_SECURED_BY_BASIC_AUTHENTICATION);
|
final HttpGet request = new HttpGet(URL_SECURED_BY_BASIC_AUTHENTICATION);
|
||||||
final String auth = DEFAULT_USER + ":" + DEFAULT_PASS;
|
final String auth = DEFAULT_USER + ":" + DEFAULT_PASS;
|
||||||
final byte[] encodedAuth = Base64.encodeBase64(auth.getBytes(StandardCharsets.ISO_8859_1));
|
final byte[] encodedAuth = Base64.encodeBase64(auth.getBytes(StandardCharsets.ISO_8859_1));
|
||||||
final String authHeader = "Basic " + new String(encodedAuth);
|
final String authHeader = "Basic " + new String(encodedAuth);
|
||||||
request.setHeader(HttpHeaders.AUTHORIZATION, authHeader);
|
request.setHeader(HttpHeaders.AUTHORIZATION, authHeader);
|
||||||
|
|
||||||
client = HttpClientBuilder.create().build();
|
try (CloseableHttpClient client = HttpClientBuilder.create()
|
||||||
response = client.execute(request);
|
.build();
|
||||||
|
|
||||||
final int statusCode = response.getStatusLine().getStatusCode();
|
CloseableHttpResponse response = (CloseableHttpResponse) client
|
||||||
|
.execute(request, new CustomHttpClientResponseHandler())) {
|
||||||
|
final int statusCode = response.getCode();
|
||||||
assertThat(statusCode, equalTo(HttpStatus.SC_OK));
|
assertThat(statusCode, equalTo(HttpStatus.SC_OK));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// UTILS
|
// UTILS
|
||||||
|
|
||||||
private CredentialsProvider provider() {
|
private CredentialsProvider provider() {
|
||||||
final CredentialsProvider provider = new BasicCredentialsProvider();
|
final HttpHost targetHost = new HttpHost("http", "localhost", 8082);
|
||||||
final UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(DEFAULT_USER, DEFAULT_PASS);
|
final BasicCredentialsProvider provider = new BasicCredentialsProvider();
|
||||||
provider.setCredentials(AuthScope.ANY, credentials);
|
AuthScope authScope = new AuthScope(targetHost);
|
||||||
|
provider.setCredentials(authScope, new UsernamePasswordCredentials(DEFAULT_USER, DEFAULT_PASS_ARRAY));
|
||||||
return provider;
|
return provider;
|
||||||
}
|
}
|
||||||
|
|
||||||
private HttpContext context() {
|
private HttpContext context() {
|
||||||
final HttpHost targetHost = new HttpHost("localhost", 8082, "http");
|
final HttpHost targetHost = new HttpHost("http", "localhost", 8082);
|
||||||
final CredentialsProvider credsProvider = new BasicCredentialsProvider();
|
final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
|
||||||
credsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(DEFAULT_USER, DEFAULT_PASS));
|
AuthScope authScope = new AuthScope(targetHost);
|
||||||
|
credsProvider.setCredentials(authScope, new UsernamePasswordCredentials(DEFAULT_USER, DEFAULT_PASS_ARRAY));
|
||||||
|
|
||||||
// Create AuthCache instance
|
// Create AuthCache instance
|
||||||
final AuthCache authCache = new BasicAuthCache();
|
final AuthCache authCache = new BasicAuthCache();
|
||||||
|
|
|
@ -8,3 +8,4 @@ This module contains articles about Jackson annotations.
|
||||||
- [Jackson – Bidirectional Relationships](https://www.baeldung.com/jackson-bidirectional-relationships-and-infinite-recursion)
|
- [Jackson – Bidirectional Relationships](https://www.baeldung.com/jackson-bidirectional-relationships-and-infinite-recursion)
|
||||||
- [Jackson JSON Views](https://www.baeldung.com/jackson-json-view-annotation)
|
- [Jackson JSON Views](https://www.baeldung.com/jackson-json-view-annotation)
|
||||||
- [Deduction-Based Polymorphism in Jackson 2.12](https://www.baeldung.com/jackson-deduction-based-polymorphism)
|
- [Deduction-Based Polymorphism in Jackson 2.12](https://www.baeldung.com/jackson-deduction-based-polymorphism)
|
||||||
|
- [@JsonIgnore vs @Transient](https://www.baeldung.com/java-jsonignore-vs-transient)
|
||||||
|
|
|
@ -2,3 +2,4 @@
|
||||||
- [Trigger Another Job from a Jenkins Pipeline](https://www.baeldung.com/ops/jenkins-pipeline-trigger-new-job)
|
- [Trigger Another Job from a Jenkins Pipeline](https://www.baeldung.com/ops/jenkins-pipeline-trigger-new-job)
|
||||||
- [Fixing the “No Such DSL method” Error in Jenkins Pipeline](https://www.baeldung.com/ops/jenkins-pipeline-no-such-dsl-method-error)
|
- [Fixing the “No Such DSL method” Error in Jenkins Pipeline](https://www.baeldung.com/ops/jenkins-pipeline-no-such-dsl-method-error)
|
||||||
- [Jenkins Pipeline – Change to Another Folder](https://www.baeldung.com/ops/jenkins-pipeline-change-to-another-folder)
|
- [Jenkins Pipeline – Change to Another Folder](https://www.baeldung.com/ops/jenkins-pipeline-change-to-another-folder)
|
||||||
|
- [How to Stop a Zombie Job on Jenkins Without Restarting the Server?](https://www.baeldung.com/ops/stop-zombie-job-on-jenkins-without-restarting-the-server)
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
pipeline {
|
||||||
|
agent any
|
||||||
|
stages {
|
||||||
|
stage('tryCatch') {
|
||||||
|
steps {
|
||||||
|
script {
|
||||||
|
try {
|
||||||
|
sh 'test_script.sh'
|
||||||
|
} catch (e) {
|
||||||
|
echo "An error occurred: ${e}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,11 +1,15 @@
|
||||||
package com.baeldung.jsonvalidation;
|
package com.baeldung.jsonvalidation;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JacksonException;
|
import com.fasterxml.jackson.core.JacksonException;
|
||||||
|
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.json.JsonMapper;
|
||||||
|
|
||||||
public class JacksonValidator {
|
public class JacksonValidator {
|
||||||
|
|
||||||
final ObjectMapper mapper = new ObjectMapper();
|
final ObjectMapper mapper = JsonMapper.builder()
|
||||||
|
.enable(DeserializationFeature.FAIL_ON_TRAILING_TOKENS)
|
||||||
|
.build();
|
||||||
|
|
||||||
public boolean isValid(String json) {
|
public boolean isValid(String json) {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
## Relevant Articles
|
||||||
|
- [Lightweight Logging With tinylog 2](https://www.baeldung.com/java-logging-tinylog-guide)
|
|
@ -3,3 +3,4 @@
|
||||||
This module contains articles about RestExpress.
|
This module contains articles about RestExpress.
|
||||||
|
|
||||||
### Relevant articles
|
### Relevant articles
|
||||||
|
- [RESTful Microservices With RestExpress](https://www.baeldung.com/java-restexpress-guide)
|
||||||
|
|
|
@ -2,3 +2,4 @@
|
||||||
- [Database Migrations with Flyway](http://www.baeldung.com/database-migrations-with-flyway)
|
- [Database Migrations with Flyway](http://www.baeldung.com/database-migrations-with-flyway)
|
||||||
- [A Guide to Flyway Callbacks](http://www.baeldung.com/flyway-callbacks)
|
- [A Guide to Flyway Callbacks](http://www.baeldung.com/flyway-callbacks)
|
||||||
- [Rolling Back Migrations with Flyway](https://www.baeldung.com/flyway-roll-back)
|
- [Rolling Back Migrations with Flyway](https://www.baeldung.com/flyway-roll-back)
|
||||||
|
- [Flyway Out of Order Migrations](https://www.baeldung.com/flyway-migrations)
|
||||||
|
|
|
@ -6,17 +6,17 @@ import org.springframework.context.annotation.ComponentScan;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.data.elasticsearch.client.ClientConfiguration;
|
import org.springframework.data.elasticsearch.client.ClientConfiguration;
|
||||||
import org.springframework.data.elasticsearch.client.RestClients;
|
import org.springframework.data.elasticsearch.client.RestClients;
|
||||||
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
import org.springframework.data.elasticsearch.config.AbstractElasticsearchConfiguration;
|
||||||
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
|
|
||||||
import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;
|
import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableElasticsearchRepositories(basePackages = "com.baeldung.spring.data.es.repository")
|
@EnableElasticsearchRepositories(basePackages = "com.baeldung.spring.data.es.repository")
|
||||||
@ComponentScan(basePackages = { "com.baeldung.spring.data.es.service" })
|
@ComponentScan(basePackages = { "com.baeldung.spring.data.es.service" })
|
||||||
public class Config {
|
public class Config extends AbstractElasticsearchConfiguration {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
RestHighLevelClient client() {
|
@Override
|
||||||
|
public RestHighLevelClient elasticsearchClient() {
|
||||||
ClientConfiguration clientConfiguration = ClientConfiguration.builder()
|
ClientConfiguration clientConfiguration = ClientConfiguration.builder()
|
||||||
.connectedTo("localhost:9200")
|
.connectedTo("localhost:9200")
|
||||||
.build();
|
.build();
|
||||||
|
@ -24,9 +24,4 @@ public class Config {
|
||||||
return RestClients.create(clientConfiguration)
|
return RestClients.create(clientConfiguration)
|
||||||
.rest();
|
.rest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
|
||||||
public ElasticsearchOperations elasticsearchTemplate() {
|
|
||||||
return new ElasticsearchRestTemplate(client());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ import org.junit.runner.RunWith;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.data.domain.PageRequest;
|
import org.springframework.data.domain.PageRequest;
|
||||||
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
|
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
||||||
import org.springframework.data.elasticsearch.core.SearchHits;
|
import org.springframework.data.elasticsearch.core.SearchHits;
|
||||||
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||||
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
|
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
|
||||||
|
@ -41,7 +41,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||||
public class ElasticSearchManualTest {
|
public class ElasticSearchManualTest {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ElasticsearchRestTemplate elasticsearchTemplate;
|
private ElasticsearchOperations elasticsearchOperations;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ArticleRepository articleRepository;
|
private ArticleRepository articleRepository;
|
||||||
|
@ -117,7 +117,7 @@ public class ElasticSearchManualTest {
|
||||||
final Query searchQuery = new NativeSearchQueryBuilder().withFilter(regexpQuery("title", ".*data.*"))
|
final Query searchQuery = new NativeSearchQueryBuilder().withFilter(regexpQuery("title", ".*data.*"))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
final SearchHits<Article> articles = elasticsearchTemplate.search(searchQuery, Article.class, IndexCoordinates.of("blog"));
|
final SearchHits<Article> articles = elasticsearchOperations.search(searchQuery, Article.class, IndexCoordinates.of("blog"));
|
||||||
|
|
||||||
assertEquals(1, articles.getTotalHits());
|
assertEquals(1, articles.getTotalHits());
|
||||||
}
|
}
|
||||||
|
@ -126,7 +126,7 @@ public class ElasticSearchManualTest {
|
||||||
public void givenSavedDoc_whenTitleUpdated_thenCouldFindByUpdatedTitle() {
|
public void givenSavedDoc_whenTitleUpdated_thenCouldFindByUpdatedTitle() {
|
||||||
final Query searchQuery = new NativeSearchQueryBuilder().withQuery(fuzzyQuery("title", "serch"))
|
final Query searchQuery = new NativeSearchQueryBuilder().withQuery(fuzzyQuery("title", "serch"))
|
||||||
.build();
|
.build();
|
||||||
final SearchHits<Article> articles = elasticsearchTemplate.search(searchQuery, Article.class, IndexCoordinates.of("blog"));
|
final SearchHits<Article> articles = elasticsearchOperations.search(searchQuery, Article.class, IndexCoordinates.of("blog"));
|
||||||
|
|
||||||
assertEquals(1, articles.getTotalHits());
|
assertEquals(1, articles.getTotalHits());
|
||||||
|
|
||||||
|
@ -147,7 +147,7 @@ public class ElasticSearchManualTest {
|
||||||
|
|
||||||
final Query searchQuery = new NativeSearchQueryBuilder().withQuery(matchQuery("title", articleTitle).minimumShouldMatch("75%"))
|
final Query searchQuery = new NativeSearchQueryBuilder().withQuery(matchQuery("title", articleTitle).minimumShouldMatch("75%"))
|
||||||
.build();
|
.build();
|
||||||
final SearchHits<Article> articles = elasticsearchTemplate.search(searchQuery, Article.class, IndexCoordinates.of("blog"));
|
final SearchHits<Article> articles = elasticsearchOperations.search(searchQuery, Article.class, IndexCoordinates.of("blog"));
|
||||||
|
|
||||||
assertEquals(1, articles.getTotalHits());
|
assertEquals(1, articles.getTotalHits());
|
||||||
final long count = articleRepository.count();
|
final long count = articleRepository.count();
|
||||||
|
@ -162,7 +162,7 @@ public class ElasticSearchManualTest {
|
||||||
public void givenSavedDoc_whenOneTermMatches_thenFindByTitle() {
|
public void givenSavedDoc_whenOneTermMatches_thenFindByTitle() {
|
||||||
final Query searchQuery = new NativeSearchQueryBuilder().withQuery(matchQuery("title", "Search engines").operator(AND))
|
final Query searchQuery = new NativeSearchQueryBuilder().withQuery(matchQuery("title", "Search engines").operator(AND))
|
||||||
.build();
|
.build();
|
||||||
final SearchHits<Article> articles = elasticsearchTemplate.search(searchQuery, Article.class, IndexCoordinates.of("blog"));
|
final SearchHits<Article> articles = elasticsearchOperations.search(searchQuery, Article.class, IndexCoordinates.of("blog"));
|
||||||
assertEquals(1, articles.getTotalHits());
|
assertEquals(1, articles.getTotalHits());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
|
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
||||||
import org.springframework.data.elasticsearch.core.SearchHits;
|
import org.springframework.data.elasticsearch.core.SearchHits;
|
||||||
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||||
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
|
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
|
||||||
|
@ -58,7 +58,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||||
public class ElasticSearchQueryManualTest {
|
public class ElasticSearchQueryManualTest {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ElasticsearchRestTemplate elasticsearchTemplate;
|
private ElasticsearchOperations elasticsearchOperations;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ArticleRepository articleRepository;
|
private ArticleRepository articleRepository;
|
||||||
|
@ -101,7 +101,7 @@ public class ElasticSearchQueryManualTest {
|
||||||
public void givenFullTitle_whenRunMatchQuery_thenDocIsFound() {
|
public void givenFullTitle_whenRunMatchQuery_thenDocIsFound() {
|
||||||
final NativeSearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchQuery("title", "Search engines").operator(Operator.AND))
|
final NativeSearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchQuery("title", "Search engines").operator(Operator.AND))
|
||||||
.build();
|
.build();
|
||||||
final SearchHits<Article> articles = elasticsearchTemplate.search(searchQuery, Article.class, IndexCoordinates.of("blog"));
|
final SearchHits<Article> articles = elasticsearchOperations.search(searchQuery, Article.class, IndexCoordinates.of("blog"));
|
||||||
assertEquals(1, articles.getTotalHits());
|
assertEquals(1, articles.getTotalHits());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,7 +110,7 @@ public class ElasticSearchQueryManualTest {
|
||||||
final NativeSearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchQuery("title", "Engines Solutions"))
|
final NativeSearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchQuery("title", "Engines Solutions"))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
final SearchHits<Article> articles = elasticsearchTemplate.search(searchQuery, Article.class, IndexCoordinates.of("blog"));
|
final SearchHits<Article> articles = elasticsearchOperations.search(searchQuery, Article.class, IndexCoordinates.of("blog"));
|
||||||
|
|
||||||
assertEquals(1, articles.getTotalHits());
|
assertEquals(1, articles.getTotalHits());
|
||||||
assertEquals("Search engines", articles.getSearchHit(0)
|
assertEquals("Search engines", articles.getSearchHit(0)
|
||||||
|
@ -123,7 +123,7 @@ public class ElasticSearchQueryManualTest {
|
||||||
final NativeSearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchQuery("title", "elasticsearch data"))
|
final NativeSearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchQuery("title", "elasticsearch data"))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
final SearchHits<Article> articles = elasticsearchTemplate.search(searchQuery, Article.class, IndexCoordinates.of("blog"));
|
final SearchHits<Article> articles = elasticsearchOperations.search(searchQuery, Article.class, IndexCoordinates.of("blog"));
|
||||||
|
|
||||||
assertEquals(3, articles.getTotalHits());
|
assertEquals(3, articles.getTotalHits());
|
||||||
}
|
}
|
||||||
|
@ -133,14 +133,14 @@ public class ElasticSearchQueryManualTest {
|
||||||
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchQuery("title.verbatim", "Second Article About Elasticsearch"))
|
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchQuery("title.verbatim", "Second Article About Elasticsearch"))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
SearchHits<Article> articles = elasticsearchTemplate.search(searchQuery, Article.class, IndexCoordinates.of("blog"));
|
SearchHits<Article> articles = elasticsearchOperations.search(searchQuery, Article.class, IndexCoordinates.of("blog"));
|
||||||
|
|
||||||
assertEquals(1, articles.getTotalHits());
|
assertEquals(1, articles.getTotalHits());
|
||||||
|
|
||||||
searchQuery = new NativeSearchQueryBuilder().withQuery(matchQuery("title.verbatim", "Second Article About"))
|
searchQuery = new NativeSearchQueryBuilder().withQuery(matchQuery("title.verbatim", "Second Article About"))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
articles = elasticsearchTemplate.search(searchQuery, Article.class, IndexCoordinates.of("blog"));
|
articles = elasticsearchOperations.search(searchQuery, Article.class, IndexCoordinates.of("blog"));
|
||||||
assertEquals(0, articles.getTotalHits());
|
assertEquals(0, articles.getTotalHits());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,7 +150,7 @@ public class ElasticSearchQueryManualTest {
|
||||||
|
|
||||||
final NativeSearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(builder)
|
final NativeSearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(builder)
|
||||||
.build();
|
.build();
|
||||||
final SearchHits<Article> articles = elasticsearchTemplate.search(searchQuery, Article.class, IndexCoordinates.of("blog"));
|
final SearchHits<Article> articles = elasticsearchOperations.search(searchQuery, Article.class, IndexCoordinates.of("blog"));
|
||||||
|
|
||||||
assertEquals(2, articles.getTotalHits());
|
assertEquals(2, articles.getTotalHits());
|
||||||
}
|
}
|
||||||
|
@ -205,7 +205,7 @@ public class ElasticSearchQueryManualTest {
|
||||||
final NativeSearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchPhraseQuery("title", "spring elasticsearch").slop(1))
|
final NativeSearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchPhraseQuery("title", "spring elasticsearch").slop(1))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
final SearchHits<Article> articles = elasticsearchTemplate.search(searchQuery, Article.class, IndexCoordinates.of("blog"));
|
final SearchHits<Article> articles = elasticsearchOperations.search(searchQuery, Article.class, IndexCoordinates.of("blog"));
|
||||||
|
|
||||||
assertEquals(1, articles.getTotalHits());
|
assertEquals(1, articles.getTotalHits());
|
||||||
}
|
}
|
||||||
|
@ -217,7 +217,7 @@ public class ElasticSearchQueryManualTest {
|
||||||
.prefixLength(3))
|
.prefixLength(3))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
final SearchHits<Article> articles = elasticsearchTemplate.search(searchQuery, Article.class, IndexCoordinates.of("blog"));
|
final SearchHits<Article> articles = elasticsearchOperations.search(searchQuery, Article.class, IndexCoordinates.of("blog"));
|
||||||
|
|
||||||
assertEquals(1, articles.getTotalHits());
|
assertEquals(1, articles.getTotalHits());
|
||||||
}
|
}
|
||||||
|
@ -229,7 +229,7 @@ public class ElasticSearchQueryManualTest {
|
||||||
.type(MultiMatchQueryBuilder.Type.BEST_FIELDS))
|
.type(MultiMatchQueryBuilder.Type.BEST_FIELDS))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
final SearchHits<Article> articles = elasticsearchTemplate.search(searchQuery, Article.class, IndexCoordinates.of("blog"));
|
final SearchHits<Article> articles = elasticsearchOperations.search(searchQuery, Article.class, IndexCoordinates.of("blog"));
|
||||||
|
|
||||||
assertEquals(2, articles.getTotalHits());
|
assertEquals(2, articles.getTotalHits());
|
||||||
}
|
}
|
||||||
|
@ -241,7 +241,7 @@ public class ElasticSearchQueryManualTest {
|
||||||
|
|
||||||
final NativeSearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(builder)
|
final NativeSearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(builder)
|
||||||
.build();
|
.build();
|
||||||
final SearchHits<Article> articles = elasticsearchTemplate.search(searchQuery, Article.class, IndexCoordinates.of("blog"));
|
final SearchHits<Article> articles = elasticsearchOperations.search(searchQuery, Article.class, IndexCoordinates.of("blog"));
|
||||||
|
|
||||||
assertEquals(2, articles.getTotalHits());
|
assertEquals(2, articles.getTotalHits());
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,4 +7,5 @@
|
||||||
- [LIKE Queries in Spring JPA Repositories](https://www.baeldung.com/spring-jpa-like-queries)
|
- [LIKE Queries in Spring JPA Repositories](https://www.baeldung.com/spring-jpa-like-queries)
|
||||||
- [How to Access EntityManager with Spring Data](https://www.baeldung.com/spring-data-entitymanager)
|
- [How to Access EntityManager with Spring Data](https://www.baeldung.com/spring-data-entitymanager)
|
||||||
- [Difference Between JPA and Spring Data JPA](https://www.baeldung.com/spring-data-jpa-vs-jpa)
|
- [Difference Between JPA and Spring Data JPA](https://www.baeldung.com/spring-data-jpa-vs-jpa)
|
||||||
|
- [Differences Between Spring Data JPA findFirst() and findTop()](https://www.baeldung.com/spring-data-jpa-findfirst-vs-findtop)
|
||||||
- More articles: [[<-- prev]](../spring-data-jpa-repo)
|
- More articles: [[<-- prev]](../spring-data-jpa-repo)
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
package com.baeldung.spring.data.persistence.search;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.GenerationType;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
public class Student {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||||
|
private long id;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
private int score;
|
||||||
|
|
||||||
|
public Student() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Student(String name, int score) {
|
||||||
|
|
||||||
|
this.name = name;
|
||||||
|
this.score = score;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 int getScore() {
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setScore(int score) {
|
||||||
|
this.score = score;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Student [id=" + id + ", name=" + name + ", score=" + score + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(id, name, score);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj)
|
||||||
|
return true;
|
||||||
|
if (obj == null)
|
||||||
|
return false;
|
||||||
|
if (getClass() != obj.getClass())
|
||||||
|
return false;
|
||||||
|
Student other = (Student) obj;
|
||||||
|
return id == other.id && Objects.equals(name, other.name) && score == other.score;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
package com.baeldung.spring.data.persistence.search;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
public class StudentApplication {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(StudentApplication.class);
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(StudentApplication.class, args);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
package com.baeldung.spring.data.persistence.search;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.springframework.data.domain.Sort;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface StudentRepository extends JpaRepository<Student, Long> {
|
||||||
|
|
||||||
|
Student findFirstByOrderByScoreDesc();
|
||||||
|
|
||||||
|
Student findFirstBy(Sort sort);
|
||||||
|
|
||||||
|
Student findFirstByNameLike(String name, Sort sort);
|
||||||
|
|
||||||
|
List<Student> findFirst3ByOrderByScoreDesc();
|
||||||
|
|
||||||
|
List<Student> findFirst2ByScoreBetween(int startScore, int endScore, Sort sort);
|
||||||
|
|
||||||
|
Student findTopByOrderByScoreDesc();
|
||||||
|
|
||||||
|
Student findTopBy(Sort sort);
|
||||||
|
|
||||||
|
Student findTopByNameLike(String name, Sort sort);
|
||||||
|
|
||||||
|
List<Student> findTop3ByOrderByScoreDesc();
|
||||||
|
|
||||||
|
List<Student> findTop2ByScoreBetween(int startScore, int endScore, Sort sort);
|
||||||
|
}
|
|
@ -3,3 +3,4 @@ spring.datasource.username=sa
|
||||||
spring.datasource.password=sa
|
spring.datasource.password=sa
|
||||||
|
|
||||||
spring.jpa.properties.hibernate.globally_quoted_identifiers=true
|
spring.jpa.properties.hibernate.globally_quoted_identifiers=true
|
||||||
|
logging.level.com.baeldung.spring.data.persistence.search=debug
|
|
@ -0,0 +1,100 @@
|
||||||
|
package com.baeldung.spring.data.persistence.search;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
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.data.domain.Sort;
|
||||||
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
|
||||||
|
@RunWith(SpringRunner.class)
|
||||||
|
@SpringBootTest
|
||||||
|
public class StudentApplicationUnitTest {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private StudentRepository studentRepo;
|
||||||
|
private List<Student> students;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void fillData() {
|
||||||
|
students = new ArrayList<>();
|
||||||
|
int count = 10;
|
||||||
|
Random r = new Random();
|
||||||
|
List<Integer> scores = r.ints(0, 101)
|
||||||
|
.distinct()
|
||||||
|
.limit(count)
|
||||||
|
.boxed()
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
Integer score = scores.get(i);
|
||||||
|
Student s = new Student("Student-" + i, score);
|
||||||
|
students.add(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
studentRepo.saveAll(students);
|
||||||
|
Comparator<Student> c = Comparator.comparing(a -> a.getScore());
|
||||||
|
c = c.reversed();
|
||||||
|
students.sort(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void clearData() {
|
||||||
|
studentRepo.deleteAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenStudentScores_whenMoreThanOne_thenFindFirst() {
|
||||||
|
|
||||||
|
Student student = studentRepo.findFirstByOrderByScoreDesc();
|
||||||
|
Student s = students.get(0);
|
||||||
|
assertEquals(student, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenStudentScores_whenMoreThan3_thenFindFirstThree() {
|
||||||
|
|
||||||
|
List<Student> firstThree = studentRepo.findFirst3ByOrderByScoreDesc();
|
||||||
|
List<Student> sList = students.subList(0, 3);
|
||||||
|
assertArrayEquals(firstThree.toArray(), sList.toArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenStudentScores_whenNameMatches_thenFindFirstStudent() {
|
||||||
|
|
||||||
|
String matchString = "3";
|
||||||
|
Student student = studentRepo.findFirstByNameLike("%" + matchString + "%", Sort.by("score")
|
||||||
|
.descending());
|
||||||
|
Student s = students.stream()
|
||||||
|
.filter(a -> a.getName()
|
||||||
|
.contains(matchString))
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
assertEquals(student, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenStudentScores_whenBetweenRange_thenFindFirstTwoStudents() {
|
||||||
|
|
||||||
|
List<Student> topTwoBetweenRange = studentRepo.findFirst2ByScoreBetween(50, 60, Sort.by("score")
|
||||||
|
.descending());
|
||||||
|
List<Student> _students = students.stream()
|
||||||
|
.filter(a -> a.getScore() >= 50 && a.getScore() <= 60)
|
||||||
|
.limit(2)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
assertArrayEquals(_students.toArray(), topTwoBetweenRange.toArray());
|
||||||
|
}
|
||||||
|
}
|
1
pom.xml
1
pom.xml
|
@ -1133,6 +1133,7 @@
|
||||||
<!-- <module>core-java-modules/core-java-19</module> --> <!-- uses preview features, to be decided how to handle -->
|
<!-- <module>core-java-modules/core-java-19</module> --> <!-- uses preview features, to be decided how to handle -->
|
||||||
<module>core-java-modules/core-java-collections-set</module>
|
<module>core-java-modules/core-java-collections-set</module>
|
||||||
<module>core-java-modules/core-java-collections-list-4</module>
|
<module>core-java-modules/core-java-collections-list-4</module>
|
||||||
|
<module>core-java-modules/core-java-collections-array-list</module>
|
||||||
<module>core-java-modules/core-java-collections-maps-4</module>
|
<module>core-java-modules/core-java-collections-maps-4</module>
|
||||||
<module>core-java-modules/core-java-collections-maps-5</module>
|
<module>core-java-modules/core-java-collections-maps-5</module>
|
||||||
<module>core-java-modules/core-java-concurrency-simple</module>
|
<module>core-java-modules/core-java-concurrency-simple</module>
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
## Spring Boot Keycloak
|
||||||
|
|
||||||
|
This module contains articles about Keycloak in Spring Boot projects.
|
||||||
|
|
||||||
|
## Relevant articles:
|
||||||
|
- [Custom User Attributes with Keycloak](https://www.baeldung.com/keycloak-custom-user-attributes)
|
||||||
|
- [Get Keycloak User ID in Spring](https://www.baeldung.com/spring-keycloak-get-user-id)
|
|
@ -0,0 +1,91 @@
|
||||||
|
<?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.keycloak</groupId>
|
||||||
|
<artifactId>spring-boot-keycloak-adapters</artifactId>
|
||||||
|
<version>0.0.1</version>
|
||||||
|
<name>spring-boot-keycloak-adapters</name>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
<description>This is a simple application demonstrating integration between Keycloak and Spring Boot.</description>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>com.baeldung</groupId>
|
||||||
|
<artifactId>parent-boot-2</artifactId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
<relativePath>../../parent-boot-2</relativePath>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<dependencyManagement>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak.bom</groupId>
|
||||||
|
<artifactId>keycloak-adapter-bom</artifactId>
|
||||||
|
<version>${keycloak-adapter-bom.version}</version>
|
||||||
|
<type>pom</type>
|
||||||
|
<scope>import</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</dependencyManagement>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-spring-boot-starter</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-oauth2-client</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<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.hsqldb</groupId>
|
||||||
|
<artifactId>hsqldb</artifactId>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.security</groupId>
|
||||||
|
<artifactId>spring-security-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<keycloak-adapter-bom.version>15.0.2</keycloak-adapter-bom.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
</project>
|
|
@ -0,0 +1,49 @@
|
||||||
|
package com.baeldung.keycloak;
|
||||||
|
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.GenerationType;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
public class Customer {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private long id;
|
||||||
|
private String name;
|
||||||
|
private String serviceRendered;
|
||||||
|
private String address;
|
||||||
|
|
||||||
|
public long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getServiceRendered() {
|
||||||
|
return serviceRendered;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setServiceRendered(String serviceRendered) {
|
||||||
|
this.serviceRendered = serviceRendered;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAddress() {
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAddress(String address) {
|
||||||
|
this.address = address;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package com.baeldung.keycloak;
|
||||||
|
|
||||||
|
import org.springframework.data.repository.CrudRepository;
|
||||||
|
|
||||||
|
public interface CustomerDAO extends CrudRepository<Customer, Long> {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
package com.baeldung.keycloak;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
|
||||||
|
import org.springframework.security.web.authentication.logout.LogoutHandler;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
import org.springframework.web.util.UriComponentsBuilder;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class KeycloakLogoutHandler implements LogoutHandler {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(KeycloakLogoutHandler.class);
|
||||||
|
private final RestTemplate restTemplate;
|
||||||
|
|
||||||
|
public KeycloakLogoutHandler(RestTemplate restTemplate) {
|
||||||
|
this.restTemplate = restTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void logout(HttpServletRequest request, HttpServletResponse response, Authentication auth) {
|
||||||
|
logoutFromKeycloak((OidcUser) auth.getPrincipal());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void logoutFromKeycloak(OidcUser user) {
|
||||||
|
String endSessionEndpoint = user.getIssuer() + "/protocol/openid-connect/logout";
|
||||||
|
UriComponentsBuilder builder = UriComponentsBuilder
|
||||||
|
.fromUriString(endSessionEndpoint)
|
||||||
|
.queryParam("id_token_hint", user.getIdToken().getTokenValue());
|
||||||
|
|
||||||
|
ResponseEntity<String> logoutResponse = restTemplate.getForEntity(builder.toUriString(), String.class);
|
||||||
|
if (logoutResponse.getStatusCode().is2xxSuccessful()) {
|
||||||
|
logger.info("Successfulley logged out from Keycloak");
|
||||||
|
} else {
|
||||||
|
logger.error("Could not propagate logout to Keycloak");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
package com.baeldung.keycloak;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||||
|
import org.springframework.security.core.session.SessionRegistryImpl;
|
||||||
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
|
import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
|
||||||
|
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableWebSecurity
|
||||||
|
class SecurityConfig {
|
||||||
|
|
||||||
|
private final KeycloakLogoutHandler keycloakLogoutHandler;
|
||||||
|
|
||||||
|
SecurityConfig(KeycloakLogoutHandler keycloakLogoutHandler) {
|
||||||
|
this.keycloakLogoutHandler = keycloakLogoutHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
|
||||||
|
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||||
|
http.authorizeRequests()
|
||||||
|
.antMatchers("/customers*", "/users*")
|
||||||
|
.hasRole("USER")
|
||||||
|
.anyRequest()
|
||||||
|
.permitAll();
|
||||||
|
http.oauth2Login()
|
||||||
|
.and()
|
||||||
|
.logout()
|
||||||
|
.addLogoutHandler(keycloakLogoutHandler)
|
||||||
|
.logoutSuccessUrl("/");
|
||||||
|
return http.build();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
package com.baeldung.keycloak;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
|
||||||
|
public class SpringBoot {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(SpringBoot.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public RestTemplate restTemplate() {
|
||||||
|
return new RestTemplate();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
package com.baeldung.keycloak;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.ui.Model;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
|
||||||
|
import java.security.Principal;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
@Controller
|
||||||
|
public class WebController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private CustomerDAO customerDAO;
|
||||||
|
|
||||||
|
@GetMapping(path = "/")
|
||||||
|
public String index() {
|
||||||
|
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();
|
||||||
|
Iterable<Customer> customers = customerDAO.findAll();
|
||||||
|
model.addAttribute("customers", customers);
|
||||||
|
model.addAttribute("username", principal.getName());
|
||||||
|
return "customers";
|
||||||
|
}
|
||||||
|
|
||||||
|
// add customers for demonstration
|
||||||
|
public void addCustomers() {
|
||||||
|
|
||||||
|
Customer customer1 = new Customer();
|
||||||
|
customer1.setAddress("1111 foo blvd");
|
||||||
|
customer1.setName("Foo Industries");
|
||||||
|
customer1.setServiceRendered("Important services");
|
||||||
|
customerDAO.save(customer1);
|
||||||
|
|
||||||
|
Customer customer2 = new Customer();
|
||||||
|
customer2.setAddress("2222 bar street");
|
||||||
|
customer2.setName("Bar LLP");
|
||||||
|
customer2.setServiceRendered("Important services");
|
||||||
|
customerDAO.save(customer2);
|
||||||
|
|
||||||
|
Customer customer3 = new Customer();
|
||||||
|
customer3.setAddress("33 main street");
|
||||||
|
customer3.setName("Big LLC");
|
||||||
|
customer3.setServiceRendered("Important services");
|
||||||
|
customerDAO.save(customer3);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
### server port
|
||||||
|
server.port=8081
|
||||||
|
|
||||||
|
#Keycloak Configuration
|
||||||
|
keycloak.auth-server-url=http://localhost:8180/auth
|
||||||
|
keycloak.realm=SpringBootKeycloak
|
||||||
|
keycloak.resource=login-app
|
||||||
|
keycloak.public-client=true
|
||||||
|
keycloak.principal-attribute=preferred_username
|
||||||
|
|
||||||
|
spring.security.oauth2.client.registration.keycloak.client-id=login-app
|
||||||
|
spring.security.oauth2.client.registration.keycloak.authorization-grant-type=authorization_code
|
||||||
|
spring.security.oauth2.client.registration.keycloak.scope=openid
|
||||||
|
spring.security.oauth2.client.provider.keycloak.issuer-uri=http://localhost:8180/auth/realms/SpringBootKeycloak
|
||||||
|
spring.security.oauth2.client.provider.keycloak.user-name-attribute=preferred_username
|
|
@ -0,0 +1,13 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<configuration>
|
||||||
|
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
|
<encoder>
|
||||||
|
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
|
||||||
|
</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<root level="INFO">
|
||||||
|
<appender-ref ref="STDOUT" />
|
||||||
|
</root>
|
||||||
|
</configuration>
|
|
@ -0,0 +1,34 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html xmlns:th="http://www.thymeleaf.org">
|
||||||
|
<head th:include="layout :: headerFragment">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="container">
|
||||||
|
<h1>
|
||||||
|
Hello, <span th:text="${username}">--name--</span>.
|
||||||
|
</h1>
|
||||||
|
<table class="table table-striped">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>ID</th>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Address</th>
|
||||||
|
<th>Service Rendered</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr th:each="customer : ${customers}">
|
||||||
|
<td th:text="${customer.id}">Text ...</td>
|
||||||
|
<td th:text="${customer.name}">Text ...</td>
|
||||||
|
<td th:text="${customer.address}">Text ...</td>
|
||||||
|
<td th:text="${customer.serviceRendered}">Text...</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<div id="pagefoot" th:include="layout :: footerFragment">Footer
|
||||||
|
</div>
|
||||||
|
<a href="/logout">Logout</a>
|
||||||
|
</div>
|
||||||
|
<!-- container -->
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,31 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html xmlns:th="http://www.thymeleaf.org">
|
||||||
|
<head th:include="layout :: headerFragment">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<div class="jumbotron text-center">
|
||||||
|
<h1>Customer Portal</h1>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam
|
||||||
|
erat lectus, vehicula feugiat ultricies at, tempus sed ante. Cras
|
||||||
|
arcu erat, lobortis vitae quam et, mollis pharetra odio. Nullam sit
|
||||||
|
amet congue ipsum. Nunc dapibus odio ut ligula venenatis porta non
|
||||||
|
id dui. Duis nec tempor tellus. Suspendisse id blandit ligula, sit
|
||||||
|
amet varius mauris. Nulla eu eros pharetra, tristique dui quis,
|
||||||
|
vehicula libero. Aenean a neque sit amet tellus porttitor rutrum nec
|
||||||
|
at leo.</p>
|
||||||
|
|
||||||
|
<h2>Existing Customers</h2>
|
||||||
|
<div class="well">
|
||||||
|
<b>Enter the intranet: </b><a th:href="@{/customers}">customers</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="pagefoot" th:include="layout :: footerFragment">Footer
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- container -->
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,18 @@
|
||||||
|
|
||||||
|
<head th:fragment="headerFragment">
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||||
|
<title>Customer Portal</title>
|
||||||
|
<link
|
||||||
|
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
|
||||||
|
rel="stylesheet"
|
||||||
|
integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u"
|
||||||
|
crossorigin="anonymous"></link>
|
||||||
|
<link
|
||||||
|
href="https://cdn.datatables.net/1.10.16/css/jquery.dataTables.min.css"
|
||||||
|
rel="stylesheet"></link>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<div id="pagefoot" th:fragment="footerFragment">
|
||||||
|
<p>Document last modified 2017/10/23.</p>
|
||||||
|
<p>Copyright: Lorem Ipsum</p>
|
||||||
|
</div>
|
|
@ -4,9 +4,8 @@ This module contains articles about Keycloak in Spring Boot projects.
|
||||||
|
|
||||||
## Relevant articles:
|
## Relevant articles:
|
||||||
- [A Quick Guide to Using Keycloak With Spring Boot](https://www.baeldung.com/spring-boot-keycloak)
|
- [A Quick Guide to Using Keycloak With Spring Boot](https://www.baeldung.com/spring-boot-keycloak)
|
||||||
- [Custom User Attributes with Keycloak](https://www.baeldung.com/keycloak-custom-user-attributes)
|
|
||||||
- [Customizing the Login Page for Keycloak](https://www.baeldung.com/keycloak-custom-login-page)
|
- [Customizing the Login Page for Keycloak](https://www.baeldung.com/keycloak-custom-login-page)
|
||||||
- [Keycloak User Self-Registration](https://www.baeldung.com/keycloak-user-registration)
|
- [Keycloak User Self-Registration](https://www.baeldung.com/keycloak-user-registration)
|
||||||
- [Customizing Themes for Keycloak](https://www.baeldung.com/spring-keycloak-custom-themes)
|
- [Customizing Themes for Keycloak](https://www.baeldung.com/spring-keycloak-custom-themes)
|
||||||
- [Securing SOAP Web Services With Keycloak](https://www.baeldung.com/soap-keycloak)
|
- [Securing SOAP Web Services With Keycloak](https://www.baeldung.com/soap-keycloak)
|
||||||
- [Get Keycloak User ID in Spring](https://www.baeldung.com/spring-keycloak-get-user-id)
|
|
||||||
|
|
|
@ -17,26 +17,14 @@
|
||||||
<relativePath>../../parent-boot-2</relativePath>
|
<relativePath>../../parent-boot-2</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<dependencyManagement>
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.keycloak.bom</groupId>
|
|
||||||
<artifactId>keycloak-adapter-bom</artifactId>
|
|
||||||
<version>${keycloak-adapter-bom.version}</version>
|
|
||||||
<type>pom</type>
|
|
||||||
<scope>import</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
</dependencyManagement>
|
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter</artifactId>
|
<artifactId>spring-boot-starter</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>keycloak-spring-boot-starter</artifactId>
|
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
@ -113,8 +101,4 @@
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
<properties>
|
|
||||||
<keycloak-adapter-bom.version>15.0.2</keycloak-adapter-bom.version>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
</project>
|
</project>
|
|
@ -2,8 +2,11 @@ package com.baeldung.keycloak;
|
||||||
|
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
|
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer;
|
||||||
import org.springframework.security.core.session.SessionRegistryImpl;
|
import org.springframework.security.core.session.SessionRegistryImpl;
|
||||||
import org.springframework.security.web.SecurityFilterChain;
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
|
import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
|
||||||
|
@ -36,6 +39,13 @@ class SecurityConfig {
|
||||||
.logout()
|
.logout()
|
||||||
.addLogoutHandler(keycloakLogoutHandler)
|
.addLogoutHandler(keycloakLogoutHandler)
|
||||||
.logoutSuccessUrl("/");
|
.logoutSuccessUrl("/");
|
||||||
|
http.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt);
|
||||||
return http.build();
|
return http.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public AuthenticationManager authenticationManager(HttpSecurity http) throws Exception {
|
||||||
|
return http.getSharedObject(AuthenticationManagerBuilder.class)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,54 +1,27 @@
|
||||||
package com.baeldung.keycloaksoap;
|
package com.baeldung.keycloaksoap;
|
||||||
|
|
||||||
import org.keycloak.adapters.KeycloakConfigResolver;
|
|
||||||
import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver;
|
|
||||||
import org.keycloak.adapters.springsecurity.KeycloakConfiguration;
|
|
||||||
import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider;
|
|
||||||
import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper;
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||||
import org.springframework.security.core.session.SessionRegistryImpl;
|
import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer;
|
||||||
import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
|
|
||||||
|
|
||||||
@KeycloakConfiguration
|
@Configuration
|
||||||
|
@EnableWebSecurity
|
||||||
@ConditionalOnProperty(name = "keycloak.enabled", havingValue = "true")
|
@ConditionalOnProperty(name = "keycloak.enabled", havingValue = "true")
|
||||||
@EnableGlobalMethodSecurity(jsr250Enabled = true)
|
@EnableGlobalMethodSecurity(jsr250Enabled = true)
|
||||||
public class KeycloakSecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
|
public class KeycloakSecurityConfig {
|
||||||
@Override
|
|
||||||
protected void configure(HttpSecurity http) throws Exception {
|
@Bean
|
||||||
super.configure(http);
|
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||||
//@formatter:off
|
http.csrf()
|
||||||
http
|
|
||||||
.csrf()
|
|
||||||
.disable()
|
.disable()
|
||||||
.authorizeRequests()
|
.authorizeHttpRequests(auth -> auth.anyRequest()
|
||||||
.anyRequest()
|
.authenticated())
|
||||||
.permitAll();
|
.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt);
|
||||||
//@formatter:on
|
return http.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Autowired
|
|
||||||
public void configureGlobal(AuthenticationManagerBuilder auth) {
|
|
||||||
KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
|
|
||||||
keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
|
|
||||||
auth.authenticationProvider(keycloakAuthenticationProvider);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
@Override
|
|
||||||
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
|
|
||||||
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public KeycloakConfigResolver keycloakSpringBootConfigResolver() {
|
|
||||||
return new KeycloakSpringBootConfigResolver();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,8 @@
|
||||||
server.port=18080
|
server.port=18080
|
||||||
|
|
||||||
keycloak.enabled=true
|
keycloak.enabled=true
|
||||||
keycloak.realm=baeldung-soap-services
|
|
||||||
keycloak.auth-server-url=http://localhost:8080/auth
|
|
||||||
keycloak.bearer-only=true
|
|
||||||
keycloak.credentials.secret=14da6f9e-261f-489a-9bf0-1441e4a9ddc4
|
|
||||||
keycloak.ssl-required=external
|
|
||||||
keycloak.resource=baeldung-soap-services
|
|
||||||
keycloak.use-resource-role-mappings=true
|
|
||||||
|
|
||||||
|
spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:8080/realms/baeldung-soap-services
|
||||||
|
|
||||||
# Custom properties begin here
|
# Custom properties begin here
|
||||||
ws.api.path=/ws/api/v1/*
|
ws.api.path=/ws/api/v1/*
|
||||||
|
|
|
@ -1,15 +1,10 @@
|
||||||
### server port
|
### server port
|
||||||
server.port=8081
|
server.port=8081
|
||||||
|
|
||||||
#Keycloak Configuration
|
|
||||||
keycloak.auth-server-url=http://localhost:8180/auth
|
|
||||||
keycloak.realm=SpringBootKeycloak
|
|
||||||
keycloak.resource=login-app
|
|
||||||
keycloak.public-client=true
|
|
||||||
keycloak.principal-attribute=preferred_username
|
|
||||||
|
|
||||||
spring.security.oauth2.client.registration.keycloak.client-id=login-app
|
spring.security.oauth2.client.registration.keycloak.client-id=login-app
|
||||||
spring.security.oauth2.client.registration.keycloak.authorization-grant-type=authorization_code
|
spring.security.oauth2.client.registration.keycloak.authorization-grant-type=authorization_code
|
||||||
spring.security.oauth2.client.registration.keycloak.scope=openid
|
spring.security.oauth2.client.registration.keycloak.scope=openid
|
||||||
spring.security.oauth2.client.provider.keycloak.issuer-uri=http://localhost:8180/auth/realms/SpringBootKeycloak
|
spring.security.oauth2.client.provider.keycloak.issuer-uri=http://localhost:8080/realms/SpringBootKeycloak
|
||||||
spring.security.oauth2.client.provider.keycloak.user-name-attribute=preferred_username
|
spring.security.oauth2.client.provider.keycloak.user-name-attribute=preferred_username
|
||||||
|
|
||||||
|
spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:8080/realms/SpringBootKeycloak
|
|
@ -0,0 +1,18 @@
|
||||||
|
package com.baeldung.keycloak;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||||
|
import com.baeldung.keycloak.SpringBoot;
|
||||||
|
|
||||||
|
@ExtendWith(SpringExtension.class)
|
||||||
|
@SpringBootTest(classes = { SpringBoot.class })
|
||||||
|
public class KeycloakContextIntegrationTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenLoadApplication_thenSuccess() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -105,7 +105,7 @@ class KeycloakSoapLiveTest {
|
||||||
void givenAccessToken_whenDeleteProduct_thenReturnSuccess() {
|
void givenAccessToken_whenDeleteProduct_thenReturnSuccess() {
|
||||||
HttpHeaders headers = new HttpHeaders();
|
HttpHeaders headers = new HttpHeaders();
|
||||||
headers.set("content-type", "text/xml");
|
headers.set("content-type", "text/xml");
|
||||||
headers.set("Authorization", "Bearer " + generateToken("jhondoe", "password"));
|
headers.set("Authorization", "Bearer " + generateToken("johndoe", "password"));
|
||||||
HttpEntity<String> request = new HttpEntity<>(Utility.getDeleteProductsRequest(), headers);
|
HttpEntity<String> request = new HttpEntity<>(Utility.getDeleteProductsRequest(), headers);
|
||||||
ResponseEntity<String> responseEntity = restTemplate.postForEntity("http://localhost:" + port + "/ws/api/v1/", request, String.class);
|
ResponseEntity<String> responseEntity = restTemplate.postForEntity("http://localhost:" + port + "/ws/api/v1/", request, String.class);
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
grant.type=password
|
grant.type=password
|
||||||
client.id=baeldung-soap-services
|
client.id=baeldung-soap-services
|
||||||
client.secret=d2ba7af8-f7d2-4c97-b4a5-3c88b59920ae
|
client.secret=d2ba7af8-f7d2-4c97-b4a5-3c88b59920ae
|
||||||
url=http://localhost:8080/auth/realms/baeldung-soap-services/protocol/openid-connect/token
|
url=http://localhost:8080/realms/baeldung-soap-services/protocol/openid-connect/token
|
||||||
|
|
||||||
|
keycloak.enabled=true
|
||||||
|
spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:8080/realms/baeldung-soap-services
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
package com.baeldung.requestheader;
|
||||||
|
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import com.baeldung.requestheader.interceptor.OperatorHolder;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
public class BuzzController {
|
||||||
|
private final OperatorHolder operatorHolder;
|
||||||
|
|
||||||
|
public BuzzController(OperatorHolder operatorHolder) {
|
||||||
|
this.operatorHolder = operatorHolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("buzz")
|
||||||
|
public String buzz() {
|
||||||
|
return "hello, " + operatorHolder.getOperator();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package com.baeldung.requestheader;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestHeader;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
public class FooBarController {
|
||||||
|
|
||||||
|
@GetMapping("foo")
|
||||||
|
public String foo(HttpServletRequest request) {
|
||||||
|
String operator = request.getHeader("operator");
|
||||||
|
return "hello, " + operator;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("bar")
|
||||||
|
public String bar(@RequestHeader("operator") String operator) {
|
||||||
|
return "hello, " + operator;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
package com.baeldung.requestheader;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
@EnableWebMvc
|
||||||
|
public class HeaderInterceptorApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(HeaderInterceptorApplication.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
package com.baeldung.requestheader.config;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Scope;
|
||||||
|
import org.springframework.context.annotation.ScopedProxyMode;
|
||||||
|
import org.springframework.web.context.WebApplicationContext;
|
||||||
|
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||||
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||||
|
|
||||||
|
import com.baeldung.requestheader.interceptor.OperatorHolder;
|
||||||
|
import com.baeldung.requestheader.interceptor.OperatorInterceptor;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class HeaderInterceptorConfig implements WebMvcConfigurer {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addInterceptors(final InterceptorRegistry registry) {
|
||||||
|
registry.addInterceptor(operatorInterceptor());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public OperatorInterceptor operatorInterceptor() {
|
||||||
|
return new OperatorInterceptor(operatorHolder());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
|
||||||
|
public OperatorHolder operatorHolder() {
|
||||||
|
return new OperatorHolder();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
package com.baeldung.requestheader.interceptor;
|
||||||
|
|
||||||
|
public class OperatorHolder {
|
||||||
|
private String operator;
|
||||||
|
|
||||||
|
public String getOperator() {
|
||||||
|
return operator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOperator(String operator) {
|
||||||
|
this.operator = operator;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package com.baeldung.requestheader.interceptor;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.springframework.web.servlet.HandlerInterceptor;
|
||||||
|
|
||||||
|
public class OperatorInterceptor implements HandlerInterceptor {
|
||||||
|
|
||||||
|
private final OperatorHolder operatorHolder;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||||
|
String operator = request.getHeader("operator");
|
||||||
|
operatorHolder.setOperator(operator);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OperatorInterceptor(OperatorHolder operatorHolder) {
|
||||||
|
this.operatorHolder = operatorHolder;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
package com.baeldung.requestheader;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.mock.web.MockHttpServletResponse;
|
||||||
|
import org.springframework.test.context.ContextConfiguration;
|
||||||
|
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||||
|
import org.springframework.test.context.web.WebAppConfiguration;
|
||||||
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||||
|
import org.springframework.web.context.WebApplicationContext;
|
||||||
|
|
||||||
|
@ExtendWith(SpringExtension.class)
|
||||||
|
@ContextConfiguration(classes = { HeaderInterceptorApplication.class })
|
||||||
|
@WebAppConfiguration
|
||||||
|
public class HeaderInterceptorIntegrationTest {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private WebApplicationContext webApplicationContext;
|
||||||
|
|
||||||
|
private MockMvc mockMvc;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void setup() {
|
||||||
|
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.webApplicationContext)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenARequestWithOperatorHeader_whenWeCallFooEndpoint_thenOperatorIsExtracted() throws Exception {
|
||||||
|
MockHttpServletResponse response = this.mockMvc.perform(get("/foo").header("operator", "John.Doe"))
|
||||||
|
.andDo(print())
|
||||||
|
.andReturn()
|
||||||
|
.getResponse();
|
||||||
|
|
||||||
|
assertThat(response.getContentAsString()).isEqualTo("hello, John.Doe");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenARequestWithOperatorHeader_whenWeCallBarEndpoint_thenOperatorIsExtracted() throws Exception {
|
||||||
|
MockHttpServletResponse response = this.mockMvc.perform(get("/bar").header("operator", "John.Doe"))
|
||||||
|
.andDo(print())
|
||||||
|
.andReturn()
|
||||||
|
.getResponse();
|
||||||
|
|
||||||
|
assertThat(response.getContentAsString()).isEqualTo("hello, John.Doe");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenARequestWithOperatorHeader_whenWeCallBuzzEndpoint_thenOperatorIsIntercepted() throws Exception {
|
||||||
|
MockHttpServletResponse response = this.mockMvc.perform(get("/buzz").header("operator", "John.Doe"))
|
||||||
|
.andDo(print())
|
||||||
|
.andReturn()
|
||||||
|
.getResponse();
|
||||||
|
|
||||||
|
assertThat(response.getContentAsString()).isEqualTo("hello, John.Doe");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -2,7 +2,6 @@ keycloak:
|
||||||
auth-server-url: https://api.example.com/auth # Keycloak server url
|
auth-server-url: https://api.example.com/auth # Keycloak server url
|
||||||
realm: todos-service-realm # Keycloak Realm
|
realm: todos-service-realm # Keycloak Realm
|
||||||
resource: todos-service-clients # Keycloak Client
|
resource: todos-service-clients # Keycloak Client
|
||||||
public-client: true
|
|
||||||
principal-attribute: preferred_username
|
principal-attribute: preferred_username
|
||||||
ssl-required: external
|
ssl-required: external
|
||||||
credentials:
|
credentials:
|
||||||
|
|
|
@ -4,4 +4,4 @@ This module contains articles about Spring with Kafka
|
||||||
|
|
||||||
### Relevant articles
|
### Relevant articles
|
||||||
|
|
||||||
- [Implementing Retry In Kafka Consumer]
|
- [Implementing Retry In Kafka Consumer](https://www.baeldung.com/spring-retry-kafka-consumer)
|
||||||
|
|
|
@ -24,7 +24,9 @@ public class SpringAsyncConfig implements AsyncConfigurer {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Executor getAsyncExecutor() {
|
public Executor getAsyncExecutor() {
|
||||||
return new SimpleAsyncTaskExecutor();
|
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
|
||||||
|
threadPoolTaskExecutor.initialize();
|
||||||
|
return threadPoolTaskExecutor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
saml.keystore.location=classpath:/saml/saml-keystore
|
saml.keystore.location=classpath:/saml/saml-keystore.jks
|
||||||
# Password for Java keystore and item therein
|
# Password for Java keystore and item therein
|
||||||
saml.keystore.password=<key_pass>
|
saml.keystore.password=baeldungsamlokta
|
||||||
saml.keystore.alias=<key_alias>
|
saml.keystore.alias=baeldungspringsaml
|
||||||
|
|
||||||
# SAML Entity ID extracted from top of SAML metadata file
|
# SAML Entity ID extracted from top of SAML metadata file
|
||||||
saml.idp=<idp_issuer_url>
|
saml.idp=http://www.okta.com/exk26fxqrz8LLk9dV4x7
|
||||||
saml.sp=http://localhost:8080/saml/metadata
|
saml.sp=http://localhost:8080/saml/metadata
|
||||||
spring.main.allow-circular-references=true
|
spring.main.allow-circular-references=true
|
Binary file not shown.
Binary file not shown.
|
@ -1,5 +1,7 @@
|
||||||
package com.baeldung.springbootsecurityrest.basicauth.config;
|
package com.baeldung.springbootsecurityrest.basicauth.config;
|
||||||
|
|
||||||
|
import static org.springframework.security.config.Customizer.withDefaults;
|
||||||
|
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.http.HttpMethod;
|
import org.springframework.http.HttpMethod;
|
||||||
|
@ -27,6 +29,7 @@ public class BasicAuthConfiguration {
|
||||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||||
http.csrf()
|
http.csrf()
|
||||||
.disable()
|
.disable()
|
||||||
|
.cors(withDefaults())
|
||||||
.authorizeRequests()
|
.authorizeRequests()
|
||||||
.antMatchers(HttpMethod.OPTIONS, "/**")
|
.antMatchers(HttpMethod.OPTIONS, "/**")
|
||||||
.permitAll()
|
.permitAll()
|
||||||
|
|
|
@ -6,3 +6,4 @@ This module contains articles about Spring MVC
|
||||||
- [Using a Slash Character in Spring URLs](https://www.baeldung.com/spring-slash-character-in-url)
|
- [Using a Slash Character in Spring URLs](https://www.baeldung.com/spring-slash-character-in-url)
|
||||||
- [Excluding URLs for a Filter in a Spring Web Application](https://www.baeldung.com/spring-exclude-filter)
|
- [Excluding URLs for a Filter in a Spring Web Application](https://www.baeldung.com/spring-exclude-filter)
|
||||||
- [Handling URL Encoded Form Data in Spring REST](https://www.baeldung.com/spring-url-encoded-form-data)
|
- [Handling URL Encoded Form Data in Spring REST](https://www.baeldung.com/spring-url-encoded-form-data)
|
||||||
|
- [Spring MVC – Mapping the Root URL to a Page](https://www.baeldung.com/spring-mvc-map-root-url)
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
package com.baeldung.rootmapping;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
@EnableWebMvc
|
||||||
|
public class RootMappingApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(RootMappingApplication.class, args);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
package com.baeldung.rootmapping.config;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
|
||||||
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class WebConfig implements WebMvcConfigurer {
|
||||||
|
@Override
|
||||||
|
public void addViewControllers(ViewControllerRegistry registry) {
|
||||||
|
registry.addViewController("/").setViewName("index");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
package com.baeldung.rootmapping.controller;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
|
||||||
|
@Controller
|
||||||
|
public class RootController {
|
||||||
|
@GetMapping("/")
|
||||||
|
public String index() {
|
||||||
|
return "index";
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue