Skip to content

Commit 17f5e88

Browse files
committed
creating basic extensions
1 parent 9be8b2a commit 17f5e88

12 files changed

Lines changed: 694 additions & 19 deletions

File tree

.github/workflows/ci.yml

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -25,38 +25,24 @@ jobs:
2525
- name: Generate Javadoc
2626
run: mvn javadoc:javadoc
2727

28-
- name: Debug generated javadoc
29-
run: |
30-
echo "::group::Listing apidocs"
31-
ls -la target/site/apidocs || echo 'No apidocs found'
32-
echo "::endgroup::"
33-
3428
- name: Copy Javadoc to temp folder
3529
run: |
3630
mkdir -p temp-docs
3731
cp -R target/site/apidocs/* temp-docs/
3832
39-
- name: Create redirect root index.html
33+
- name: Prepare Javadoc for GitHub Pages
4034
run: |
35+
mkdir -p temp-docs
36+
cp -R target/site/apidocs/* temp-docs/
37+
echo > temp-docs/.nojekyll
4138
echo '<!DOCTYPE html>
4239
<html lang="en">
4340
<head>
4441
<meta http-equiv="refresh" content="0; url=index.html">
4542
<title>Redirecting…</title>
4643
</head>
4744
<body>
48-
<p>If you are not redirected automatically, follow this <a href="index.html">link</a>.</p>
49-
</body>
50-
</html>' > temp-docs/.nojekyll
51-
cp temp-docs/index.html temp-docs/root.html
52-
echo '<!DOCTYPE html>
53-
<html lang="en">
54-
<head>
55-
<meta http-equiv="refresh" content="0; url=root.html">
56-
<title>Redirecting…</title>
57-
</head>
58-
<body>
59-
<p>If you are not redirected automatically, follow this <a href="root.html">link</a>.</p>
45+
<p>If you are not redirected automatically, follow this <a href="index.html">Javadoc</a>.</p>
6046
</body>
6147
</html>' > temp-docs/index.html
6248

src/main/java/com/dudko/tools/safejavastreams/core/Either.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,12 @@ public abstract <T> T fold(Function<? super L, ? extends T> leftMapper,
122122
*/
123123
public abstract Optional<R> toOptional();
124124

125+
/**
126+
* Converts this Either to a Stream.
127+
*
128+
* @return Stream with this Either
129+
*/
130+
public abstract R get();
125131

126132
/**
127133
* Converts this Either to a Stream.
@@ -227,6 +233,11 @@ public Optional<R> toOptional() {
227233
return Optional.empty();
228234
}
229235

236+
@Override
237+
public R get() {
238+
throw new NoSuchElementException("No right value present");
239+
}
240+
230241
public String toString() {
231242
return "Left(" + value + ")";
232243
}
@@ -294,6 +305,11 @@ public Optional<R> toOptional() {
294305
return Optional.of(value);
295306
}
296307

308+
@Override
309+
public R get() {
310+
return value;
311+
}
312+
297313
public String toString() {
298314
return "Right(" + value + ")";
299315
}

src/main/java/com/dudko/tools/safejavastreams/core/Try.java

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,10 @@ public abstract <U> U fold(Function<? super Throwable, ? extends U> failureMappe
9898
*/
9999
public abstract Optional<T> toOptional();
100100

101+
public abstract Throwable getError();
102+
103+
public abstract <L> Either<L, T> toEither(Function<? super Throwable, ? extends L> mapper);
104+
101105
/**
102106
* Checks if this Try is a Failure of specific exception type.
103107
*
@@ -179,10 +183,24 @@ public static <T> Try<T> of(ThrowingSupplier<T> supplier) {
179183
}
180184
}
181185

186+
/**
187+
* Creates a Success instance.
188+
*
189+
* @param value the value
190+
* @param <T> type of the value
191+
* @return Success with the value
192+
*/
182193
public static <T> Try<T> success(T value) {
183194
return new Success<>(value);
184195
}
185196

