deps: Refactor dependencies (#3224)

* remove spring dep
move junit, logging, mockito under dep mgmt

* upgrade anti-corruption-layer deps

* async method invocation

* balking, bloc

* bridge to bytecode

* caching

* callback - cqrs

* component - health check

* hexagonal - metadata mapping

* rest of the patterns

* remove checkstyle, take spotless into use
This commit is contained in:
Ilkka Seppälä
2025-03-29 19:34:27 +02:00
committed by GitHub
parent 371439aeaa
commit 0ca162a55c
1863 changed files with 14403 additions and 17632 deletions
@@ -27,7 +27,6 @@ package com.iluwatar.promise;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import lombok.extern.slf4j.Slf4j;
@@ -36,26 +35,28 @@ import lombok.extern.slf4j.Slf4j;
* The Promise object is used for asynchronous computations. A Promise represents an operation that
* hasn't completed yet, but is expected in the future.
*
* <p>A Promise represents a proxy for a value not necessarily known when the promise is created.
* It allows you to associate dependent promises to an asynchronous action's eventual success value
* or failure reason. This lets asynchronous methods return values like synchronous methods: instead
* of the final value, the asynchronous method returns a promise of having a value at some point in
* the future.
* <p>A Promise represents a proxy for a value not necessarily known when the promise is created. It
* allows you to associate dependent promises to an asynchronous action's eventual success value or
* failure reason. This lets asynchronous methods return values like synchronous methods: instead of
* the final value, the asynchronous method returns a promise of having a value at some point in the
* future.
*
* <p>Promises provide a few advantages over callback objects:
*
* <ul>
* <li> Functional composition and error handling
* <li> Prevents callback hell and provides callback aggregation
* <li>Functional composition and error handling
* <li>Prevents callback hell and provides callback aggregation
* </ul>
*
* <p>In this application the usage of promise is demonstrated with two examples:
*
* <ul>
* <li>Count Lines: In this example a file is downloaded and its line count is calculated.
* The calculated line count is then consumed and printed on console.
* <li>Lowest Character Frequency: In this example a file is downloaded and its lowest frequency
* character is found and printed on console. This happens via a chain of promises, we start with
* a file download promise, then a promise of character frequency, then a promise of lowest
* frequency character which is finally consumed and result is printed on console.
* <li>Count Lines: In this example a file is downloaded and its line count is calculated. The
* calculated line count is then consumed and printed on console.
* <li>Lowest Character Frequency: In this example a file is downloaded and its lowest frequency
* character is found and printed on console. This happens via a chain of promises, we start
* with a file download promise, then a promise of character frequency, then a promise of
* lowest frequency character which is finally consumed and result is printed on console.
* </ul>
*
* @see CompletableFuture
@@ -99,12 +100,12 @@ public class App {
* consume the result in a Consumer<Character>
*/
private void calculateLowestFrequencyChar() {
lowestFrequencyChar().thenAccept(
charFrequency -> {
LOGGER.info("Char with lowest frequency is: {}", charFrequency);
taskCompleted();
}
);
lowestFrequencyChar()
.thenAccept(
charFrequency -> {
LOGGER.info("Char with lowest frequency is: {}", charFrequency);
taskCompleted();
});
}
/*
@@ -112,12 +113,12 @@ public class App {
* in a Consumer<Integer>
*/
private void calculateLineCount() {
countLines().thenAccept(
count -> {
LOGGER.info("Line count is: {}", count);
taskCompleted();
}
);
countLines()
.thenAccept(
count -> {
LOGGER.info("Line count is: {}", count);
taskCompleted();
});
}
/*
@@ -150,14 +151,12 @@ public class App {
*/
private Promise<String> download(String urlString) {
return new Promise<String>()
.fulfillInAsync(
() -> Utility.downloadFile(urlString), executor)
.fulfillInAsync(() -> Utility.downloadFile(urlString), executor)
.onError(
throwable -> {
LOGGER.error("An error occurred: ", throwable);
taskCompleted();
}
);
});
}
private void stop() throws InterruptedException {
@@ -44,9 +44,7 @@ public class Promise<T> extends PromiseSupport<T> {
private Runnable fulfillmentAction;
private Consumer<? super Throwable> exceptionHandler;
/**
* Creates a promise that will be fulfilled in the future.
*/
/** Creates a promise that will be fulfilled in the future. */
public Promise() {
// Empty constructor
}
@@ -66,7 +64,7 @@ public class Promise<T> extends PromiseSupport<T> {
* Fulfills the promise with exception due to error in execution.
*
* @param exception the exception will be wrapped in {@link ExecutionException} when accessing the
* value using {@link #get()}.
* value using {@link #get()}.
*/
@Override
public void fulfillExceptionally(Exception exception) {
@@ -93,18 +91,19 @@ public class Promise<T> extends PromiseSupport<T> {
* Executes the task using the executor in other thread and fulfills the promise returned once the
* task completes either successfully or with an exception.
*
* @param task the task that will provide the value to fulfill the promise.
* @param task the task that will provide the value to fulfill the promise.
* @param executor the executor in which the task should be run.
* @return a promise that represents the result of running the task provided.
*/
public Promise<T> fulfillInAsync(final Callable<T> task, Executor executor) {
executor.execute(() -> {
try {
fulfill(task.call());
} catch (Exception ex) {
fulfillExceptionally(ex);
}
});
executor.execute(
() -> {
try {
fulfill(task.call());
} catch (Exception ex) {
fulfillExceptionally(ex);
}
});
return this;
}
@@ -125,7 +124,7 @@ public class Promise<T> extends PromiseSupport<T> {
* Set the exception handler on this promise.
*
* @param exceptionHandler a consumer that will handle the exception occurred while fulfilling the
* promise.
* promise.
* @return this
*/
public Promise<T> onError(Consumer<? super Throwable> exceptionHandler) {
@@ -198,4 +197,4 @@ public class Promise<T> extends PromiseSupport<T> {
}
}
}
}
}
@@ -39,9 +39,7 @@ import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
/**
* Utility to perform various operations.
*/
/** Utility to perform various operations. */
@Slf4j
public class Utility {
@@ -53,7 +51,8 @@ public class Utility {
*/
public static Map<Character, Long> characterFrequency(String fileLocation) {
try (var bufferedReader = new BufferedReader(new FileReader(fileLocation))) {
return bufferedReader.lines()
return bufferedReader
.lines()
.flatMapToInt(String::chars)
.mapToObj(x -> (char) x)
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
@@ -69,9 +68,7 @@ public class Utility {
* @return the character, {@code Optional.empty()} otherwise.
*/
public static Character lowestFrequencyChar(Map<Character, Long> charFrequency) {
return charFrequency
.entrySet()
.stream()
return charFrequency.entrySet().stream()
.min(Comparator.comparingLong(Entry::getValue))
.map(Entry::getKey)
.orElseThrow();
@@ -101,7 +98,7 @@ public class Utility {
var url = new URL(urlString);
var file = File.createTempFile("promise_pattern", null);
try (var bufferedReader = new BufferedReader(new InputStreamReader(url.openStream()));
var writer = new FileWriter(file)) {
var writer = new FileWriter(file)) {
String line;
while ((line = bufferedReader.readLine()) != null) {
writer.write(line);
@@ -28,9 +28,7 @@ import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import org.junit.jupiter.api.Test;
/**
* Application test.
*/
/** Application test. */
class AppTest {
@Test
@@ -41,9 +41,7 @@ import java.util.function.Consumer;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
/**
* Tests Promise class.
*/
/** Tests Promise class. */
class PromiseTest {
private Executor executor;
@@ -66,17 +64,18 @@ class PromiseTest {
}
@Test
void promiseIsFulfilledWithAnExceptionIfTaskThrowsAnException()
throws InterruptedException {
void promiseIsFulfilledWithAnExceptionIfTaskThrowsAnException() throws InterruptedException {
testWaitingForeverForPromiseToBeFulfilled();
testWaitingSomeTimeForPromiseToBeFulfilled();
}
private void testWaitingForeverForPromiseToBeFulfilled() throws InterruptedException {
var promise = new Promise<Integer>();
promise.fulfillInAsync(() -> {
throw new RuntimeException("Barf!");
}, executor);
promise.fulfillInAsync(
() -> {
throw new RuntimeException("Barf!");
},
executor);
try {
promise.get();
@@ -97,9 +96,11 @@ class PromiseTest {
private void testWaitingSomeTimeForPromiseToBeFulfilled() throws InterruptedException {
var promise = new Promise<Integer>();
promise.fulfillInAsync(() -> {
throw new RuntimeException("Barf!");
}, executor);
promise.fulfillInAsync(
() -> {
throw new RuntimeException("Barf!");
},
executor);
try {
promise.get(1000, TimeUnit.SECONDS);
@@ -116,15 +117,15 @@ class PromiseTest {
assertTrue(promise.isDone());
assertFalse(promise.isCancelled());
}
}
@Test
void dependentPromiseIsFulfilledAfterTheConsumerConsumesTheResultOfThisPromise()
throws InterruptedException, ExecutionException {
var dependentPromise = promise
.fulfillInAsync(new NumberCrunchingTask(), executor)
.thenAccept(value -> assertEquals(NumberCrunchingTask.CRUNCHED_NUMBER, value));
var dependentPromise =
promise
.fulfillInAsync(new NumberCrunchingTask(), executor)
.thenAccept(value -> assertEquals(NumberCrunchingTask.CRUNCHED_NUMBER, value));
dependentPromise.get();
assertTrue(dependentPromise.isDone());
@@ -134,16 +135,19 @@ class PromiseTest {
@Test
void dependentPromiseIsFulfilledWithAnExceptionIfConsumerThrowsAnException()
throws InterruptedException {
var dependentPromise = promise
.fulfillInAsync(new NumberCrunchingTask(), executor)
.thenAccept(value -> {
throw new RuntimeException("Barf!");
});
var dependentPromise =
promise
.fulfillInAsync(new NumberCrunchingTask(), executor)
.thenAccept(
value -> {
throw new RuntimeException("Barf!");
});
try {
dependentPromise.get();
fail("Fetching dependent promise should result in exception "
+ "if the action threw an exception");
fail(
"Fetching dependent promise should result in exception "
+ "if the action threw an exception");
} catch (ExecutionException ex) {
assertTrue(promise.isDone());
assertFalse(promise.isCancelled());
@@ -151,8 +155,9 @@ class PromiseTest {
try {
dependentPromise.get(1000, TimeUnit.SECONDS);
fail("Fetching dependent promise should result in exception "
+ "if the action threw an exception");
fail(
"Fetching dependent promise should result in exception "
+ "if the action threw an exception");
} catch (ExecutionException ex) {
assertTrue(promise.isDone());
assertFalse(promise.isCancelled());
@@ -162,13 +167,14 @@ class PromiseTest {
@Test
void dependentPromiseIsFulfilledAfterTheFunctionTransformsTheResultOfThisPromise()
throws InterruptedException, ExecutionException {
var dependentPromise = promise
.fulfillInAsync(new NumberCrunchingTask(), executor)
.thenApply(value -> {
assertEquals(NumberCrunchingTask.CRUNCHED_NUMBER, value);
return String.valueOf(value);
});
var dependentPromise =
promise
.fulfillInAsync(new NumberCrunchingTask(), executor)
.thenApply(
value -> {
assertEquals(NumberCrunchingTask.CRUNCHED_NUMBER, value);
return String.valueOf(value);
});
assertEquals(String.valueOf(NumberCrunchingTask.CRUNCHED_NUMBER), dependentPromise.get());
assertTrue(dependentPromise.isDone());
@@ -178,16 +184,19 @@ class PromiseTest {
@Test
void dependentPromiseIsFulfilledWithAnExceptionIfTheFunctionThrowsException()
throws InterruptedException {
var dependentPromise = promise
.fulfillInAsync(new NumberCrunchingTask(), executor)
.thenApply(value -> {
throw new RuntimeException("Barf!");
});
var dependentPromise =
promise
.fulfillInAsync(new NumberCrunchingTask(), executor)
.thenApply(
value -> {
throw new RuntimeException("Barf!");
});
try {
dependentPromise.get();
fail("Fetching dependent promise should result in exception "
+ "if the function threw an exception");
fail(
"Fetching dependent promise should result in exception "
+ "if the function threw an exception");
} catch (ExecutionException ex) {
assertTrue(promise.isDone());
assertFalse(promise.isCancelled());
@@ -195,8 +204,9 @@ class PromiseTest {
try {
dependentPromise.get(1000, TimeUnit.SECONDS);
fail("Fetching dependent promise should result in exception "
+ "if the function threw an exception");
fail(
"Fetching dependent promise should result in exception "
+ "if the function threw an exception");
} catch (ExecutionException ex) {
assertTrue(promise.isDone());
assertFalse(promise.isCancelled());