Merge branch 'master' into study-groovy

This commit is contained in:
Alex Golub 2023-01-20 20:08:17 +02:00
commit dd1613669e
103 changed files with 2149 additions and 362 deletions

View File

@ -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.

View File

@ -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;

View File

@ -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)

View File

@ -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());
}
} }

View File

@ -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)

View File

@ -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>

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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 + ')';
}
}

View File

@ -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 + ')';
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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"));
}
}

View File

@ -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);
}
}

View File

@ -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)

View File

@ -0,0 +1,6 @@
package com.baeldung.inmemorycompilation;
public interface InMemoryClass {
void runCode();
}

View File

@ -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();
}
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}
}

View File

@ -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

View File

@ -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

View File

@ -5,65 +5,73 @@ 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;
} }
} }
}

View File

@ -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));
}
} }

View File

@ -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)

View File

@ -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)

View File

@ -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>

View File

@ -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());
}
}
}

View File

@ -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));
}
}

View File

@ -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));
}
}

View File

@ -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;
} }
/** /**

View File

@ -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)

View File

@ -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>

View File

@ -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>

View File

@ -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));
}
} }
} }

View File

@ -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;

View File

@ -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();

View File

@ -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)

View File

@ -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)

View File

@ -0,0 +1,16 @@
pipeline {
agent any
stages {
stage('tryCatch') {
steps {
script {
try {
sh 'test_script.sh'
} catch (e) {
echo "An error occurred: ${e}"
}
}
}
}
}
}

View File

@ -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 {

View File

@ -0,0 +1,2 @@
## Relevant Articles
- [Lightweight Logging With tinylog 2](https://www.baeldung.com/java-logging-tinylog-guide)

View File

@ -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)

View File

@ -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)

View File

@ -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());
}
} }

View File

@ -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());
} }
} }

View File

@ -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());
} }

View File

@ -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)

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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

View File

@ -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());
}
}

View File

@ -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>

View File

@ -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)

View File

@ -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>

View File

@ -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;
}
}

View File

@ -0,0 +1,7 @@
package com.baeldung.keycloak;
import org.springframework.data.repository.CrudRepository;
public interface CustomerDAO extends CrudRepository<Customer, Long> {
}

View File

@ -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");
}
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -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

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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)

View File

@ -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>

View File

@ -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();
}
} }

View File

@ -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();
}
} }

View File

@ -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/*

View File

@ -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

View File

@ -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() {
}
}

View File

@ -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);

View File

@ -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

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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");
}
}

View File

@ -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:

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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)

View File

@ -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);
}
}

View File

@ -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");
}
}

View File

@ -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