Merge branch 'eugenp:master' into master
This commit is contained in:
commit
fda1afcf35
@ -10,3 +10,4 @@ This module contains complete guides about arrays in Java
|
|||||||
- [Creating a Generic Array in Java](https://www.baeldung.com/java-generic-array)
|
- [Creating a Generic Array in Java](https://www.baeldung.com/java-generic-array)
|
||||||
- [Maximum Size of Java Arrays](https://www.baeldung.com/java-arrays-max-size)
|
- [Maximum Size of Java Arrays](https://www.baeldung.com/java-arrays-max-size)
|
||||||
- [Merge Two Arrays and Remove Duplicates in Java](https://www.baeldung.com/java-merge-two-arrays-delete-duplicates)
|
- [Merge Two Arrays and Remove Duplicates in Java](https://www.baeldung.com/java-merge-two-arrays-delete-duplicates)
|
||||||
|
- [Print a Java 2D Array](https://www.baeldung.com/java-2d-array-print)
|
||||||
|
@ -0,0 +1,24 @@
|
|||||||
|
package com.baeldung.equilibriumindex;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
class EquilibriumIndexFinder {
|
||||||
|
|
||||||
|
List<Integer> findEquilibriumIndexes(int[] array) {
|
||||||
|
int[] partialSums = new int[array.length + 1];
|
||||||
|
partialSums[0] = 0;
|
||||||
|
for (int i = 0; i < array.length; i++) {
|
||||||
|
partialSums[i+1] = partialSums[i] + array[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Integer> equilibriumIndexes = new ArrayList<Integer>();
|
||||||
|
for (int i = 0; i < array.length; i++) {
|
||||||
|
if (partialSums[i] == (partialSums[array.length] - (partialSums[i+1]))) {
|
||||||
|
equilibriumIndexes.add(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return equilibriumIndexes;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
package com.baeldung.equilibriumindex;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
class EquilibriumIndexFinderUnitTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenArrayHasEquilibriumIndexes_whenFindEquilibriumIndexes_thenListAllEquilibriumIndexes() {
|
||||||
|
int[] array = {1, -3, 0, 4, -5, 4, 0, 1, -2, -1};
|
||||||
|
assertThat(new EquilibriumIndexFinder().findEquilibriumIndexes(array)).containsExactly(1, 4, 9);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenArrayWithoutEquilibriumIndexes_whenFindEquilibriumIndexes_thenEmptyList() {
|
||||||
|
int[] array = {1, 2, 3};
|
||||||
|
assertThat(new EquilibriumIndexFinder().findEquilibriumIndexes(array)).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenArrayWithOneElement_whenFindEquilibriumIndexes_thenListFirstIndex() {
|
||||||
|
int[] array = {5};
|
||||||
|
assertThat(new EquilibriumIndexFinder().findEquilibriumIndexes(array)).containsExactly(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -6,3 +6,4 @@ This module contains articles about Java Character Class
|
|||||||
- [Character#isAlphabetic vs. Character#isLetter](https://www.baeldung.com/java-character-isletter-isalphabetic)
|
- [Character#isAlphabetic vs. Character#isLetter](https://www.baeldung.com/java-character-isletter-isalphabetic)
|
||||||
- [Difference Between Java’s “char” and “String”](https://www.baeldung.com/java-char-vs-string)
|
- [Difference Between Java’s “char” and “String”](https://www.baeldung.com/java-char-vs-string)
|
||||||
- [Increment Character in Java](https://www.baeldung.com/java-char-sequence)
|
- [Increment Character in Java](https://www.baeldung.com/java-char-sequence)
|
||||||
|
- [Creating Unicode Character From Its Code Point Hex String](https://www.baeldung.com/java-unicode-character-from-code-point-hex-string)
|
||||||
|
@ -0,0 +1,33 @@
|
|||||||
|
package com.baeldung.countdownlatchvssemaphore;
|
||||||
|
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
|
||||||
|
public class CountDownLatchDemo {
|
||||||
|
|
||||||
|
public static void main(String[] args) throws InterruptedException {
|
||||||
|
// Create a CountDownLatch with an initial count equal to the number of tasks to be completed
|
||||||
|
int numberOfTasks = 3;
|
||||||
|
CountDownLatch latch = new CountDownLatch(numberOfTasks);
|
||||||
|
|
||||||
|
// Simulate completion of tasks by worker threads
|
||||||
|
for (int i = 1; i <= numberOfTasks; i++) {
|
||||||
|
new Thread(() -> {
|
||||||
|
System.out.println("Task completed by Thread " + Thread.currentThread()
|
||||||
|
.getId());
|
||||||
|
|
||||||
|
// Decrement the latch count to signal completion of a task
|
||||||
|
latch.countDown();
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main thread waits until all tasks are completed
|
||||||
|
latch.await();
|
||||||
|
System.out.println("All tasks completed. Main thread proceeds.");
|
||||||
|
|
||||||
|
// Attempting to reset will have no effect
|
||||||
|
latch.countDown();
|
||||||
|
// Latch is already at zero, await() returns immediately
|
||||||
|
latch.await(); // This line won't block
|
||||||
|
System.out.println("Latch is already at zero and cannot be reset.");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
package com.baeldung.countdownlatchvssemaphore;
|
||||||
|
|
||||||
|
import java.util.concurrent.Semaphore;
|
||||||
|
|
||||||
|
public class SemaphoreDemo {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
// Create a Semaphore with a fixed number of permits
|
||||||
|
int NUM_PERMITS = 3;
|
||||||
|
Semaphore semaphore = new Semaphore(NUM_PERMITS);
|
||||||
|
|
||||||
|
// Simulate resource access by worker threads
|
||||||
|
for (int i = 1; i <= 5; i++) {
|
||||||
|
new Thread(() -> {
|
||||||
|
try {
|
||||||
|
// Acquire a permit to access the resource
|
||||||
|
semaphore.acquire();
|
||||||
|
System.out.println("Thread " + Thread.currentThread().getId() + " accessing resource.");
|
||||||
|
|
||||||
|
// Simulate resource usage
|
||||||
|
Thread.sleep(2000);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
// Release the permit after resource access is complete
|
||||||
|
semaphore.release();
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simulate resetting the Semaphore by releasing additional permits after a delay
|
||||||
|
try {
|
||||||
|
Thread.sleep(5000);
|
||||||
|
|
||||||
|
// Resetting the semaphore permits to the initial count
|
||||||
|
semaphore.release(NUM_PERMITS);
|
||||||
|
System.out.println("Semaphore permits reset to initial count.");
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,4 +3,4 @@ This module contains articles about date operations in Java.
|
|||||||
|
|
||||||
### Relevant Articles:
|
### Relevant Articles:
|
||||||
- [Calculate Number of Weekdays Between Two Dates in Java](https://www.baeldung.com/java-count-weekdays-between-two-dates)
|
- [Calculate Number of Weekdays Between Two Dates in Java](https://www.baeldung.com/java-count-weekdays-between-two-dates)
|
||||||
|
- [Convert Long to Date in Java](https://www.baeldung.com/java-long-date-conversion)
|
||||||
|
@ -3,4 +3,4 @@
|
|||||||
This module contains articles about converting between Java date and time objects.
|
This module contains articles about converting between Java date and time objects.
|
||||||
|
|
||||||
### Relevant Articles:
|
### Relevant Articles:
|
||||||
|
- [Convert Gregorian to Hijri Date in Java](https://www.baeldung.com/java-date-gregorian-hijri-conversion)
|
||||||
|
@ -14,3 +14,4 @@ This module contains articles about core features in the Java language
|
|||||||
- [Static Final Variables in Java](https://www.baeldung.com/java-static-final-variables)
|
- [Static Final Variables in Java](https://www.baeldung.com/java-static-final-variables)
|
||||||
- [What Is the Error: “Non-static method cannot be referenced from a static context”?](https://www.baeldung.com/java-non-static-method-cannot-be-referenced-from-a-static-context)
|
- [What Is the Error: “Non-static method cannot be referenced from a static context”?](https://www.baeldung.com/java-non-static-method-cannot-be-referenced-from-a-static-context)
|
||||||
- [Recursively Sum the Integers in an Array](https://www.baeldung.com/java-recursive-sum-integer-array)
|
- [Recursively Sum the Integers in an Array](https://www.baeldung.com/java-recursive-sum-integer-array)
|
||||||
|
- [Set an Environment Variable at Runtime in Java](https://www.baeldung.com/java-set-environment-variable-runtime)
|
||||||
|
@ -0,0 +1,55 @@
|
|||||||
|
package com.baeldung.customurlconnection;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLConnection;
|
||||||
|
|
||||||
|
public class CustomURLConnection extends URLConnection {
|
||||||
|
private final String simulatedData = "This is the simulated data from the resource.";
|
||||||
|
private URL url;
|
||||||
|
private boolean connected = false;
|
||||||
|
private String headerValue = "SimulatedHeaderValue";
|
||||||
|
|
||||||
|
protected CustomURLConnection(URL url) {
|
||||||
|
super(url);
|
||||||
|
this.url = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void connect() throws IOException {
|
||||||
|
connected = true;
|
||||||
|
System.out.println("Connection established to: " + url);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InputStream getInputStream() throws IOException {
|
||||||
|
if (!connected) {
|
||||||
|
connect();
|
||||||
|
}
|
||||||
|
return new ByteArrayInputStream(simulatedData.getBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OutputStream getOutputStream() throws IOException {
|
||||||
|
ByteArrayOutputStream simulatedOutput = new ByteArrayOutputStream();
|
||||||
|
return simulatedOutput;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getContentLength() {
|
||||||
|
return simulatedData.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getHeaderField(String name) {
|
||||||
|
if ("SimulatedHeader".equalsIgnoreCase(name)) { // Example header name
|
||||||
|
return headerValue;
|
||||||
|
} else {
|
||||||
|
return null; // Header not found
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package com.baeldung.customurlconnection;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLConnection;
|
||||||
|
import java.net.URLStreamHandler;
|
||||||
|
|
||||||
|
public class CustomURLStreamHandler extends URLStreamHandler {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected URLConnection openConnection(URL u) throws IOException {
|
||||||
|
// Create and return an instance of CustomURLConnection
|
||||||
|
return new CustomURLConnection(u);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package com.baeldung.customurlconnection;
|
||||||
|
|
||||||
|
import java.net.URLStreamHandler;
|
||||||
|
import java.net.URLStreamHandlerFactory;
|
||||||
|
|
||||||
|
public class CustomURLStreamHandlerFactory implements URLStreamHandlerFactory {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public URLStreamHandler createURLStreamHandler(String protocol) {
|
||||||
|
// Check if the requested protocol is our custom protocol
|
||||||
|
if ("myprotocol".equals(protocol)) {
|
||||||
|
return new CustomURLStreamHandler();
|
||||||
|
}
|
||||||
|
return null; // Let the default handler deal with other protocols
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
package com.baeldung.customurlconnection;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.Scanner;
|
||||||
|
|
||||||
|
public class Main {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
URL.setURLStreamHandlerFactory(new CustomURLStreamHandlerFactory());
|
||||||
|
|
||||||
|
try {
|
||||||
|
URL url = new URL("myprotocol://example.com/resource");
|
||||||
|
|
||||||
|
CustomURLConnection customConnection = (CustomURLConnection) url.openConnection();
|
||||||
|
customConnection.connect();
|
||||||
|
|
||||||
|
InputStream inputStream = customConnection.getInputStream();
|
||||||
|
|
||||||
|
String content = new Scanner(inputStream).useDelimiter("\\A").next();
|
||||||
|
System.out.println(content);
|
||||||
|
|
||||||
|
int contentLength = customConnection.getContentLength();
|
||||||
|
System.out.println("Content Length: " + contentLength);
|
||||||
|
|
||||||
|
String headerValue = customConnection.getHeaderField("SimulatedHeader");
|
||||||
|
System.out.println("Header Value: " + headerValue);
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
package com.baeldung.urlencoder;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
public class SpaceURLEncoderUnitTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenSpaceInString_whenUsingDefaultEncoding_thenReturnPlusSign() {
|
||||||
|
String originalString = "Welcome to the Baeldung Website!";
|
||||||
|
String encodedString = URLEncoder.encode(originalString);
|
||||||
|
assertEquals("Welcome+to+the+Baeldung+Website%21", encodedString);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenSpaceInString_whenUsingUTF8Encoding_thenReturnPlusSign() throws UnsupportedEncodingException {
|
||||||
|
String originalString = "Welcome to the Baeldung Website!";
|
||||||
|
String encodedString = URLEncoder.encode(originalString, StandardCharsets.UTF_8.toString());
|
||||||
|
assertEquals("Welcome+to+the+Baeldung+Website%21", encodedString);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenSpaceInString_whenUsingDefaultEncodingAndReplace_thenReturnPct20() throws UnsupportedEncodingException {
|
||||||
|
String originalString = "Welcome to the Baeldung Website!";
|
||||||
|
String encodedString = URLEncoder.encode(originalString)
|
||||||
|
.replace("+", "%20");
|
||||||
|
assertEquals("Welcome%20to%20the%20Baeldung%20Website%21", encodedString);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenSpaceInString_whenUsingDefaultEncodingAndReplaceAll_thenReturnPct20() throws UnsupportedEncodingException {
|
||||||
|
String originalString = "Welcome to the Baeldung Website!";
|
||||||
|
String encodedString = URLEncoder.encode(originalString)
|
||||||
|
.replaceAll("\\+", "%20");
|
||||||
|
assertEquals("Welcome%20to%20the%20Baeldung%20Website%21", encodedString);
|
||||||
|
}
|
||||||
|
}
|
@ -22,7 +22,7 @@ public class URLNormalizationUnitTest {
|
|||||||
String normalizedUri = originalUrl.split("\\?")[0];
|
String normalizedUri = originalUrl.split("\\?")[0];
|
||||||
assertEquals(expectedNormalizedUrl, normalizedUri);
|
assertEquals(expectedNormalizedUrl, normalizedUri);
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException("Invalid URL: " + originalUrl);
|
fail(originalUrl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,7 +35,7 @@ public class URLNormalizationUnitTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void givenOriginalUrl_whenUsingRegularExpression_thenNormalizedUrl() throws URISyntaxException, UnsupportedEncodingException {
|
public void givenOriginalUrl_whenUsingRegularExpression_thenNormalizedUrl() {
|
||||||
String regex = "^(https?://[^/]+/[^?#]+)";
|
String regex = "^(https?://[^/]+/[^?#]+)";
|
||||||
Pattern pattern = Pattern.compile(regex);
|
Pattern pattern = Pattern.compile(regex);
|
||||||
Matcher matcher = pattern.matcher(originalUrl);
|
Matcher matcher = pattern.matcher(originalUrl);
|
||||||
@ -44,7 +44,7 @@ public class URLNormalizationUnitTest {
|
|||||||
String normalizedUrl = matcher.group(1);
|
String normalizedUrl = matcher.group(1);
|
||||||
assertEquals(expectedNormalizedUrl, normalizedUrl);
|
assertEquals(expectedNormalizedUrl, normalizedUrl);
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException("Invalid URL: " + originalUrl);
|
fail(originalUrl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
package com.baeldung.reflection.innerclass;
|
||||||
|
|
||||||
|
public class Person {
|
||||||
|
String name;
|
||||||
|
Address address;
|
||||||
|
|
||||||
|
public Person() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Address {
|
||||||
|
String zip;
|
||||||
|
|
||||||
|
public Address(String zip) {
|
||||||
|
this.zip = zip;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Builder {
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,67 @@
|
|||||||
|
package com.baeldung.reflection.innerclass;
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class CreateInnerClassWithReflectionUnitTest {
|
||||||
|
|
||||||
|
static Logger logger = LoggerFactory.getLogger(CreateInnerClassWithReflectionUnitTest.class);
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenInnerClass_whenUseReflection_thenShowConstructors() {
|
||||||
|
final String personBuilderClassName = "com.baeldung.reflection.innerclass.Person$Builder";
|
||||||
|
final String personAddressClassName = "com.baeldung.reflection.innerclass.Person$Address";
|
||||||
|
assertDoesNotThrow(() -> logConstructors(Class.forName(personAddressClassName)));
|
||||||
|
assertDoesNotThrow(() -> logConstructors(Class.forName(personBuilderClassName)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void logConstructors(Class<?> clazz) {
|
||||||
|
Arrays.stream(clazz.getDeclaredConstructors())
|
||||||
|
.map(c -> formatConstructorSignature(c))
|
||||||
|
.forEach(logger::info);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String formatConstructorSignature(Constructor<?> constructor) {
|
||||||
|
String params = Arrays.stream(constructor.getParameters())
|
||||||
|
.map(parameter -> parameter.getType().getSimpleName() + " " + parameter.getName())
|
||||||
|
.collect(Collectors.joining(", "));
|
||||||
|
return constructor.getName() + "(" + params + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenStaticInnerClass_whenUseReflection_thenInstantiate()
|
||||||
|
throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException,
|
||||||
|
InstantiationException, IllegalAccessException {
|
||||||
|
final String personBuilderClassName = "com.baeldung.reflection.innerclass.Person$Builder";
|
||||||
|
Class<Person.Builder> personBuilderClass = (Class<Person.Builder>) Class.forName(personBuilderClassName);
|
||||||
|
Person.Builder personBuilderObj = personBuilderClass.getDeclaredConstructor().newInstance();
|
||||||
|
assertTrue(personBuilderObj instanceof Person.Builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenNonStaticInnerClass_whenUseReflection_thenInstantiate()
|
||||||
|
throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException,
|
||||||
|
InstantiationException, IllegalAccessException {
|
||||||
|
final String personClassName = "com.baeldung.reflection.innerclass.Person";
|
||||||
|
final String personAddressClassName = "com.baeldung.reflection.innerclass.Person$Address";
|
||||||
|
|
||||||
|
Class<Person> personClass = (Class<Person>) Class.forName(personClassName);
|
||||||
|
Person personObj = personClass.getConstructor().newInstance();
|
||||||
|
|
||||||
|
Class<Person.Address> personAddressClass = (Class<Person.Address>) Class.forName(personAddressClassName);
|
||||||
|
|
||||||
|
assertThrows(NoSuchMethodException.class, () -> personAddressClass.getDeclaredConstructor(String.class));
|
||||||
|
|
||||||
|
Constructor<Person.Address> constructorOfPersonAddress = personAddressClass.getDeclaredConstructor(Person.class, String.class);
|
||||||
|
Person.Address personAddressObj = constructorOfPersonAddress.newInstance(personObj, "751003");
|
||||||
|
assertTrue(personAddressObj instanceof Person.Address);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
package com.baeldung.stream.range;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
public class StreamRangeUnitTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenRangeStreamUsingLimitSkip_thenPrintsRange() {
|
||||||
|
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
|
||||||
|
List<Integer> expectedRange = Arrays.asList(3, 4, 5, 6, 7);
|
||||||
|
|
||||||
|
List<Integer> range = numbers.stream()
|
||||||
|
.skip(2)
|
||||||
|
.limit(5)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
assertEquals(expectedRange, range);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenRangeStreamUsingCollectingAndThen_thenPrintsRange() {
|
||||||
|
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
|
||||||
|
List<Integer> expectedRange = Arrays.asList(3, 4, 5, 6, 7);
|
||||||
|
|
||||||
|
List<Integer> range = numbers.stream()
|
||||||
|
.filter(n -> n >= 3 && n <= 7)
|
||||||
|
.collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
|
||||||
|
|
||||||
|
assertEquals(expectedRange, range);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,93 @@
|
|||||||
|
package com.baeldung.string.runlength;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
public class RunLengthEncodingUnitTest {
|
||||||
|
private static final String INPUT = "WWWWWWWWWWWWBAAACCDEEEEE";
|
||||||
|
private static final String RLE = "12W1B3A2C1D5E";
|
||||||
|
|
||||||
|
String runLengthEncode(String input) {
|
||||||
|
StringBuilder result = new StringBuilder();
|
||||||
|
int count = 1;
|
||||||
|
char[] chars = input.toCharArray();
|
||||||
|
for (int i = 0; i < chars.length; i++) {
|
||||||
|
char c = chars[i];
|
||||||
|
if (i + 1 < chars.length && c == chars[i + 1]) {
|
||||||
|
count++;
|
||||||
|
} else {
|
||||||
|
result.append(count).append(c);
|
||||||
|
count = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
String runLengthDecode(String rle) {
|
||||||
|
StringBuilder result = new StringBuilder();
|
||||||
|
char[] chars = rle.toCharArray();
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
for (char c : chars) {
|
||||||
|
if (Character.isDigit(c)) {
|
||||||
|
count = 10 * count + Character.getNumericValue(c);
|
||||||
|
} else {
|
||||||
|
result.append(String.join("", Collections.nCopies(count, String.valueOf(c))));
|
||||||
|
count = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
String runLengthEncodeByRegEx(String input) {
|
||||||
|
String[] arr = input.split("(?<=(\\D))(?!\\1)");
|
||||||
|
StringBuilder result = new StringBuilder();
|
||||||
|
for (String run : arr) {
|
||||||
|
result.append(run.length()).append(run.charAt(0));
|
||||||
|
}
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
String runLengthDecodeByRegEx(String rle) {
|
||||||
|
if (rle.isEmpty()) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
String[] arr = rle.split("(?<=\\D)|(?=\\D+)");
|
||||||
|
if (arr.length % 2 != 0) {
|
||||||
|
throw new IllegalArgumentException("Not a RLE string");
|
||||||
|
}
|
||||||
|
StringBuilder result = new StringBuilder();
|
||||||
|
|
||||||
|
for (int i = 1; i <= arr.length; i += 2) {
|
||||||
|
int count = Integer.parseInt(arr[i - 1]);
|
||||||
|
String c = arr[i];
|
||||||
|
|
||||||
|
result.append(String.join("", Collections.nCopies(count, c)));
|
||||||
|
}
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void whenInvokingRunLengthEncode_thenGetExpectedResult() {
|
||||||
|
assertEquals(RLE, runLengthEncode(INPUT));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void whenInvokingRunLengthDecode_thenGetExpectedResult() {
|
||||||
|
assertEquals(INPUT, runLengthDecode(RLE));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void whenInvokingRunLengthEncodeByRegEx_thenGetExpectedResult() {
|
||||||
|
assertEquals(RLE, runLengthEncodeByRegEx(INPUT));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void whenInvokingRunLengthDecodeByRegEx_thenGetExpectedResult() {
|
||||||
|
assertEquals(INPUT, runLengthDecodeByRegEx(RLE));
|
||||||
|
}
|
||||||
|
}
|
@ -14,3 +14,4 @@
|
|||||||
- [UTF-8 Validation in Java](https://www.baeldung.com/java-utf-8-validation)
|
- [UTF-8 Validation in Java](https://www.baeldung.com/java-utf-8-validation)
|
||||||
- [Simple Morse Code Translation in Java](https://www.baeldung.com/java-morse-code-english-translate)
|
- [Simple Morse Code Translation in Java](https://www.baeldung.com/java-morse-code-english-translate)
|
||||||
- [How to Determine if a String Contains Invalid Encoded Characters](https://www.baeldung.com/java-check-string-contains-invalid-encoded-characters)
|
- [How to Determine if a String Contains Invalid Encoded Characters](https://www.baeldung.com/java-check-string-contains-invalid-encoded-characters)
|
||||||
|
- [Regular Expression for Password Validation in Java](https://www.baeldung.com/java-regex-password-validation)
|
||||||
|
@ -14,7 +14,7 @@ public class DecodeUUIDStringFromBase64UnitTest {
|
|||||||
private final UUID originalUUID = UUID.fromString("cc5f93f7-8cf1-4a51-83c6-e740313a0c6c");
|
private final UUID originalUUID = UUID.fromString("cc5f93f7-8cf1-4a51-83c6-e740313a0c6c");
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldDecodeUUIDUsingByteArrayAndBase64Decoder() {
|
public void givenEncodedString_whenDecodingUsingBase64Decoder_thenGiveExpectedUUID() {
|
||||||
String expectedEncodedString = "UUrxjPeTX8xsDDoxQOfGgw";
|
String expectedEncodedString = "UUrxjPeTX8xsDDoxQOfGgw";
|
||||||
byte[] decodedBytes = Base64.getDecoder()
|
byte[] decodedBytes = Base64.getDecoder()
|
||||||
.decode(expectedEncodedString);
|
.decode(expectedEncodedString);
|
||||||
@ -23,7 +23,7 @@ public class DecodeUUIDStringFromBase64UnitTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldDecodeUUIDUsingByteBufferAndBase64UrlDecoder() {
|
public void givenEncodedString_whenDecodingUsingByteBufferAndBase64UrlDecoder_thenGiveExpectedUUID() {
|
||||||
String expectedEncodedString = "zF-T94zxSlGDxudAMToMbA";
|
String expectedEncodedString = "zF-T94zxSlGDxudAMToMbA";
|
||||||
byte[] decodedBytes = Base64.getUrlDecoder()
|
byte[] decodedBytes = Base64.getUrlDecoder()
|
||||||
.decode(expectedEncodedString);
|
.decode(expectedEncodedString);
|
||||||
@ -35,7 +35,7 @@ public class DecodeUUIDStringFromBase64UnitTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldDecodeUUIDUsingApacheUtils() {
|
public void givenEncodedString_whenDecodingUsingApacheUtils_thenGiveExpectedUUID() {
|
||||||
String expectedEncodedString = "UUrxjPeTX8xsDDoxQOfGgw";
|
String expectedEncodedString = "UUrxjPeTX8xsDDoxQOfGgw";
|
||||||
byte[] decodedBytes = decodeBase64(expectedEncodedString);
|
byte[] decodedBytes = decodeBase64(expectedEncodedString);
|
||||||
UUID uuid = Conversion.byteArrayToUuid(decodedBytes, 0);
|
UUID uuid = Conversion.byteArrayToUuid(decodedBytes, 0);
|
||||||
|
@ -14,7 +14,7 @@ public class EncodeUUIDToBase64StringUnitTest {
|
|||||||
private final UUID originalUUID = UUID.fromString("cc5f93f7-8cf1-4a51-83c6-e740313a0c6c");
|
private final UUID originalUUID = UUID.fromString("cc5f93f7-8cf1-4a51-83c6-e740313a0c6c");
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldEncodeUUIDUsingByteArrayAndBase64Encoder() {
|
public void givenUUID_whenEncodingUsingBase64Encoder_thenGiveExpectedEncodedString() {
|
||||||
String expectedEncodedString = "UUrxjPeTX8xsDDoxQOfGgw";
|
String expectedEncodedString = "UUrxjPeTX8xsDDoxQOfGgw";
|
||||||
byte[] uuidBytes = convertToByteArray(originalUUID);
|
byte[] uuidBytes = convertToByteArray(originalUUID);
|
||||||
String encodedUUID = Base64.getEncoder().withoutPadding()
|
String encodedUUID = Base64.getEncoder().withoutPadding()
|
||||||
@ -23,7 +23,7 @@ public class EncodeUUIDToBase64StringUnitTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldEncodeUUIDUsingByteBufferAndBase64UrlEncoder() {
|
public void givenUUID_whenEncodingUsingByteBufferAndBase64UrlEncoder_thenGiveExpectedEncodedString() {
|
||||||
String expectedEncodedString = "zF-T94zxSlGDxudAMToMbA";
|
String expectedEncodedString = "zF-T94zxSlGDxudAMToMbA";
|
||||||
ByteBuffer byteBuffer = ByteBuffer.wrap(new byte[16]);
|
ByteBuffer byteBuffer = ByteBuffer.wrap(new byte[16]);
|
||||||
byteBuffer.putLong(originalUUID.getMostSignificantBits());
|
byteBuffer.putLong(originalUUID.getMostSignificantBits());
|
||||||
@ -34,7 +34,7 @@ public class EncodeUUIDToBase64StringUnitTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldEncodeUUIDUsingApacheUtils() {
|
public void givenUUID_whenEncodingUsingApacheUtils_thenGiveExpectedEncodedString() {
|
||||||
String expectedEncodedString = "UUrxjPeTX8xsDDoxQOfGgw";
|
String expectedEncodedString = "UUrxjPeTX8xsDDoxQOfGgw";
|
||||||
byte[] bytes = Conversion.uuidToByteArray(originalUUID, new byte[16], 0, 16);
|
byte[] bytes = Conversion.uuidToByteArray(originalUUID, new byte[16], 0, 16);
|
||||||
String encodedUUID = encodeBase64URLSafeString(bytes);
|
String encodedUUID = encodeBase64URLSafeString(bytes);
|
||||||
|
BIN
javax-sound/src/main/resources/AudioFileWithMpegFormat.mpeg
Normal file
BIN
javax-sound/src/main/resources/AudioFileWithMpegFormat.mpeg
Normal file
Binary file not shown.
BIN
javax-sound/src/main/resources/AudioFileWithWavFormat.wav
Normal file
BIN
javax-sound/src/main/resources/AudioFileWithWavFormat.wav
Normal file
Binary file not shown.
2
logging-modules/logging-techniques/README.md
Normal file
2
logging-modules/logging-techniques/README.md
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
### Relevant Articles:
|
||||||
|
- [Structured Logging in Java](https://www.baeldung.com/java-structured-logging)
|
@ -8,6 +8,36 @@
|
|||||||
<version>0.0.1-SNAPSHOT</version>
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
<name>maven-exec-plugin</name>
|
<name>maven-exec-plugin</name>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.maven.shared</groupId>
|
||||||
|
<artifactId>maven-invoker</artifactId>
|
||||||
|
<version>${apache.maven.invoker.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.maven</groupId>
|
||||||
|
<artifactId>maven-embedder</artifactId>
|
||||||
|
<version>${apache.maven.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter</artifactId>
|
||||||
|
<version>${junit.jupiter.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-engine</artifactId>
|
||||||
|
<version>${junit.jupiter.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-api</artifactId>
|
||||||
|
<version>${junit.jupiter.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
@ -38,6 +68,9 @@
|
|||||||
<properties>
|
<properties>
|
||||||
<maven-compiler-plugin.version>3.12.1</maven-compiler-plugin.version>
|
<maven-compiler-plugin.version>3.12.1</maven-compiler-plugin.version>
|
||||||
<exec-maven-plugin.version>3.1.0</exec-maven-plugin.version>
|
<exec-maven-plugin.version>3.1.0</exec-maven-plugin.version>
|
||||||
|
<junit.jupiter.version>5.10.0</junit.jupiter.version>
|
||||||
|
<apache.maven.version>3.9.6</apache.maven.version>
|
||||||
|
<apache.maven.invoker.version>3.2.0</apache.maven.invoker.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
</project>
|
</project>
|
@ -0,0 +1,17 @@
|
|||||||
|
package com.baeldung.learningplatform;
|
||||||
|
|
||||||
|
public enum JavaVersion {
|
||||||
|
|
||||||
|
JAVA_8("1.8"), JAVA_9("9"), JAVA_17("17");
|
||||||
|
|
||||||
|
private final String version;
|
||||||
|
|
||||||
|
|
||||||
|
JavaVersion(String version) {
|
||||||
|
this.version = version;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getVersion() {
|
||||||
|
return this.version;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
package com.baeldung.learningplatform;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
public interface Maven {
|
||||||
|
String POM_XML = "pom.xml";
|
||||||
|
String COMPILE_GOAL = "compile";
|
||||||
|
String USE_CUSTOM_POM = "-f";
|
||||||
|
int OK = 0;
|
||||||
|
String MVN = "mvn";
|
||||||
|
|
||||||
|
void compile(Path projectFolder);
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
package com.baeldung.learningplatform;
|
||||||
|
|
||||||
|
public class MavenCompilationException extends RuntimeException {
|
||||||
|
|
||||||
|
public MavenCompilationException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MavenCompilationException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package com.baeldung.learningplatform;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import org.apache.maven.cli.MavenCli;
|
||||||
|
|
||||||
|
public class MavenEmbedder implements Maven {
|
||||||
|
|
||||||
|
public static final String MVN_HOME = "maven.multiModuleProjectDirectory";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void compile(Path projectFolder) {
|
||||||
|
MavenCli cli = new MavenCli();
|
||||||
|
System.setProperty(MVN_HOME, projectFolder.toString());
|
||||||
|
cli.doMain(new String[]{COMPILE_GOAL}, projectFolder.toString(), null, null);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
package com.baeldung.learningplatform;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
public abstract class MavenExecutorAdapter implements Maven {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void compile(Path projectFolder) {
|
||||||
|
int exitCode;
|
||||||
|
try {
|
||||||
|
exitCode = execute(projectFolder, COMPILE_GOAL);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new MavenCompilationException("Interrupted during compilation", e);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new MavenCompilationException("Incorrect execution", e);
|
||||||
|
}
|
||||||
|
if (exitCode != OK) {
|
||||||
|
throw new MavenCompilationException("Failure during compilation: " + exitCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract int execute(Path projectFolder, String compileGoal)
|
||||||
|
throws InterruptedException, IOException;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
package com.baeldung.learningplatform;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Collections;
|
||||||
|
import org.apache.maven.shared.invoker.DefaultInvocationRequest;
|
||||||
|
import org.apache.maven.shared.invoker.DefaultInvoker;
|
||||||
|
import org.apache.maven.shared.invoker.InvocationRequest;
|
||||||
|
import org.apache.maven.shared.invoker.InvocationResult;
|
||||||
|
import org.apache.maven.shared.invoker.Invoker;
|
||||||
|
import org.apache.maven.shared.invoker.MavenInvocationException;
|
||||||
|
|
||||||
|
public class MavenInvoker implements Maven {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void compile(Path projectFolder) {
|
||||||
|
InvocationRequest request = new DefaultInvocationRequest();
|
||||||
|
request.setPomFile(projectFolder.resolve(POM_XML).toFile());
|
||||||
|
request.setGoals(Collections.singletonList(Maven.COMPILE_GOAL));
|
||||||
|
Invoker invoker = new DefaultInvoker();
|
||||||
|
try {
|
||||||
|
InvocationResult result = invoker.execute(request);
|
||||||
|
if (result.getExitCode() != 0) {
|
||||||
|
throw new MavenCompilationException("Build failed", result.getExecutionException());
|
||||||
|
}
|
||||||
|
} catch (MavenInvocationException e) {
|
||||||
|
throw new MavenCompilationException("Exception during Maven invocation", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package com.baeldung.learningplatform;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
public class MavenProcessBuilder extends MavenExecutorAdapter {
|
||||||
|
private static final ProcessBuilder PROCESS_BUILDER = new ProcessBuilder();
|
||||||
|
|
||||||
|
protected int execute(Path projectFolder, String compileGoal) throws IOException, InterruptedException {
|
||||||
|
Process process = PROCESS_BUILDER
|
||||||
|
.command(MVN, USE_CUSTOM_POM, projectFolder.resolve(POM_XML).toString(), compileGoal)
|
||||||
|
.start();
|
||||||
|
return process.waitFor();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
package com.baeldung.learningplatform;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
public class MavenRuntimeExec extends MavenExecutorAdapter {
|
||||||
|
@Override
|
||||||
|
protected int execute(Path projectFolder, String compileGoal) throws InterruptedException, IOException {
|
||||||
|
String[] arguments = {MVN, USE_CUSTOM_POM, projectFolder.resolve(POM_XML).toString(), COMPILE_GOAL};
|
||||||
|
Process process = Runtime.getRuntime().exec(arguments);
|
||||||
|
return process.waitFor();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,100 @@
|
|||||||
|
package com.baeldung.learningplatform;
|
||||||
|
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.FileSystems;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import org.apache.maven.model.Build;
|
||||||
|
import org.apache.maven.model.Dependency;
|
||||||
|
import org.apache.maven.model.Model;
|
||||||
|
import org.apache.maven.model.Plugin;
|
||||||
|
import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
|
||||||
|
import org.codehaus.plexus.util.xml.Xpp3Dom;
|
||||||
|
|
||||||
|
public class ProjectBuilder {
|
||||||
|
|
||||||
|
private static final String PACKAGE = "package ";
|
||||||
|
private static final String POM_XML = "pom.xml";
|
||||||
|
private static final String SRC_TEST = "src/test/";
|
||||||
|
private static final String SRC_MAIN_JAVA = "src/main/java/";
|
||||||
|
private static final String PACKAGE_DELIMITER = ".";
|
||||||
|
private static final String MAIN_JAVA = "Main.java";
|
||||||
|
private final List<Dependency> dependencies = new ArrayList<>();
|
||||||
|
private JavaVersion javaVersion = JavaVersion.JAVA_8;
|
||||||
|
|
||||||
|
public ProjectBuilder addDependency(String groupId, String artifactId, String version) {
|
||||||
|
Dependency dependency = new Dependency();
|
||||||
|
dependency.setGroupId(groupId);
|
||||||
|
dependency.setArtifactId(artifactId);
|
||||||
|
dependency.setVersion(version);
|
||||||
|
dependencies.add(dependency);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProjectBuilder setJavaVersion(JavaVersion version) {
|
||||||
|
this.javaVersion = version;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void build(String userName, Path projectPath, String packageName) throws IOException {
|
||||||
|
Model model = new Model();
|
||||||
|
configureModel(userName, model);
|
||||||
|
dependencies.forEach(model::addDependency);
|
||||||
|
Build build = configureJavaVersion();
|
||||||
|
model.setBuild(build);
|
||||||
|
MavenXpp3Writer writer = new MavenXpp3Writer();
|
||||||
|
writer.write(new FileWriter(projectPath.resolve(POM_XML).toFile()), model);
|
||||||
|
generateFolders(projectPath, SRC_TEST);
|
||||||
|
|
||||||
|
Path generatedPackage = generateFolders(projectPath,
|
||||||
|
SRC_MAIN_JAVA +
|
||||||
|
packageName.replace(PACKAGE_DELIMITER, FileSystems.getDefault().getSeparator()));
|
||||||
|
String generatedClass = generateMainClass(PACKAGE + packageName);
|
||||||
|
Files.writeString(generatedPackage.resolve(MAIN_JAVA), generatedClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void configureModel(String userName, Model model) {
|
||||||
|
model.setModelVersion("4.0.0");
|
||||||
|
model.setArtifactId("com." + userName.toLowerCase());
|
||||||
|
model.setGroupId("learning-project");
|
||||||
|
model.setVersion("0.0.1-SNAPSHOT");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String generateMainClass(String packageName) {
|
||||||
|
return packageName + ";\n" +
|
||||||
|
"\n" +
|
||||||
|
"public class Main {\n" +
|
||||||
|
" public static void main(String[] args){\n" +
|
||||||
|
" System.out.println(\"Hello World!\");\n" +
|
||||||
|
" }\n" +
|
||||||
|
"}\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Path generateFolders(Path sourceFolder, String packageName) throws IOException {
|
||||||
|
return Files.createDirectories(sourceFolder.resolve(packageName));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Build configureJavaVersion() {
|
||||||
|
Plugin plugin = new Plugin();
|
||||||
|
plugin.setGroupId("org.apache.maven.plugins");
|
||||||
|
plugin.setArtifactId("maven-compiler-plugin");
|
||||||
|
plugin.setVersion("3.8.1");
|
||||||
|
|
||||||
|
Xpp3Dom configuration = new Xpp3Dom("configuration");
|
||||||
|
Xpp3Dom source = new Xpp3Dom("source");
|
||||||
|
source.setValue(javaVersion.getVersion());
|
||||||
|
Xpp3Dom target = new Xpp3Dom("target");
|
||||||
|
target.setValue(javaVersion.getVersion());
|
||||||
|
configuration.addChild(source);
|
||||||
|
configuration.addChild(target);
|
||||||
|
|
||||||
|
plugin.setConfiguration(configuration);
|
||||||
|
|
||||||
|
Build build = new Build();
|
||||||
|
build.addPlugin(plugin);
|
||||||
|
return build;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
package com.baeldung.learningplatform;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.FileVisitResult;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.SimpleFileVisitor;
|
||||||
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
|
|
||||||
|
public class FileUtil {
|
||||||
|
|
||||||
|
private FileUtil() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void removeDirectoryRecursively(Path folder) throws IOException {
|
||||||
|
if (Files.exists(folder)) {
|
||||||
|
Files.walkFileTree(folder, new SimpleFileVisitor<>() {
|
||||||
|
@Override
|
||||||
|
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
||||||
|
Files.delete(file);
|
||||||
|
return FileVisitResult.CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
|
||||||
|
Files.delete(dir);
|
||||||
|
return FileVisitResult.CONTINUE;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
package com.baeldung.learningplatform;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.io.TempDir;
|
||||||
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
|
import org.junit.jupiter.params.provider.MethodSource;
|
||||||
|
|
||||||
|
class MavenRuntimeExecUnitTest {
|
||||||
|
|
||||||
|
private static final String PACKAGE_NAME = "com.baeldung.generatedcode";
|
||||||
|
private static final String USER_NAME = "john_doe";
|
||||||
|
@TempDir
|
||||||
|
private Path tempDir;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void setUp() throws IOException {
|
||||||
|
ProjectBuilder projectBuilder = new ProjectBuilder();
|
||||||
|
projectBuilder.build(USER_NAME, tempDir, PACKAGE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource
|
||||||
|
void givenMavenInterface_whenCompileMavenProject_thenCreateTargetDirectory(Maven maven) {
|
||||||
|
maven.compile(tempDir);
|
||||||
|
assertTrue(Files.exists(tempDir));
|
||||||
|
}
|
||||||
|
|
||||||
|
static Stream<Maven> givenMavenInterface_whenCompileMavenProject_thenCreateTargetDirectory() {
|
||||||
|
return Stream.of(
|
||||||
|
new MavenRuntimeExec(),
|
||||||
|
new MavenProcessBuilder(),
|
||||||
|
new MavenEmbedder(),
|
||||||
|
new MavenInvoker());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
package com.baeldung.learningplatform;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
|
||||||
|
public interface ProjectsPaths {
|
||||||
|
|
||||||
|
public static final Path PROJECT_DIR = Paths.get("src/test/resources/learning-project/");
|
||||||
|
public static final Path PROJECT_POM_XML = PROJECT_DIR.resolve("pom.xml");
|
||||||
|
public static final Path PROJECT_TARGET = PROJECT_DIR.resolve("target");
|
||||||
|
}
|
@ -12,7 +12,7 @@ class ConnectionPerChannelPublisherLiveTest {
|
|||||||
// host, workerCount, iterations, payloadSize
|
// host, workerCount, iterations, payloadSize
|
||||||
Stream.of(1,5,10,20,50,100,150)
|
Stream.of(1,5,10,20,50,100,150)
|
||||||
.forEach(workers -> {
|
.forEach(workers -> {
|
||||||
ConnectionPerChannelPublisher.main(new String[]{"192.168.99.100", Integer.toString(workers), "1000", "4096"});
|
ConnectionPerChannelPublisher.main(new String[]{"localhost", Integer.toString(workers), "1000", "4096"});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,9 +10,9 @@ class SingleConnectionPublisherLiveTest {
|
|||||||
@Test
|
@Test
|
||||||
void whenSingleChannel_thenRunBenchmark() throws Exception {
|
void whenSingleChannel_thenRunBenchmark() throws Exception {
|
||||||
// host, workerCount, iterations, payloadSize
|
// host, workerCount, iterations, payloadSize
|
||||||
Stream.of(1,5,10,20,50,100,150)
|
Stream.of(1,5,10,20,50)
|
||||||
.forEach(workers -> {
|
.forEach(workers -> {
|
||||||
SingleConnectionPublisher.main(new String[]{"192.168.99.100", Integer.toString(workers), "1000", "4096"});
|
SingleConnectionPublisher.main(new String[]{"localhost", Integer.toString(workers), "1000", "4096"});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,11 +56,17 @@ public class DynamicQueueCreationLiveTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
void givenQueueName_whenQueueDoesNotExist_thenCheckingIfQueueExists() throws IOException, TimeoutException {
|
void givenQueueName_whenQueueDoesNotExist_thenCheckingIfQueueExists() throws IOException, TimeoutException {
|
||||||
|
Channel temp = null;
|
||||||
try (Channel channel = connection.createChannel()) {
|
try {
|
||||||
|
Channel channel = connection.createChannel();
|
||||||
assertThrows(IOException.class, () -> {
|
assertThrows(IOException.class, () -> {
|
||||||
channel.queueDeclarePassive(QUEUE_NAME_NEW);
|
channel.queueDeclarePassive(QUEUE_NAME_NEW);
|
||||||
});
|
});
|
||||||
|
temp = channel;
|
||||||
|
} finally {
|
||||||
|
if(temp != null && temp.isOpen()) {
|
||||||
|
temp.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
<groupId>io.micronaut.platform</groupId>
|
<groupId>io.micronaut.platform</groupId>
|
||||||
<artifactId>micronaut-parent</artifactId>
|
<artifactId>micronaut-parent</artifactId>
|
||||||
<version>4.1.2</version>
|
<version>4.1.2</version>
|
||||||
|
<relativePath/>
|
||||||
</parent>
|
</parent>
|
||||||
<properties>
|
<properties>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
@ -1 +1,2 @@
|
|||||||
### Relevant Articles:
|
### Relevant Articles:
|
||||||
|
- [Monkey Patching in Java](https://www.baeldung.com/java-monkey-patching)
|
||||||
|
@ -6,6 +6,18 @@
|
|||||||
<artifactId>core-java-persistence-3</artifactId>
|
<artifactId>core-java-persistence-3</artifactId>
|
||||||
<version>0.1.0-SNAPSHOT</version>
|
<version>0.1.0-SNAPSHOT</version>
|
||||||
<name>core-java-persistence-3</name>
|
<name>core-java-persistence-3</name>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<source>17</source>
|
||||||
|
<target>17</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<parent>
|
<parent>
|
||||||
|
@ -0,0 +1,33 @@
|
|||||||
|
package jdbcpagination;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
public class PaginationLogic {
|
||||||
|
|
||||||
|
public static ResultSet readPageWithLimitAndOffset(Connection connection, int offset, int pageSize) throws SQLException {
|
||||||
|
String sql = """
|
||||||
|
SELECT * FROM employees
|
||||||
|
LIMIT ? OFFSET ?
|
||||||
|
""";
|
||||||
|
PreparedStatement preparedStatement = connection.prepareStatement(sql);
|
||||||
|
preparedStatement.setInt(1, pageSize);
|
||||||
|
preparedStatement.setInt(2, offset);
|
||||||
|
|
||||||
|
return preparedStatement.executeQuery();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ResultSet readPageWithSortedKeys(Connection connection, int lastFetchedId, int pageSize) throws SQLException {
|
||||||
|
String sql = """
|
||||||
|
SELECT * FROM employees
|
||||||
|
WHERE id > ? LIMIT ?
|
||||||
|
""";
|
||||||
|
PreparedStatement preparedStatement = connection.prepareStatement(sql);
|
||||||
|
preparedStatement.setInt(1, lastFetchedId);
|
||||||
|
preparedStatement.setInt(2, pageSize);
|
||||||
|
|
||||||
|
return preparedStatement.executeQuery();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,134 @@
|
|||||||
|
package jdbcpagination;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.DriverManager;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.AfterAll;
|
||||||
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
public class PaginationLogicUnitTest {
|
||||||
|
private static Connection connection = null;
|
||||||
|
private static final String JDBC_URL = "jdbc:h2:mem:testDB";
|
||||||
|
private static final String USERNAME = "dbUser";
|
||||||
|
private static final String PASSWORD = "dbPassword";
|
||||||
|
|
||||||
|
@BeforeAll
|
||||||
|
public static void setup() throws Exception {
|
||||||
|
connection = connect(JDBC_URL, USERNAME, PASSWORD);
|
||||||
|
populateDB();
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterAll
|
||||||
|
public static void tearDown() throws SQLException {
|
||||||
|
destroyDB();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenDBPopulated_WhenReadPaginatedWithLimitAndOffset_ThenReturnsPaginatedResult() throws SQLException {
|
||||||
|
int offset = 0; // offset is set to 0 and keep updating with pageSize
|
||||||
|
int pageSize = 100_000;
|
||||||
|
int totalPages = 0;
|
||||||
|
while (true) {
|
||||||
|
ResultSet resultSet = PaginationLogic.readPageWithLimitAndOffset(connection, offset, pageSize);
|
||||||
|
if (!resultSet.next())
|
||||||
|
break;
|
||||||
|
List<String> resultPage = new ArrayList<>();
|
||||||
|
|
||||||
|
do {
|
||||||
|
resultPage.add(resultSet.getString("first_name"));
|
||||||
|
} while (resultSet.next());
|
||||||
|
assertEquals("firstname" + (resultPage.size() * (totalPages + 1)), resultPage.get(resultPage.size() - 1));
|
||||||
|
offset += pageSize;
|
||||||
|
totalPages++;
|
||||||
|
}
|
||||||
|
assertEquals(10, totalPages);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenDBPopulated_WhenReadPaginatedWithSortedKeys_ThenReturnsPaginatedResult() throws SQLException {
|
||||||
|
// find min and max ID
|
||||||
|
PreparedStatement preparedStatement = connection.prepareStatement("SELECT min(id) as min_id, max(id) as max_id FROM employees");
|
||||||
|
ResultSet resultSet = preparedStatement.executeQuery();
|
||||||
|
resultSet.next();
|
||||||
|
|
||||||
|
int minId = resultSet.getInt("min_id");
|
||||||
|
int maxId = resultSet.getInt("max_id");
|
||||||
|
int lastFetchedId = 0; // assign lastFetchedId to minId
|
||||||
|
|
||||||
|
int pageSize = 100_000;
|
||||||
|
int totalPages = 0;
|
||||||
|
|
||||||
|
while ((lastFetchedId + pageSize) <= maxId) {
|
||||||
|
resultSet = PaginationLogic.readPageWithSortedKeys(connection, lastFetchedId, pageSize);
|
||||||
|
if (!resultSet.next())
|
||||||
|
break;
|
||||||
|
List<String> resultPage = new ArrayList<>();
|
||||||
|
do {
|
||||||
|
resultPage.add(resultSet.getString("first_name"));
|
||||||
|
lastFetchedId = resultSet.getInt("id");
|
||||||
|
} while (resultSet.next());
|
||||||
|
assertEquals("firstname" + (resultPage.size() * (totalPages + 1)), resultPage.get(resultPage.size() - 1));
|
||||||
|
totalPages++;
|
||||||
|
}
|
||||||
|
assertEquals(10, totalPages);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void destroyDB() throws SQLException {
|
||||||
|
String destroy = """
|
||||||
|
DROP table IF EXISTS EMPLOYEES;
|
||||||
|
""";
|
||||||
|
connection.prepareStatement(destroy)
|
||||||
|
.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void populateDB() throws SQLException {
|
||||||
|
String createTable = """
|
||||||
|
CREATE TABLE EMPLOYEES (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
first_name VARCHAR(50),
|
||||||
|
last_name VARCHAR(50),
|
||||||
|
salary DECIMAL(10, 2)
|
||||||
|
);
|
||||||
|
""";
|
||||||
|
PreparedStatement preparedStatement = connection.prepareStatement(createTable);
|
||||||
|
preparedStatement.execute();
|
||||||
|
|
||||||
|
String load = """
|
||||||
|
INSERT INTO EMPLOYEES (first_name, last_name, salary)
|
||||||
|
VALUES(?,?,?)
|
||||||
|
""";
|
||||||
|
IntStream.rangeClosed(1, 1_000_000)
|
||||||
|
.forEach(i -> {
|
||||||
|
PreparedStatement preparedStatement1 = null;
|
||||||
|
try {
|
||||||
|
preparedStatement1 = connection.prepareStatement(load);
|
||||||
|
preparedStatement1.setString(1, "firstname" + i);
|
||||||
|
preparedStatement1.setString(2, "lastname" + i);
|
||||||
|
preparedStatement1.setDouble(3, 100_000 + (1_000_000 - 100_000) + Math.random());
|
||||||
|
|
||||||
|
preparedStatement1.execute();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Connection connect(String url, String user, String password) throws SQLException {
|
||||||
|
Connection connection = DriverManager.getConnection(url, user, password);
|
||||||
|
if (connection != null) {
|
||||||
|
System.out.println("Connected to database");
|
||||||
|
}
|
||||||
|
|
||||||
|
return connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -102,7 +102,7 @@
|
|||||||
<module>spring-data-solr</module>
|
<module>spring-data-solr</module>
|
||||||
<module>spring-data-shardingsphere</module>
|
<module>spring-data-shardingsphere</module>
|
||||||
<module>spring-hibernate-3</module>
|
<module>spring-hibernate-3</module>
|
||||||
<!-- <module>spring-hibernate-5</module> FAILED --> <!-- long running -->
|
<module>spring-hibernate-5</module>
|
||||||
<module>spring-hibernate-6</module>
|
<module>spring-hibernate-6</module>
|
||||||
<module>spring-jpa</module>
|
<module>spring-jpa</module>
|
||||||
<module>spring-jpa-2</module>
|
<module>spring-jpa-2</module>
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
## Relevant Articles
|
## Relevant Articles
|
||||||
- [Scroll API in Spring Data JPA](https://www.baeldung.com/spring-data-jpa-scroll-api)
|
- [Scroll API in Spring Data JPA](https://www.baeldung.com/spring-data-jpa-scroll-api)
|
||||||
- [List vs. Set in @OneToMany JPA](https://www.baeldung.com/spring-jpa-onetomany-list-vs-set)
|
- [List vs. Set in @OneToMany JPA](https://www.baeldung.com/spring-jpa-onetomany-list-vs-set)
|
||||||
|
- [N+1 Problem in Hibernate and Spring Data JPA](https://www.baeldung.com/spring-hibernate-n1-problem)
|
||||||
|
@ -6,4 +6,5 @@
|
|||||||
- [TRUNCATE TABLE in Spring Data JPA](https://www.baeldung.com/spring-data-jpa-truncate-table)
|
- [TRUNCATE TABLE in Spring Data JPA](https://www.baeldung.com/spring-data-jpa-truncate-table)
|
||||||
- [When to Use the getReferenceById() and findById() Methods in Spring Data JPA](https://www.baeldung.com/spring-data-jpa-getreferencebyid-findbyid-methods)
|
- [When to Use the getReferenceById() and findById() Methods in Spring Data JPA](https://www.baeldung.com/spring-data-jpa-getreferencebyid-findbyid-methods)
|
||||||
- [Implementing Persistable-Only Entities in Spring Data JPA](https://www.baeldung.com/spring-data-persistable-only-entities)
|
- [Implementing Persistable-Only Entities in Spring Data JPA](https://www.baeldung.com/spring-data-persistable-only-entities)
|
||||||
|
- [Storing PostgreSQL JSONB Using Spring Boot and JPA](https://www.baeldung.com/spring-boot-jpa-storing-postgresql-jsonb)
|
||||||
- More articles: [[<-- prev]](../spring-data-jpa-repo-3)
|
- More articles: [[<-- prev]](../spring-data-jpa-repo-3)
|
||||||
|
@ -125,6 +125,20 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<argLine>
|
||||||
|
--add-opens java.base/java.lang=ALL-UNNAMED
|
||||||
|
</argLine>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<!-- Spring -->
|
<!-- Spring -->
|
||||||
<org.springframework.version>5.0.2.RELEASE</org.springframework.version>
|
<org.springframework.version>5.0.2.RELEASE</org.springframework.version>
|
||||||
@ -132,7 +146,7 @@
|
|||||||
<org.springframework.security.version>4.2.1.RELEASE</org.springframework.security.version>
|
<org.springframework.security.version>4.2.1.RELEASE</org.springframework.security.version>
|
||||||
<!-- persistence -->
|
<!-- persistence -->
|
||||||
<hibernate.version>5.6.15.Final</hibernate.version>
|
<hibernate.version>5.6.15.Final</hibernate.version>
|
||||||
<hibernatesearch.version>5.8.2.Final</hibernatesearch.version>
|
<hibernatesearch.version>5.11.12.Final</hibernatesearch.version>
|
||||||
<mysql-connector-java.version>8.2.0</mysql-connector-java.version>
|
<mysql-connector-java.version>8.2.0</mysql-connector-java.version>
|
||||||
<tomcat-dbcp.version>9.0.0.M26</tomcat-dbcp.version>
|
<tomcat-dbcp.version>9.0.0.M26</tomcat-dbcp.version>
|
||||||
<jta.version>1.1</jta.version>
|
<jta.version>1.1</jta.version>
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ehcache xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="true"
|
||||||
|
monitoring="autodetect" dynamicConfig="true">
|
||||||
|
|
||||||
|
<diskStore path="java.io.tmpdir/ehcache" />
|
||||||
|
|
||||||
|
<defaultCache maxEntriesLocalHeap="10000" eternal="false"
|
||||||
|
timeToIdleSeconds="120" timeToLiveSeconds="120" diskSpoolBufferSizeMB="30"
|
||||||
|
maxEntriesLocalDisk="10000000" diskExpiryThreadIntervalSeconds="120"
|
||||||
|
memoryStoreEvictionPolicy="LRU" statistics="true">
|
||||||
|
<persistence strategy="localTempSwap" />
|
||||||
|
</defaultCache>
|
||||||
|
|
||||||
|
<cache name="org.hibernate.cache.internal.StandardQueryCache"
|
||||||
|
maxEntriesLocalHeap="5" eternal="false" timeToLiveSeconds="120">
|
||||||
|
<persistence strategy="localTempSwap" />
|
||||||
|
</cache>
|
||||||
|
|
||||||
|
</ehcache>
|
@ -7,13 +7,13 @@ import javax.persistence.*;
|
|||||||
@Entity
|
@Entity
|
||||||
@Table(name = "FOO")
|
@Table(name = "FOO")
|
||||||
@Where(clause = "DELETED = 0")
|
@Where(clause = "DELETED = 0")
|
||||||
public class Foo {
|
public class Fooo {
|
||||||
|
|
||||||
public Foo() {
|
public Fooo() {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Foo(final String name) {
|
public Fooo(final String name) {
|
||||||
super();
|
super();
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
@ -14,7 +14,7 @@ import org.springframework.transaction.annotation.Transactional;
|
|||||||
import com.baeldung.persistence.deletion.config.PersistenceJPAConfigDeletion;
|
import com.baeldung.persistence.deletion.config.PersistenceJPAConfigDeletion;
|
||||||
import com.baeldung.persistence.deletion.model.Bar;
|
import com.baeldung.persistence.deletion.model.Bar;
|
||||||
import com.baeldung.persistence.deletion.model.Baz;
|
import com.baeldung.persistence.deletion.model.Baz;
|
||||||
import com.baeldung.persistence.deletion.model.Foo;
|
import com.baeldung.persistence.deletion.model.Fooo;
|
||||||
|
|
||||||
import javax.persistence.EntityManager;
|
import javax.persistence.EntityManager;
|
||||||
import javax.persistence.PersistenceContext;
|
import javax.persistence.PersistenceContext;
|
||||||
@ -41,29 +41,29 @@ public class DeletionIntegrationTest {
|
|||||||
@Test
|
@Test
|
||||||
@Transactional
|
@Transactional
|
||||||
public final void givenEntityIsRemoved_thenItIsNotInDB() {
|
public final void givenEntityIsRemoved_thenItIsNotInDB() {
|
||||||
Foo foo = new Foo("foo");
|
Fooo fooo = new Fooo("foo");
|
||||||
entityManager.persist(foo);
|
entityManager.persist(fooo);
|
||||||
flushAndClear();
|
flushAndClear();
|
||||||
|
|
||||||
foo = entityManager.find(Foo.class, foo.getId());
|
fooo = entityManager.find(Fooo.class, fooo.getId());
|
||||||
assertThat(foo, notNullValue());
|
assertThat(fooo, notNullValue());
|
||||||
|
|
||||||
entityManager.remove(foo);
|
entityManager.remove(fooo);
|
||||||
flushAndClear();
|
flushAndClear();
|
||||||
|
|
||||||
assertThat(entityManager.find(Foo.class, foo.getId()), nullValue());
|
assertThat(entityManager.find(Fooo.class, fooo.getId()), nullValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Transactional
|
@Transactional
|
||||||
public final void givenEntityIsRemovedAndReferencedByAnotherEntity_thenItIsNotRemoved() {
|
public final void givenEntityIsRemovedAndReferencedByAnotherEntity_thenItIsNotRemoved() {
|
||||||
Bar bar = new Bar("bar");
|
Bar bar = new Bar("bar");
|
||||||
Foo foo = new Foo("foo");
|
Fooo fooo = new Fooo("foo");
|
||||||
foo.setBar(bar);
|
fooo.setBar(bar);
|
||||||
entityManager.persist(foo);
|
entityManager.persist(fooo);
|
||||||
flushAndClear();
|
flushAndClear();
|
||||||
|
|
||||||
foo = entityManager.find(Foo.class, foo.getId());
|
fooo = entityManager.find(Fooo.class, fooo.getId());
|
||||||
bar = entityManager.find(Bar.class, bar.getId());
|
bar = entityManager.find(Bar.class, bar.getId());
|
||||||
entityManager.remove(bar);
|
entityManager.remove(bar);
|
||||||
flushAndClear();
|
flushAndClear();
|
||||||
@ -71,8 +71,8 @@ public class DeletionIntegrationTest {
|
|||||||
bar = entityManager.find(Bar.class, bar.getId());
|
bar = entityManager.find(Bar.class, bar.getId());
|
||||||
assertThat(bar, notNullValue());
|
assertThat(bar, notNullValue());
|
||||||
|
|
||||||
foo = entityManager.find(Foo.class, foo.getId());
|
fooo = entityManager.find(Fooo.class, fooo.getId());
|
||||||
foo.setBar(null);
|
fooo.setBar(null);
|
||||||
entityManager.remove(bar);
|
entityManager.remove(bar);
|
||||||
flushAndClear();
|
flushAndClear();
|
||||||
|
|
||||||
@ -83,16 +83,16 @@ public class DeletionIntegrationTest {
|
|||||||
@Transactional
|
@Transactional
|
||||||
public final void givenEntityIsRemoved_thenRemovalIsCascaded() {
|
public final void givenEntityIsRemoved_thenRemovalIsCascaded() {
|
||||||
Bar bar = new Bar("bar");
|
Bar bar = new Bar("bar");
|
||||||
Foo foo = new Foo("foo");
|
Fooo fooo = new Fooo("foo");
|
||||||
foo.setBar(bar);
|
fooo.setBar(bar);
|
||||||
entityManager.persist(foo);
|
entityManager.persist(fooo);
|
||||||
flushAndClear();
|
flushAndClear();
|
||||||
|
|
||||||
foo = entityManager.find(Foo.class, foo.getId());
|
fooo = entityManager.find(Fooo.class, fooo.getId());
|
||||||
entityManager.remove(foo);
|
entityManager.remove(fooo);
|
||||||
flushAndClear();
|
flushAndClear();
|
||||||
|
|
||||||
assertThat(entityManager.find(Foo.class, foo.getId()), nullValue());
|
assertThat(entityManager.find(Fooo.class, fooo.getId()), nullValue());
|
||||||
assertThat(entityManager.find(Bar.class, bar.getId()), nullValue());
|
assertThat(entityManager.find(Bar.class, bar.getId()), nullValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,39 +116,39 @@ public class DeletionIntegrationTest {
|
|||||||
@Test
|
@Test
|
||||||
@Transactional
|
@Transactional
|
||||||
public final void givenEntityIsDeletedWithJpaBulkDeleteStatement_thenItIsNotInDB() {
|
public final void givenEntityIsDeletedWithJpaBulkDeleteStatement_thenItIsNotInDB() {
|
||||||
Foo foo = new Foo("foo");
|
Fooo fooo = new Fooo("foo");
|
||||||
entityManager.persist(foo);
|
entityManager.persist(fooo);
|
||||||
flushAndClear();
|
flushAndClear();
|
||||||
|
|
||||||
entityManager.createQuery("delete from Foo where id = :id").setParameter("id", foo.getId()).executeUpdate();
|
entityManager.createQuery("delete from Foo where id = :id").setParameter("id", fooo.getId()).executeUpdate();
|
||||||
|
|
||||||
assertThat(entityManager.find(Foo.class, foo.getId()), nullValue());
|
assertThat(entityManager.find(Fooo.class, fooo.getId()), nullValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Transactional
|
@Transactional
|
||||||
public final void givenEntityIsDeletedWithNativeQuery_thenItIsNotInDB() {
|
public final void givenEntityIsDeletedWithNativeQuery_thenItIsNotInDB() {
|
||||||
Foo foo = new Foo("foo");
|
Fooo fooo = new Fooo("foo");
|
||||||
entityManager.persist(foo);
|
entityManager.persist(fooo);
|
||||||
flushAndClear();
|
flushAndClear();
|
||||||
|
|
||||||
entityManager.createNativeQuery("delete from FOO where ID = :id").setParameter("id", foo.getId()).executeUpdate();
|
entityManager.createNativeQuery("delete from FOO where ID = :id").setParameter("id", fooo.getId()).executeUpdate();
|
||||||
|
|
||||||
assertThat(entityManager.find(Foo.class, foo.getId()), nullValue());
|
assertThat(entityManager.find(Fooo.class, fooo.getId()), nullValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Transactional
|
@Transactional
|
||||||
public final void givenEntityIsSoftDeleted_thenItIsNotReturnedFromQueries() {
|
public final void givenEntityIsSoftDeleted_thenItIsNotReturnedFromQueries() {
|
||||||
Foo foo = new Foo("foo");
|
Fooo fooo = new Fooo("foo");
|
||||||
entityManager.persist(foo);
|
entityManager.persist(fooo);
|
||||||
flushAndClear();
|
flushAndClear();
|
||||||
|
|
||||||
foo = entityManager.find(Foo.class, foo.getId());
|
fooo = entityManager.find(Fooo.class, fooo.getId());
|
||||||
foo.setDeleted();
|
fooo.setDeleted();
|
||||||
flushAndClear();
|
flushAndClear();
|
||||||
|
|
||||||
assertThat(entityManager.find(Foo.class, foo.getId()), nullValue());
|
assertThat(entityManager.find(Fooo.class, fooo.getId()), nullValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void flushAndClear() {
|
private void flushAndClear() {
|
||||||
|
@ -55,7 +55,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.jsonwebtoken</groupId>
|
<groupId>io.jsonwebtoken</groupId>
|
||||||
<artifactId>jjwt-api</artifactId>
|
<artifactId>jjwt-api</artifactId>
|
||||||
<version>0.12.3</version>
|
<version>${jjwt.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- persistence -->
|
<!-- persistence -->
|
||||||
<dependency>
|
<dependency>
|
||||||
@ -107,6 +107,18 @@
|
|||||||
<artifactId>jackson-core</artifactId>
|
<artifactId>jackson-core</artifactId>
|
||||||
<version>${jakson-core.version}</version>
|
<version>${jakson-core.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ch.qos.logback</groupId>
|
||||||
|
<artifactId>logback-classic</artifactId>
|
||||||
|
<version>${logback.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ch.qos.logback</groupId>
|
||||||
|
<artifactId>logback-core</artifactId>
|
||||||
|
<version>${logback.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
@ -115,8 +127,11 @@
|
|||||||
<spring-boot.version>3.1.0</spring-boot.version>
|
<spring-boot.version>3.1.0</spring-boot.version>
|
||||||
<!-- persistence -->
|
<!-- persistence -->
|
||||||
<tomcat-dbcp.version>10.1.9</tomcat-dbcp.version>
|
<tomcat-dbcp.version>10.1.9</tomcat-dbcp.version>
|
||||||
<jakson-databind.version>2.15.1</jakson-databind.version>
|
<jakson-databind.version>2.16.1</jakson-databind.version>
|
||||||
<jakson-core.version>2.14.2</jakson-core.version>
|
<jakson-core.version>2.16.1</jakson-core.version>
|
||||||
|
|
||||||
|
<jjwt.version>0.12.3</jjwt.version>
|
||||||
|
<logback.version>1.4.14</logback.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
</project>
|
</project>
|
@ -1,5 +1,6 @@
|
|||||||
package com.baeldung.multitenant.config;
|
package com.baeldung.multitenant.config;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
import org.springframework.boot.jdbc.DataSourceBuilder;
|
import org.springframework.boot.jdbc.DataSourceBuilder;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
@ -18,6 +19,9 @@ import java.util.Properties;
|
|||||||
@Configuration
|
@Configuration
|
||||||
public class MultitenantConfiguration {
|
public class MultitenantConfiguration {
|
||||||
|
|
||||||
|
@Value("${defaultTenant}")
|
||||||
|
private String defaultTenant;
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@ConfigurationProperties(prefix = "tenants")
|
@ConfigurationProperties(prefix = "tenants")
|
||||||
public DataSource dataSource() {
|
public DataSource dataSource() {
|
||||||
@ -43,7 +47,7 @@ public class MultitenantConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
AbstractRoutingDataSource dataSource = new MultitenantDataSource();
|
AbstractRoutingDataSource dataSource = new MultitenantDataSource();
|
||||||
dataSource.setDefaultTargetDataSource(resolvedDataSources.get("tenant_1"));
|
dataSource.setDefaultTargetDataSource(resolvedDataSources.get(defaultTenant));
|
||||||
dataSource.setTargetDataSources(resolvedDataSources);
|
dataSource.setTargetDataSources(resolvedDataSources);
|
||||||
|
|
||||||
dataSource.afterPropertiesSet();
|
dataSource.afterPropertiesSet();
|
||||||
|
@ -1,26 +1,31 @@
|
|||||||
package com.baeldung.multitenant.security;
|
package com.baeldung.multitenant.security;
|
||||||
|
|
||||||
import io.jsonwebtoken.Jwts;
|
import io.jsonwebtoken.Jwts;
|
||||||
import io.jsonwebtoken.SignatureAlgorithm;
|
import io.jsonwebtoken.security.Keys;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import javax.crypto.SecretKey;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
public class AuthenticationService {
|
public class AuthenticationService {
|
||||||
|
|
||||||
private static final long EXPIRATIONTIME = 864_000_00; // 1 day in milliseconds
|
private static final long EXPIRATIONTIME = 864_000_00; // 1 day in milliseconds
|
||||||
private static final String SIGNINGKEY = "SecretKey";
|
private static final String SECRETKEY = "q3t6w9zCFJNcQfTjWnq3t6w9zCFJNcQfTjWnZr4u7xADGKaPd";
|
||||||
|
private static final SecretKey SIGNINGKEY = Keys.hmacShaKeyFor(SECRETKEY.getBytes(StandardCharsets.UTF_8));
|
||||||
private static final String PREFIX = "Bearer";
|
private static final String PREFIX = "Bearer";
|
||||||
|
|
||||||
public static void addToken(HttpServletResponse res, String username, String tenant) {
|
public static void addToken(HttpServletResponse res, String username, String tenant) {
|
||||||
String JwtToken = Jwts.builder().setSubject(username)
|
String JwtToken = Jwts.builder()
|
||||||
.setAudience(tenant)
|
.subject(username)
|
||||||
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATIONTIME))
|
.audience().add(tenant).and()
|
||||||
.signWith(SignatureAlgorithm.HS512, SIGNINGKEY)
|
.issuedAt(new Date(System.currentTimeMillis()))
|
||||||
|
.expiration(new Date(System.currentTimeMillis() + EXPIRATIONTIME))
|
||||||
|
.signWith(SIGNINGKEY)
|
||||||
.compact();
|
.compact();
|
||||||
res.addHeader("Authorization", PREFIX + " " + JwtToken);
|
res.addHeader("Authorization", PREFIX + " " + JwtToken);
|
||||||
}
|
}
|
||||||
@ -29,9 +34,8 @@ public class AuthenticationService {
|
|||||||
String token = req.getHeader("Authorization");
|
String token = req.getHeader("Authorization");
|
||||||
if (token != null) {
|
if (token != null) {
|
||||||
String user = Jwts.parser()
|
String user = Jwts.parser()
|
||||||
.setSigningKey(SIGNINGKEY)
|
.verifyWith(SIGNINGKEY)
|
||||||
.build().parseClaimsJws(token.replace(PREFIX, ""))
|
.build().parseClaimsJws(token.replace(PREFIX, "").trim()).getPayload()
|
||||||
.getBody()
|
|
||||||
.getSubject();
|
.getSubject();
|
||||||
if (user != null) {
|
if (user != null) {
|
||||||
return new UsernamePasswordAuthenticationToken(user, null, Collections.emptyList());
|
return new UsernamePasswordAuthenticationToken(user, null, Collections.emptyList());
|
||||||
@ -48,7 +52,7 @@ public class AuthenticationService {
|
|||||||
}
|
}
|
||||||
String tenant = Jwts.parser()
|
String tenant = Jwts.parser()
|
||||||
.setSigningKey(SIGNINGKEY)
|
.setSigningKey(SIGNINGKEY)
|
||||||
.build().parseClaimsJws(token.replace(PREFIX, ""))
|
.build().parseClaimsJws(token.replace(PREFIX, "").trim())
|
||||||
.getBody()
|
.getBody()
|
||||||
.getAudience()
|
.getAudience()
|
||||||
.iterator()
|
.iterator()
|
||||||
|
@ -4,9 +4,9 @@ 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.authentication.AuthenticationManager;
|
||||||
import org.springframework.security.config.Customizer;
|
import org.springframework.security.config.Customizer;
|
||||||
|
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
||||||
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.AbstractHttpConfigurer;
|
|
||||||
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
|
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
|
||||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||||
import org.springframework.security.core.userdetails.User;
|
import org.springframework.security.core.userdetails.User;
|
||||||
@ -42,16 +42,21 @@ public class SecurityConfiguration {
|
|||||||
return new BCryptPasswordEncoder();
|
return new BCryptPasswordEncoder();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
|
||||||
|
return authenticationConfiguration.getAuthenticationManager();
|
||||||
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||||
final AuthenticationManager authenticationManager = http.getSharedObject(AuthenticationManager.class);
|
final AuthenticationManager authenticationManager = authenticationManager(http.getSharedObject(AuthenticationConfiguration.class));
|
||||||
http
|
http
|
||||||
.authorizeHttpRequests(authorize ->
|
.authorizeHttpRequests(authorize ->
|
||||||
authorize.requestMatchers("/login").permitAll().anyRequest().authenticated())
|
authorize.requestMatchers("/login").permitAll().anyRequest().authenticated())
|
||||||
.sessionManagement(securityContext -> securityContext.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
.sessionManagement(securityContext -> securityContext.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
||||||
.addFilterBefore(new LoginFilter("/login", authenticationManager), UsernamePasswordAuthenticationFilter.class)
|
.addFilterBefore(new LoginFilter("/login", authenticationManager), UsernamePasswordAuthenticationFilter.class)
|
||||||
.addFilterBefore(new AuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
|
.addFilterBefore(new AuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
|
||||||
.csrf(AbstractHttpConfigurer::disable)
|
.csrf(csrf -> csrf.disable())
|
||||||
.headers(header -> header.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable))
|
.headers(header -> header.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable))
|
||||||
.httpBasic(Customizer.withDefaults());
|
.httpBasic(Customizer.withDefaults());
|
||||||
|
|
||||||
|
@ -9,3 +9,7 @@ spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1
|
|||||||
#spring.datasource.username=mysqluser
|
#spring.datasource.username=mysqluser
|
||||||
#spring.datasource.password=mysqlpass
|
#spring.datasource.password=mysqlpass
|
||||||
#spring.datasource.url=jdbc:mysql://localhost:3306/myDb?createDatabaseIfNotExist=true
|
#spring.datasource.url=jdbc:mysql://localhost:3306/myDb?createDatabaseIfNotExist=true
|
||||||
|
|
||||||
|
# MultiTenantApplication
|
||||||
|
defaultTenant=tenant_1
|
||||||
|
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect
|
4
pom.xml
4
pom.xml
@ -733,7 +733,7 @@
|
|||||||
<module>jackson-simple</module>
|
<module>jackson-simple</module>
|
||||||
<module>java-blockchain</module>
|
<module>java-blockchain</module>
|
||||||
<module>java-jdi</module>
|
<module>java-jdi</module>
|
||||||
<!--<module>java-panama</module>--> <!--JAVA-27339-->
|
<module>java-panama</module>
|
||||||
<module>javafx</module>
|
<module>javafx</module>
|
||||||
<module>javax-sound</module>
|
<module>javax-sound</module>
|
||||||
<module>javaxval-2</module>
|
<module>javaxval-2</module>
|
||||||
@ -973,7 +973,7 @@
|
|||||||
<module>jackson-simple</module>
|
<module>jackson-simple</module>
|
||||||
<module>java-blockchain</module>
|
<module>java-blockchain</module>
|
||||||
<module>java-jdi</module>
|
<module>java-jdi</module>
|
||||||
<!--<module>java-panama</module>--> <!--JAVA-27339-->
|
<module>java-panama</module>
|
||||||
<module>javafx</module>
|
<module>javafx</module>
|
||||||
<module>javax-sound</module>
|
<module>javax-sound</module>
|
||||||
<module>javaxval-2</module>
|
<module>javaxval-2</module>
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
<module>quarkus-jandex</module>
|
<module>quarkus-jandex</module>
|
||||||
<module>quarkus-vs-springboot</module>
|
<module>quarkus-vs-springboot</module>
|
||||||
<module>quarkus-funqy</module>
|
<module>quarkus-funqy</module>
|
||||||
|
<!-- requires Java 21 <module>quarkus-virtual-threads</module> -->
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
</project>
|
</project>
|
4
quarkus-modules/quarkus-virtual-threads/.dockerignore
Normal file
4
quarkus-modules/quarkus-virtual-threads/.dockerignore
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
*
|
||||||
|
!target/*-runner
|
||||||
|
!target/*-runner.jar
|
||||||
|
!target/lib/*
|
0
quarkus-modules/quarkus-virtual-threads/README.md
Normal file
0
quarkus-modules/quarkus-virtual-threads/README.md
Normal file
160
quarkus-modules/quarkus-virtual-threads/pom.xml
Normal file
160
quarkus-modules/quarkus-virtual-threads/pom.xml
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<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.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-virtual-threads</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>com.baeldung</groupId>
|
||||||
|
<artifactId>quarkus-modules</artifactId>
|
||||||
|
<version>1.0.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<dependencyManagement>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>${quarkus.platform.group-id}</groupId>
|
||||||
|
<artifactId>${quarkus.platform.artifact-id}</artifactId>
|
||||||
|
<version>${quarkus.platform.version}</version>
|
||||||
|
<type>pom</type>
|
||||||
|
<scope>import</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</dependencyManagement>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<compiler-plugin.version>3.11.0</compiler-plugin.version>
|
||||||
|
<maven.compiler.release>21</maven.compiler.release>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||||
|
<quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
|
||||||
|
<quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
|
||||||
|
<quarkus.platform.version>3.4.3</quarkus.platform.version>
|
||||||
|
<surefire-plugin.version>3.0.0</surefire-plugin.version>
|
||||||
|
<loom-unit.version>0.3.0</loom-unit.version>
|
||||||
|
<panache-common-deployment.version>3.6.0</panache-common-deployment.version>
|
||||||
|
<mockito-core.version>3.11.2</mockito-core.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-hibernate-validator</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-jdbc-postgresql</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-hibernate-orm-panache</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-resteasy-reactive-jackson</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-rest-client-reactive-jackson</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-arc</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.rest-assured</groupId>
|
||||||
|
<artifactId>rest-assured</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>me.escoffier.loom</groupId>
|
||||||
|
<artifactId>loom-unit</artifactId>
|
||||||
|
<version>${loom-unit.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<!-- Quarkus Test framework -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-junit5</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-panache-common-deployment</artifactId>
|
||||||
|
<version>${panache-common-deployment.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mockito</groupId>
|
||||||
|
<artifactId>mockito-core</artifactId>
|
||||||
|
<version>${mockito-core.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-panache-mock</artifactId>
|
||||||
|
<version>${panache-common-deployment.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>${quarkus.platform.group-id}</groupId>
|
||||||
|
<artifactId>quarkus-maven-plugin</artifactId>
|
||||||
|
<version>${quarkus.platform.version}</version>
|
||||||
|
<extensions>true</extensions>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>build</goal>
|
||||||
|
<goal>generate-code</goal>
|
||||||
|
<goal>generate-code-tests</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>${compiler-plugin.version}</version>
|
||||||
|
<configuration>
|
||||||
|
<compilerArgs>
|
||||||
|
<arg>-parameters</arg>
|
||||||
|
</compilerArgs>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<version>${surefire-plugin.version}</version>
|
||||||
|
<configuration>
|
||||||
|
<systemPropertyVariables>
|
||||||
|
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
|
||||||
|
<maven.home>${maven.home}</maven.home>
|
||||||
|
</systemPropertyVariables>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
<profiles>
|
||||||
|
<profile>
|
||||||
|
<id>native</id>
|
||||||
|
<activation>
|
||||||
|
<property>
|
||||||
|
<name>native</name>
|
||||||
|
</property>
|
||||||
|
</activation>
|
||||||
|
<properties>
|
||||||
|
<quarkus.package.type>native</quarkus.package.type>
|
||||||
|
</properties>
|
||||||
|
</profile>
|
||||||
|
</profiles>
|
||||||
|
</project>
|
@ -0,0 +1,97 @@
|
|||||||
|
####
|
||||||
|
# This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode
|
||||||
|
#
|
||||||
|
# Before building the container image run:
|
||||||
|
#
|
||||||
|
# ./mvnw package
|
||||||
|
#
|
||||||
|
# Then, build the image with:
|
||||||
|
#
|
||||||
|
# docker build -f src/main/docker/Dockerfile.jvm -t quarkus/virtual-threads-jvm .
|
||||||
|
#
|
||||||
|
# Then run the container using:
|
||||||
|
#
|
||||||
|
# docker run -i --rm -p 8080:8080 quarkus/virtual-threads-jvm
|
||||||
|
#
|
||||||
|
# If you want to include the debug port into your docker image
|
||||||
|
# you will have to expose the debug port (default 5005 being the default) like this : EXPOSE 8080 5005.
|
||||||
|
# Additionally you will have to set -e JAVA_DEBUG=true and -e JAVA_DEBUG_PORT=*:5005
|
||||||
|
# when running the container
|
||||||
|
#
|
||||||
|
# Then run the container using :
|
||||||
|
#
|
||||||
|
# docker run -i --rm -p 8080:8080 quarkus/virtual-threads-jvm
|
||||||
|
#
|
||||||
|
# This image uses the `run-java.sh` script to run the application.
|
||||||
|
# This scripts computes the command line to execute your Java application, and
|
||||||
|
# includes memory/GC tuning.
|
||||||
|
# You can configure the behavior using the following environment properties:
|
||||||
|
# - JAVA_OPTS: JVM options passed to the `java` command (example: "-verbose:class")
|
||||||
|
# - JAVA_OPTS_APPEND: User specified Java options to be appended to generated options
|
||||||
|
# in JAVA_OPTS (example: "-Dsome.property=foo")
|
||||||
|
# - JAVA_MAX_MEM_RATIO: Is used when no `-Xmx` option is given in JAVA_OPTS. This is
|
||||||
|
# used to calculate a default maximal heap memory based on a containers restriction.
|
||||||
|
# If used in a container without any memory constraints for the container then this
|
||||||
|
# option has no effect. If there is a memory constraint then `-Xmx` is set to a ratio
|
||||||
|
# of the container available memory as set here. The default is `50` which means 50%
|
||||||
|
# of the available memory is used as an upper boundary. You can skip this mechanism by
|
||||||
|
# setting this value to `0` in which case no `-Xmx` option is added.
|
||||||
|
# - JAVA_INITIAL_MEM_RATIO: Is used when no `-Xms` option is given in JAVA_OPTS. This
|
||||||
|
# is used to calculate a default initial heap memory based on the maximum heap memory.
|
||||||
|
# If used in a container without any memory constraints for the container then this
|
||||||
|
# option has no effect. If there is a memory constraint then `-Xms` is set to a ratio
|
||||||
|
# of the `-Xmx` memory as set here. The default is `25` which means 25% of the `-Xmx`
|
||||||
|
# is used as the initial heap size. You can skip this mechanism by setting this value
|
||||||
|
# to `0` in which case no `-Xms` option is added (example: "25")
|
||||||
|
# - JAVA_MAX_INITIAL_MEM: Is used when no `-Xms` option is given in JAVA_OPTS.
|
||||||
|
# This is used to calculate the maximum value of the initial heap memory. If used in
|
||||||
|
# a container without any memory constraints for the container then this option has
|
||||||
|
# no effect. If there is a memory constraint then `-Xms` is limited to the value set
|
||||||
|
# here. The default is 4096MB which means the calculated value of `-Xms` never will
|
||||||
|
# be greater than 4096MB. The value of this variable is expressed in MB (example: "4096")
|
||||||
|
# - JAVA_DIAGNOSTICS: Set this to get some diagnostics information to standard output
|
||||||
|
# when things are happening. This option, if set to true, will set
|
||||||
|
# `-XX:+UnlockDiagnosticVMOptions`. Disabled by default (example: "true").
|
||||||
|
# - JAVA_DEBUG: If set remote debugging will be switched on. Disabled by default (example:
|
||||||
|
# true").
|
||||||
|
# - JAVA_DEBUG_PORT: Port used for remote debugging. Defaults to 5005 (example: "8787").
|
||||||
|
# - CONTAINER_CORE_LIMIT: A calculated core limit as described in
|
||||||
|
# https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt. (example: "2")
|
||||||
|
# - CONTAINER_MAX_MEMORY: Memory limit given to the container (example: "1024").
|
||||||
|
# - GC_MIN_HEAP_FREE_RATIO: Minimum percentage of heap free after GC to avoid expansion.
|
||||||
|
# (example: "20")
|
||||||
|
# - GC_MAX_HEAP_FREE_RATIO: Maximum percentage of heap free after GC to avoid shrinking.
|
||||||
|
# (example: "40")
|
||||||
|
# - GC_TIME_RATIO: Specifies the ratio of the time spent outside the garbage collection.
|
||||||
|
# (example: "4")
|
||||||
|
# - GC_ADAPTIVE_SIZE_POLICY_WEIGHT: The weighting given to the current GC time versus
|
||||||
|
# previous GC times. (example: "90")
|
||||||
|
# - GC_METASPACE_SIZE: The initial metaspace size. (example: "20")
|
||||||
|
# - GC_MAX_METASPACE_SIZE: The maximum metaspace size. (example: "100")
|
||||||
|
# - GC_CONTAINER_OPTIONS: Specify Java GC to use. The value of this variable should
|
||||||
|
# contain the necessary JRE command-line options to specify the required GC, which
|
||||||
|
# will override the default of `-XX:+UseParallelGC` (example: -XX:+UseG1GC).
|
||||||
|
# - HTTPS_PROXY: The location of the https proxy. (example: "myuser@127.0.0.1:8080")
|
||||||
|
# - HTTP_PROXY: The location of the http proxy. (example: "myuser@127.0.0.1:8080")
|
||||||
|
# - NO_PROXY: A comma separated lists of hosts, IP addresses or domains that can be
|
||||||
|
# accessed directly. (example: "foo.example.com,bar.example.com")
|
||||||
|
#
|
||||||
|
###
|
||||||
|
FROM registry.access.redhat.com/ubi8/openjdk-21:1.18
|
||||||
|
|
||||||
|
ENV LANGUAGE='en_US:en'
|
||||||
|
|
||||||
|
|
||||||
|
# We make four distinct layers so if there are application changes the library layers can be re-used
|
||||||
|
COPY --chown=185 target/quarkus-app/lib/ /deployments/lib/
|
||||||
|
COPY --chown=185 target/quarkus-app/*.jar /deployments/
|
||||||
|
COPY --chown=185 target/quarkus-app/app/ /deployments/app/
|
||||||
|
COPY --chown=185 target/quarkus-app/quarkus/ /deployments/quarkus/
|
||||||
|
|
||||||
|
EXPOSE 8080
|
||||||
|
USER 185
|
||||||
|
ENV JAVA_OPTS_APPEND="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
|
||||||
|
ENV JAVA_APP_JAR="/deployments/quarkus-run.jar"
|
||||||
|
|
||||||
|
ENTRYPOINT [ "/opt/jboss/container/java/run/run-java.sh" ]
|
||||||
|
|
@ -0,0 +1,93 @@
|
|||||||
|
####
|
||||||
|
# This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode
|
||||||
|
#
|
||||||
|
# Before building the container image run:
|
||||||
|
#
|
||||||
|
# ./mvnw package -Dquarkus.package.type=legacy-jar
|
||||||
|
#
|
||||||
|
# Then, build the image with:
|
||||||
|
#
|
||||||
|
# docker build -f src/main/docker/Dockerfile.legacy-jar -t quarkus/virtual-threads-legacy-jar .
|
||||||
|
#
|
||||||
|
# Then run the container using:
|
||||||
|
#
|
||||||
|
# docker run -i --rm -p 8080:8080 quarkus/virtual-threads-legacy-jar
|
||||||
|
#
|
||||||
|
# If you want to include the debug port into your docker image
|
||||||
|
# you will have to expose the debug port (default 5005 being the default) like this : EXPOSE 8080 5005.
|
||||||
|
# Additionally you will have to set -e JAVA_DEBUG=true and -e JAVA_DEBUG_PORT=*:5005
|
||||||
|
# when running the container
|
||||||
|
#
|
||||||
|
# Then run the container using :
|
||||||
|
#
|
||||||
|
# docker run -i --rm -p 8080:8080 quarkus/virtual-threads-legacy-jar
|
||||||
|
#
|
||||||
|
# This image uses the `run-java.sh` script to run the application.
|
||||||
|
# This scripts computes the command line to execute your Java application, and
|
||||||
|
# includes memory/GC tuning.
|
||||||
|
# You can configure the behavior using the following environment properties:
|
||||||
|
# - JAVA_OPTS: JVM options passed to the `java` command (example: "-verbose:class")
|
||||||
|
# - JAVA_OPTS_APPEND: User specified Java options to be appended to generated options
|
||||||
|
# in JAVA_OPTS (example: "-Dsome.property=foo")
|
||||||
|
# - JAVA_MAX_MEM_RATIO: Is used when no `-Xmx` option is given in JAVA_OPTS. This is
|
||||||
|
# used to calculate a default maximal heap memory based on a containers restriction.
|
||||||
|
# If used in a container without any memory constraints for the container then this
|
||||||
|
# option has no effect. If there is a memory constraint then `-Xmx` is set to a ratio
|
||||||
|
# of the container available memory as set here. The default is `50` which means 50%
|
||||||
|
# of the available memory is used as an upper boundary. You can skip this mechanism by
|
||||||
|
# setting this value to `0` in which case no `-Xmx` option is added.
|
||||||
|
# - JAVA_INITIAL_MEM_RATIO: Is used when no `-Xms` option is given in JAVA_OPTS. This
|
||||||
|
# is used to calculate a default initial heap memory based on the maximum heap memory.
|
||||||
|
# If used in a container without any memory constraints for the container then this
|
||||||
|
# option has no effect. If there is a memory constraint then `-Xms` is set to a ratio
|
||||||
|
# of the `-Xmx` memory as set here. The default is `25` which means 25% of the `-Xmx`
|
||||||
|
# is used as the initial heap size. You can skip this mechanism by setting this value
|
||||||
|
# to `0` in which case no `-Xms` option is added (example: "25")
|
||||||
|
# - JAVA_MAX_INITIAL_MEM: Is used when no `-Xms` option is given in JAVA_OPTS.
|
||||||
|
# This is used to calculate the maximum value of the initial heap memory. If used in
|
||||||
|
# a container without any memory constraints for the container then this option has
|
||||||
|
# no effect. If there is a memory constraint then `-Xms` is limited to the value set
|
||||||
|
# here. The default is 4096MB which means the calculated value of `-Xms` never will
|
||||||
|
# be greater than 4096MB. The value of this variable is expressed in MB (example: "4096")
|
||||||
|
# - JAVA_DIAGNOSTICS: Set this to get some diagnostics information to standard output
|
||||||
|
# when things are happening. This option, if set to true, will set
|
||||||
|
# `-XX:+UnlockDiagnosticVMOptions`. Disabled by default (example: "true").
|
||||||
|
# - JAVA_DEBUG: If set remote debugging will be switched on. Disabled by default (example:
|
||||||
|
# true").
|
||||||
|
# - JAVA_DEBUG_PORT: Port used for remote debugging. Defaults to 5005 (example: "8787").
|
||||||
|
# - CONTAINER_CORE_LIMIT: A calculated core limit as described in
|
||||||
|
# https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt. (example: "2")
|
||||||
|
# - CONTAINER_MAX_MEMORY: Memory limit given to the container (example: "1024").
|
||||||
|
# - GC_MIN_HEAP_FREE_RATIO: Minimum percentage of heap free after GC to avoid expansion.
|
||||||
|
# (example: "20")
|
||||||
|
# - GC_MAX_HEAP_FREE_RATIO: Maximum percentage of heap free after GC to avoid shrinking.
|
||||||
|
# (example: "40")
|
||||||
|
# - GC_TIME_RATIO: Specifies the ratio of the time spent outside the garbage collection.
|
||||||
|
# (example: "4")
|
||||||
|
# - GC_ADAPTIVE_SIZE_POLICY_WEIGHT: The weighting given to the current GC time versus
|
||||||
|
# previous GC times. (example: "90")
|
||||||
|
# - GC_METASPACE_SIZE: The initial metaspace size. (example: "20")
|
||||||
|
# - GC_MAX_METASPACE_SIZE: The maximum metaspace size. (example: "100")
|
||||||
|
# - GC_CONTAINER_OPTIONS: Specify Java GC to use. The value of this variable should
|
||||||
|
# contain the necessary JRE command-line options to specify the required GC, which
|
||||||
|
# will override the default of `-XX:+UseParallelGC` (example: -XX:+UseG1GC).
|
||||||
|
# - HTTPS_PROXY: The location of the https proxy. (example: "myuser@127.0.0.1:8080")
|
||||||
|
# - HTTP_PROXY: The location of the http proxy. (example: "myuser@127.0.0.1:8080")
|
||||||
|
# - NO_PROXY: A comma separated lists of hosts, IP addresses or domains that can be
|
||||||
|
# accessed directly. (example: "foo.example.com,bar.example.com")
|
||||||
|
#
|
||||||
|
###
|
||||||
|
FROM registry.access.redhat.com/ubi8/openjdk-21:1.18
|
||||||
|
|
||||||
|
ENV LANGUAGE='en_US:en'
|
||||||
|
|
||||||
|
|
||||||
|
COPY target/lib/* /deployments/lib/
|
||||||
|
COPY target/*-runner.jar /deployments/quarkus-run.jar
|
||||||
|
|
||||||
|
EXPOSE 8080
|
||||||
|
USER 185
|
||||||
|
ENV JAVA_OPTS_APPEND="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
|
||||||
|
ENV JAVA_APP_JAR="/deployments/quarkus-run.jar"
|
||||||
|
|
||||||
|
ENTRYPOINT [ "/opt/jboss/container/java/run/run-java.sh" ]
|
@ -0,0 +1,27 @@
|
|||||||
|
####
|
||||||
|
# This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode.
|
||||||
|
#
|
||||||
|
# Before building the container image run:
|
||||||
|
#
|
||||||
|
# ./mvnw package -Dnative
|
||||||
|
#
|
||||||
|
# Then, build the image with:
|
||||||
|
#
|
||||||
|
# docker build -f src/main/docker/Dockerfile.native -t quarkus/virtual-threads .
|
||||||
|
#
|
||||||
|
# Then run the container using:
|
||||||
|
#
|
||||||
|
# docker run -i --rm -p 8080:8080 quarkus/virtual-threads
|
||||||
|
#
|
||||||
|
###
|
||||||
|
FROM registry.access.redhat.com/ubi8/ubi-minimal:8.9
|
||||||
|
WORKDIR /work/
|
||||||
|
RUN chown 1001 /work \
|
||||||
|
&& chmod "g+rwX" /work \
|
||||||
|
&& chown 1001:root /work
|
||||||
|
COPY --chown=1001:root target/*-runner /work/application
|
||||||
|
|
||||||
|
EXPOSE 8080
|
||||||
|
USER 1001
|
||||||
|
|
||||||
|
ENTRYPOINT ["./application", "-Dquarkus.http.host=0.0.0.0"]
|
@ -0,0 +1,30 @@
|
|||||||
|
####
|
||||||
|
# This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode.
|
||||||
|
# It uses a micro base image, tuned for Quarkus native executables.
|
||||||
|
# It reduces the size of the resulting container image.
|
||||||
|
# Check https://quarkus.io/guides/quarkus-runtime-base-image for further information about this image.
|
||||||
|
#
|
||||||
|
# Before building the container image run:
|
||||||
|
#
|
||||||
|
# ./mvnw package -Dnative
|
||||||
|
#
|
||||||
|
# Then, build the image with:
|
||||||
|
#
|
||||||
|
# docker build -f src/main/docker/Dockerfile.native-micro -t quarkus/virtual-threads .
|
||||||
|
#
|
||||||
|
# Then run the container using:
|
||||||
|
#
|
||||||
|
# docker run -i --rm -p 8080:8080 quarkus/virtual-threads
|
||||||
|
#
|
||||||
|
###
|
||||||
|
FROM quay.io/quarkus/quarkus-micro-image:2.0
|
||||||
|
WORKDIR /work/
|
||||||
|
RUN chown 1001 /work \
|
||||||
|
&& chmod "g+rwX" /work \
|
||||||
|
&& chown 1001:root /work
|
||||||
|
COPY --chown=1001:root target/*-runner /work/application
|
||||||
|
|
||||||
|
EXPOSE 8080
|
||||||
|
USER 1001
|
||||||
|
|
||||||
|
ENTRYPOINT ["./application", "-Dquarkus.http.host=0.0.0.0"]
|
@ -0,0 +1,16 @@
|
|||||||
|
package com.baeldung.quarkus;
|
||||||
|
|
||||||
|
import jakarta.ws.rs.GET;
|
||||||
|
import jakarta.ws.rs.Path;
|
||||||
|
import jakarta.ws.rs.Produces;
|
||||||
|
import jakarta.ws.rs.core.MediaType;
|
||||||
|
|
||||||
|
@Path("/hello")
|
||||||
|
public class GreetingResource {
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Produces(MediaType.TEXT_PLAIN)
|
||||||
|
public String hello() {
|
||||||
|
return "Hello from RESTEasy Reactive";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package com.baeldung.quarkus.rest;
|
||||||
|
|
||||||
|
import jakarta.ws.rs.GET;
|
||||||
|
import jakarta.ws.rs.Path;
|
||||||
|
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
|
||||||
|
|
||||||
|
@RegisterRestClient(configKey = "remote-service")
|
||||||
|
public interface RemoteService {
|
||||||
|
@GET
|
||||||
|
@Path("/greetings")
|
||||||
|
default String greetings(){
|
||||||
|
return "Mocked Greeting";
|
||||||
|
};
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package com.baeldung.quarkus.rest;
|
||||||
|
|
||||||
|
import io.smallrye.common.annotation.RunOnVirtualThread;
|
||||||
|
import jakarta.ws.rs.GET;
|
||||||
|
import jakarta.ws.rs.Path;
|
||||||
|
import org.eclipse.microprofile.rest.client.inject.RestClient;
|
||||||
|
|
||||||
|
@Path("/greetings")
|
||||||
|
public class VirtualThreadApp {
|
||||||
|
@RestClient RemoteService service;
|
||||||
|
@GET @RunOnVirtualThread
|
||||||
|
public String process() {
|
||||||
|
var response = service.greetings();
|
||||||
|
return response.toUpperCase();
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because one or more lines are too long
@ -0,0 +1 @@
|
|||||||
|
remote-service/mp-rest/url=http://localhost:8080
|
@ -0,0 +1,16 @@
|
|||||||
|
package com.baeldung.quarkus;
|
||||||
|
|
||||||
|
import jakarta.ws.rs.GET;
|
||||||
|
import jakarta.ws.rs.Path;
|
||||||
|
import jakarta.ws.rs.Produces;
|
||||||
|
import jakarta.ws.rs.core.MediaType;
|
||||||
|
|
||||||
|
@Path("/hello")
|
||||||
|
public class GreetingResource {
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Produces(MediaType.TEXT_PLAIN)
|
||||||
|
public String hello() {
|
||||||
|
return "Hello from RESTEasy Reactive";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package com.baeldung.quarkus.rest;
|
||||||
|
|
||||||
|
import jakarta.ws.rs.GET;
|
||||||
|
import jakarta.ws.rs.Path;
|
||||||
|
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
|
||||||
|
|
||||||
|
@RegisterRestClient(configKey = "remote-service")
|
||||||
|
public interface RemoteService {
|
||||||
|
@GET
|
||||||
|
@Path("/greetings")
|
||||||
|
default String greetings(){
|
||||||
|
return "Mocked Greeting";
|
||||||
|
};
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package com.baeldung.quarkus.rest;
|
||||||
|
|
||||||
|
import io.smallrye.common.annotation.RunOnVirtualThread;
|
||||||
|
import jakarta.ws.rs.GET;
|
||||||
|
import jakarta.ws.rs.Path;
|
||||||
|
import org.eclipse.microprofile.rest.client.inject.RestClient;
|
||||||
|
|
||||||
|
@Path("/greetings")
|
||||||
|
public class VirtualThreadApp {
|
||||||
|
@RestClient RemoteService service;
|
||||||
|
@GET @RunOnVirtualThread
|
||||||
|
public String process() {
|
||||||
|
var response = service.greetings();
|
||||||
|
return response.toUpperCase();
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
12079
quarkus-modules/quarkus-vs-springboot/jmeter/zip_code_database.csv
Normal file
12079
quarkus-modules/quarkus-vs-springboot/jmeter/zip_code_database.csv
Normal file
File diff suppressed because it is too large
Load Diff
12079
quarkus-modules/quarkus-vs-springboot/wrk/zip_code_database.csv
Normal file
12079
quarkus-modules/quarkus-vs-springboot/wrk/zip_code_database.csv
Normal file
File diff suppressed because it is too large
Load Diff
@ -2,4 +2,5 @@
|
|||||||
|
|
||||||
- [Spring Boot With Spring Batch](https://www.baeldung.com/spring-boot-spring-batch)
|
- [Spring Boot With Spring Batch](https://www.baeldung.com/spring-boot-spring-batch)
|
||||||
- [How to Trigger and Stop a Scheduled Spring Batch Job](https://www.baeldung.com/spring-batch-start-stop-job)
|
- [How to Trigger and Stop a Scheduled Spring Batch Job](https://www.baeldung.com/spring-batch-start-stop-job)
|
||||||
|
- [Access Job Parameters From ItemReader in Spring Batch](https://www.baeldung.com/spring-batch-itemreader-access-job-parameters)
|
||||||
- More articles [[<-- prev]](/spring-batch)
|
- More articles [[<-- prev]](/spring-batch)
|
||||||
|
@ -11,3 +11,4 @@ This module contains articles about Spring Boot customization 2
|
|||||||
- [Guide to Spring Type Conversions](https://www.baeldung.com/spring-type-conversions)
|
- [Guide to Spring Type Conversions](https://www.baeldung.com/spring-type-conversions)
|
||||||
- [Container Configuration in Spring Boot 2](https://www.baeldung.com/embeddedservletcontainercustomizer-configurableembeddedservletcontainer-spring-boot)
|
- [Container Configuration in Spring Boot 2](https://www.baeldung.com/embeddedservletcontainercustomizer-configurableembeddedservletcontainer-spring-boot)
|
||||||
- [Speed up Spring Boot Startup Time](https://www.baeldung.com/spring-boot-startup-speed)
|
- [Speed up Spring Boot Startup Time](https://www.baeldung.com/spring-boot-startup-speed)
|
||||||
|
- More articles: [[<-- prev]](/spring-boot-modules/spring-boot-basic-customization)
|
@ -9,9 +9,10 @@
|
|||||||
<description>Module For Spring Boot Basic Customization 2</description>
|
<description>Module For Spring Boot Basic Customization 2</description>
|
||||||
|
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>com.baeldung.spring-boot-modules</groupId>
|
<groupId>com.baeldung</groupId>
|
||||||
<artifactId>spring-boot-modules</artifactId>
|
<artifactId>parent-boot-3</artifactId>
|
||||||
<version>1.0.0-SNAPSHOT</version>
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
<relativePath>../../parent-boot-3</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
@ -7,7 +7,7 @@ import org.springframework.boot.web.servlet.ServletRegistrationBean;
|
|||||||
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 javax.servlet.ServletContextListener;
|
import jakarta.servlet.ServletContextListener;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
public class WebConf {
|
public class WebConf {
|
||||||
|
@ -4,7 +4,7 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import javax.servlet.*;
|
import jakarta.servlet.*;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
|
@ -3,8 +3,8 @@ package com.baeldung.dispatchservlet.listener;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import javax.servlet.ServletContextEvent;
|
import jakarta.servlet.ServletContextEvent;
|
||||||
import javax.servlet.ServletContextListener;
|
import jakarta.servlet.ServletContextListener;
|
||||||
|
|
||||||
public class CustomListener implements ServletContextListener {
|
public class CustomListener implements ServletContextListener {
|
||||||
|
|
||||||
|
@ -4,11 +4,11 @@ import com.baeldung.dispatchservlet.filter.CustomFilter;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
import jakarta.servlet.ServletException;
|
||||||
import javax.servlet.annotation.WebServlet;
|
import jakarta.servlet.annotation.WebServlet;
|
||||||
import javax.servlet.http.HttpServlet;
|
import jakarta.servlet.http.HttpServlet;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
public class CustomServlet extends HttpServlet {
|
public class CustomServlet extends HttpServlet {
|
||||||
|
@ -3,10 +3,10 @@ package com.baeldung.onceperrequestfilter;
|
|||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.web.filter.OncePerRequestFilter;
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
|
|
||||||
import javax.servlet.FilterChain;
|
import jakarta.servlet.FilterChain;
|
||||||
import javax.servlet.ServletException;
|
import jakarta.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
|
@ -6,7 +6,7 @@ import org.springframework.stereotype.Controller;
|
|||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.context.request.async.DeferredResult;
|
import org.springframework.web.context.request.async.DeferredResult;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
@ -5,10 +5,10 @@ import org.slf4j.LoggerFactory;
|
|||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.web.filter.OncePerRequestFilter;
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
|
|
||||||
import javax.servlet.FilterChain;
|
import jakarta.servlet.FilterChain;
|
||||||
import javax.servlet.ServletException;
|
import jakarta.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package com.baeldung.typeconversion.entity;
|
package com.baeldung.typeconversion.entity;
|
||||||
|
|
||||||
import javax.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
import javax.persistence.Id;
|
import jakarta.persistence.Id;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
public class Employee {
|
public class Employee {
|
||||||
|
@ -11,3 +11,4 @@ This module contains articles about Spring Boot customization
|
|||||||
- [Spring Boot: Configuring a Main Class](https://www.baeldung.com/spring-boot-main-class)
|
- [Spring Boot: Configuring a Main Class](https://www.baeldung.com/spring-boot-main-class)
|
||||||
- [How to Define a Spring Boot Filter?](https://www.baeldung.com/spring-boot-add-filter)
|
- [How to Define a Spring Boot Filter?](https://www.baeldung.com/spring-boot-add-filter)
|
||||||
- [Guide to the Favicon in Spring Boot](https://www.baeldung.com/spring-boot-favicon)
|
- [Guide to the Favicon in Spring Boot](https://www.baeldung.com/spring-boot-favicon)
|
||||||
|
- More articles: [[next -->]](/spring-boot-modules/spring-boot-basic-customization-2)
|
||||||
|
@ -9,9 +9,10 @@
|
|||||||
<description>Module For Spring Boot Basic Customization</description>
|
<description>Module For Spring Boot Basic Customization</description>
|
||||||
|
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>com.baeldung.spring-boot-modules</groupId>
|
<groupId>com.baeldung</groupId>
|
||||||
<artifactId>spring-boot-modules</artifactId>
|
<artifactId>parent-boot-3</artifactId>
|
||||||
<version>1.0.0-SNAPSHOT</version>
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
<relativePath>../../parent-boot-3</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
@ -81,7 +82,7 @@
|
|||||||
</build>
|
</build>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<spring-boot-maven-plugin.version>1.5.2.RELEASE</spring-boot-maven-plugin.version>
|
<spring-boot-maven-plugin.version>3.1.5</spring-boot-maven-plugin.version>
|
||||||
<!-- The main class to start by executing "java -jar" -->
|
<!-- The main class to start by executing "java -jar" -->
|
||||||
<start-class>com.baeldung.changeport.CustomApplication</start-class>
|
<start-class>com.baeldung.changeport.CustomApplication</start-class>
|
||||||
</properties>
|
</properties>
|
||||||
|
@ -5,9 +5,14 @@ import org.slf4j.LoggerFactory;
|
|||||||
import org.springframework.core.annotation.Order;
|
import org.springframework.core.annotation.Order;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import javax.servlet.*;
|
import jakarta.servlet.Filter;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import jakarta.servlet.FilterChain;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import jakarta.servlet.FilterConfig;
|
||||||
|
import jakarta.servlet.ServletException;
|
||||||
|
import jakarta.servlet.ServletRequest;
|
||||||
|
import jakarta.servlet.ServletResponse;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -23,7 +28,7 @@ public class RequestResponseLoggingFilter implements Filter {
|
|||||||
private final static Logger LOG = LoggerFactory.getLogger(RequestResponseLoggingFilter.class);
|
private final static Logger LOG = LoggerFactory.getLogger(RequestResponseLoggingFilter.class);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(final FilterConfig filterConfig) throws ServletException {
|
public void init(final FilterConfig filterConfig) {
|
||||||
LOG.info("Initializing filter :{}", this);
|
LOG.info("Initializing filter :{}", this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,8 +5,13 @@ import org.slf4j.LoggerFactory;
|
|||||||
import org.springframework.core.annotation.Order;
|
import org.springframework.core.annotation.Order;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import javax.servlet.*;
|
import jakarta.servlet.Filter;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import jakarta.servlet.FilterChain;
|
||||||
|
import jakarta.servlet.FilterConfig;
|
||||||
|
import jakarta.servlet.ServletException;
|
||||||
|
import jakarta.servlet.ServletRequest;
|
||||||
|
import jakarta.servlet.ServletResponse;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -5,8 +5,8 @@ import org.springframework.http.HttpStatus;
|
|||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
|
||||||
import javax.servlet.RequestDispatcher;
|
import jakarta.servlet.RequestDispatcher;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
public class MyErrorController implements ErrorController {
|
public class MyErrorController implements ErrorController {
|
||||||
|
@ -4,7 +4,7 @@ import org.springframework.boot.SpringApplication;
|
|||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
import org.springframework.context.annotation.Profile;
|
import org.springframework.context.annotation.Profile;
|
||||||
|
|
||||||
import javax.annotation.security.RolesAllowed;
|
import jakarta.annotation.security.RolesAllowed;
|
||||||
|
|
||||||
@Profile("failureanalyzer")
|
@Profile("failureanalyzer")
|
||||||
@SpringBootApplication(scanBasePackages = "com.baeldung.failureanalyzer")
|
@SpringBootApplication(scanBasePackages = "com.baeldung.failureanalyzer")
|
||||||
|
@ -2,7 +2,7 @@ package com.baeldung.failureanalyzer;
|
|||||||
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class MyService {
|
public class MyService {
|
||||||
|
@ -1,2 +1 @@
|
|||||||
org.springframework.boot.diagnostics.FailureAnalyzer=com.baeldung.failureanalyzer.MyBeanNotOfRequiredTypeFailureAnalyzer
|
org.springframework.boot.diagnostics.FailureAnalyzer=com.baeldung.failureanalyzer.MyBeanNotOfRequiredTypeFailureAnalyzer
|
||||||
|
|
||||||
|
@ -158,7 +158,7 @@
|
|||||||
<properties>
|
<properties>
|
||||||
<subethasmtp.version>3.1.7</subethasmtp.version>
|
<subethasmtp.version>3.1.7</subethasmtp.version>
|
||||||
<httpclient.version>4.5.8</httpclient.version>
|
<httpclient.version>4.5.8</httpclient.version>
|
||||||
<spring.cloud-version>2021.0.0</spring.cloud-version>
|
<spring.cloud-version>2023.0.0</spring.cloud-version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
</project>
|
</project>
|
BIN
spring-boot-modules/spring-boot-telegram/baeldungbot
Normal file
BIN
spring-boot-modules/spring-boot-telegram/baeldungbot
Normal file
Binary file not shown.
@ -8,4 +8,5 @@ This module contains articles about reactive Spring Boot.
|
|||||||
- [Spring Boot Actuator](https://www.baeldung.com/spring-boot-actuators)
|
- [Spring Boot Actuator](https://www.baeldung.com/spring-boot-actuators)
|
||||||
- [Reactive WebSockets with Spring 5](https://www.baeldung.com/spring-5-reactive-websockets)
|
- [Reactive WebSockets with Spring 5](https://www.baeldung.com/spring-5-reactive-websockets)
|
||||||
- [A Guide to Spring Session Reactive Support: WebSession](https://www.baeldung.com/spring-session-reactive)
|
- [A Guide to Spring Session Reactive Support: WebSession](https://www.baeldung.com/spring-session-reactive)
|
||||||
|
- [Custom JSON Deserialization Using Spring WebClient](https://www.baeldung.com/spring-webclient-json-custom-deserialization)
|
||||||
- More articles: [[<-- prev]](../spring-reactive-2)
|
- More articles: [[<-- prev]](../spring-reactive-2)
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user