197+
/**
198+
* Creates a Failure instance.
199+
*
200+
* @param exception the exception
201+
* @param <T> type of the value
202+
* @return Failure with the exception
203+
*/
186204
public static <T> Try<T> failure(Throwable exception) {
187205
return new Failure<>(exception);
188206
}
@@ -254,6 +272,16 @@ public Try<T> peekFailure(Consumer<? super Throwable> action) {
254272
public Optional<T> toOptional() {
255273
return Optional.of(value);
256274
}
275+
276+
@Override
277+
public Throwable getError() {
278+
throw new IllegalStateException("No error in Success");
279+
}
280+
281+
@Override
282+
public <L> Either<L, T> toEither(Function<? super Throwable, ? extends L> mapper) {
283+
return Either.right(value);
284+
}
257285
}
258286

259287
/**
@@ -319,6 +347,16 @@ public Try<T> peekFailure(Consumer<? super Throwable> action) {
319347
public Optional<T> toOptional() {
320348
return Optional.empty();
321349
}
350+
351+
@Override
352+
public Throwable getError() {
353+
return exception;
354+
}
355+
356+
@Override
357+
public <L> Either<L, T> toEither(Function<? super Throwable, ? extends L> mapper) {
358+
return Either.left(mapper.apply(exception));
359+
}
322360
}
323361

324362
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package com.dudko.tools.safejavastreams.demo.extensions;
2+
3+
import com.dudko.tools.safejavastreams.core.Either;
4+
import com.dudko.tools.safejavastreams.extensions.EitherExtensions;
5+
6+
import java.util.Optional;
7+
import java.util.concurrent.CompletableFuture;
8+
9+
public class EitherExtensionsDemo {
10+
public static void main(String[] args) {
11+
// 1. fromOptional
12+
Optional<String> opt = Optional.of("Hello");
13+
Either<String, String> eitherFromOpt = EitherExtensions.fromOptional(opt, () -> "Was empty");
14+
System.out.println("Either from Optional: " + eitherFromOpt);
15+
16+
// 2. fromOptional with empty value
17+
Optional<String> empty = Optional.empty();
18+
Either<String, String> eitherEmpty = EitherExtensions.fromOptional(empty, () -> "Missing value");
19+
System.out.println("Either from empty Optional: " + eitherEmpty);
20+
21+
// 3. fromFuture (success)
22+
CompletableFuture<String> future = CompletableFuture.completedFuture("Async result");
23+
Either<String, String> eitherFuture = EitherExtensions.fromFuture(future, Throwable::getMessage);
24+
System.out.println("Either from Future: " + eitherFuture);
25+
26+
// 4. fromFuture (failure)
27+
CompletableFuture<String> failedFuture = new CompletableFuture<>();
28+
failedFuture.completeExceptionally(new RuntimeException("Boom!"));
29+
Either<String, String> failedEither = EitherExtensions.fromFuture(failedFuture, Throwable::getMessage);
30+
System.out.println("Either from failed Future: " + failedEither);
31+
32+
// 5. fromChecked (success)
33+
Either<String, String> checkedSuccess = EitherExtensions.fromChecked(() -> "Success!", Throwable::getMessage);
34+
System.out.println("Either from checked (success): " + checkedSuccess);
35+
36+
// 6. fromChecked (failure)
37+
Either<String, String> checkedFailure = EitherExtensions.fromChecked(() -> {
38+
throw new IllegalStateException("Failure happened");
39+
}, Throwable::getMessage);
40+
System.out.println("Either from checked (failure): " + checkedFailure);
41+
42+
// 7. From Supplier (success case)
43+
Either<String, String> fromSupplierOk = EitherExtensions.fromSupplier(() -> "it works", Throwable::getMessage);
44+
System.out.println("From supplier success: " + fromSupplierOk);
45+
46+
// 8. From Supplier (failure case)
47+
Either<String, String> fromSupplierFail = EitherExtensions.fromSupplier(() -> {
48+
throw new IllegalStateException("boom from supplier");
49+
}, Throwable::getMessage);
50+
System.out.println("From supplier failure: " + fromSupplierFail);
51+
}
52+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package com.dudko.tools.safejavastreams.demo.extensions;
2+
3+
import com.dudko.tools.safejavastreams.core.Result;
4+
import com.dudko.tools.safejavastreams.extensions.ResultExtensions;
5+
6+
import java.util.Optional;
7+
import java.util.concurrent.CompletableFuture;
8+
import java.util.function.Supplier;
9+
10+
public class ResultExtensionsDemo {
11+
public static void main(String[] args) {
12+
// 1. From Optional (present)
13+
Optional<String> some = Optional.of("hello");
14+
Result<String, String> present = ResultExtensions.fromOptional(some, () -> "Value was not present");
15+
System.out.println("Present Optional: " + present);
16+
17+
// 2. From Optional (empty)
18+
Optional<String> none = Optional.empty();
19+
Result<String, String> empty = ResultExtensions.fromOptional(none, () -> "Missing value");
20+
System.out.println("Empty Optional: " + empty);
21+
22+
// 3. From Supplier (success)
23+
Supplier<String> supplier = () -> "computed";
24+
Result<String, String> computed = ResultExtensions.fromSupplier(supplier, Throwable::getMessage);
25+
System.out.println("Supplier success: " + computed);
26+
27+
// 4. From Supplier (failure)
28+
Supplier<String> failingSupplier = () -> {
29+
throw new IllegalStateException("boom");
30+
};
31+
Result<String, String> failed = ResultExtensions.fromSupplier(failingSupplier, Throwable::getMessage);
32+
System.out.println("Supplier failure: " + failed);
33+
34+
// 5. From CompletableFuture (success)
35+
CompletableFuture<String> future = CompletableFuture.completedFuture("async");
36+
Result<String, String> asyncResult = ResultExtensions.fromFuture(future, Throwable::getMessage);
37+
System.out.println("Future success: " + asyncResult);
38+
39+
// 6. From CompletableFuture (exceptional)
40+
CompletableFuture<String> broken = new CompletableFuture<>();
41+
broken.completeExceptionally(new RuntimeException("kaboom"));
42+
Result<String, String> brokenResult = ResultExtensions.fromFuture(broken, Throwable::getMessage);
43+
System.out.println("Future failure: " + brokenResult);
44+
}
45+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package com.dudko.tools.safejavastreams.demo.extensions;
2+
3+
4+
import com.dudko.tools.safejavastreams.core.Try;
5+
import com.dudko.tools.safejavastreams.extensions.TryExtensions;
6+
7+
import java.util.Optional;
8+
import java.util.concurrent.CompletableFuture;
9+
10+
public class TryExtensionsDemo {
11+
public static void main(String[] args) {
12+
// 1. From Optional (success)
13+
Optional<String> optional = Optional.of("hello");
14+
Try<String> fromOpt = TryExtensions.fromOptional(optional, () -> new IllegalStateException("Optional was empty"));
15+
System.out.println("From Optional: " + fromOpt);
16+
17+
// 2. From Optional (failure)
18+
Optional<String> empty = Optional.empty();
19+
Try<String> fromEmpty = TryExtensions.fromOptional(empty, () -> new RuntimeException("Missing value"));
20+
System.out.println("From Empty Optional: " + fromEmpty);
21+
22+
// 3. From ThrowingSupplier
23+
Try<String> wrapped = TryExtensions.from(() -> "Success!");
24+
Try<String> failed = TryExtensions.from(() -> {
25+
throw new Exception("Nope!");
26+
});
27+
System.out.println("From ThrowingSupplier (success): " + wrapped);
28+
System.out.println("From ThrowingSupplier (failure): " + failed);
29+
30+
// 4. From CompletableFuture
31+
CompletableFuture<String> future = CompletableFuture.completedFuture("Future done");
32+
Try<String> fromFuture = TryExtensions.fromFuture(future);
33+
System.out.println("From CompletableFuture: " + fromFuture);
34+
35+
// 5. From Broken CompletableFuture
36+
CompletableFuture<String> brokenFuture = new CompletableFuture<>();
37+
brokenFuture.completeExceptionally(new IllegalStateException("Boom"));
38+
Try<String> failedFuture = TryExtensions.fromFuture(brokenFuture);
39+
System.out.println("From Broken CompletableFuture: " + failedFuture);
40+
}
41+
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package com.dudko.tools.safejavastreams.extensions;
2+
3+
import com.dudko.tools.safejavastreams.core.Either;
4+
5+
import java.util.Optional;
6+
import java.util.concurrent.CompletableFuture;
7+
import java.util.function.Function;
8+
import java.util.function.Supplier;
9+
10+
/**
11+
* Utility methods to convert from other types to {@link Either}.
12+
*/
13+
public final class EitherExtensions {
14+
15+
private EitherExtensions() {
16+
throw new AssertionError("No instances for you!");
17+
}
18+
19+
/**
20+
* Converts an {@link Optional} to an {@link Either}.
21+
*
22+
* @param optional the optional value
23+
* @param leftSupplier supplier for the Left value if Optional is empty
24+
* @param <L> type of Left (error)
25+
* @param <R> type of Right (success)
26+
* @return Either with Right if value is present, Left otherwise
27+
*/
28+
public static <L, R> Either<L, R> fromOptional(Optional<R> optional, Supplier<? extends L> leftSupplier) {
29+
return optional.map(Either::<L, R>right)
30+
.orElseGet(() -> Either.left(leftSupplier.get()));
31+
}
32+
33+
/**
34+
* Converts a {@link CompletableFuture} to an {@link Either}. Blocks the current thread.
35+
*
36+
* @param future the future
37+
* @param errorMapper function to convert exceptions to Left
38+
* @param <L> type of Left (error)
39+
* @param <R> type of Right (success)
40+
* @return Either with result or mapped error
41+
*/
42+
public static <L, R> Either<L, R> fromFuture(
43+
CompletableFuture<R> future,
44+
Function<Throwable, ? extends L> errorMapper) {
45+
try {
46+
return Either.right(future.get());
47+
} catch (Throwable t) {
48+
Throwable root = t.getCause() != null ? t.getCause() : t;
49+
return Either.left(errorMapper.apply(root));
50+
}
51+
}
52+
53+
/**
54+
* Wraps a {@link Supplier} that may throw, producing an {@link Either}.
55+
*
56+
* @param supplier the supplier
57+
* @param errorMapper mapper from exception to Left value
58+
* @param <L> type of Left (error)
59+
* @param <R> type of Right (success)
60+
* @return Either with result or mapped error
61+
*/
62+
public static <L, R> Either<L, R> fromChecked(Supplier<R> supplier, Function<Throwable, ? extends L> errorMapper) {
63+
try {
64+
return Either.right(supplier.get());
65+
} catch (Throwable t) {
66+
return Either.left(errorMapper.apply(t));
67+
}
68+
}
69+
70+
/**
71+
* Wraps a supplier that may throw, producing an {@link Either}.
72+
*
73+
* @param supplier the supplier to execute
74+
* @param errorMapper a function mapping a {@link Throwable} to an error value
75+
* @param <L> the error type (Left)
76+
* @param <R> the result type (Right)
77+
* @return a successful {@link Either} with the supplier's value, or a failed {@link Either} with the mapped error
78+
*/
79+
public static <L, R> Either<L, R> fromSupplier(Supplier<R> supplier, Function<Throwable, ? extends L> errorMapper) {
80+
try {
81+
return Either.right(supplier.get());
82+
} catch (Throwable t) {
83+
return Either.left(errorMapper.apply(t));
84+
}
85+
}
86+
87+
}

0 commit comments

Comments
 (0)