Skip to content

Commit 2c5fc7e

Browse files
committed
Introduce default method checked() for throwable functional interface
Allow throwing original checked exception instead of wrapping unchecked exception
1 parent bc65f93 commit 2c5fc7e

File tree

8 files changed

+154
-0
lines changed

8 files changed

+154
-0
lines changed

spring-core/src/main/java/org/springframework/util/function/ThrowingBiFunction.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,15 @@
1818

1919
import java.util.function.BiFunction;
2020

21+
import static org.springframework.util.function.ThrowingFunction.throwAsUnchecked;
22+
2123
/**
2224
* A {@link BiFunction} that allows invocation of code that throws a checked
2325
* exception.
2426
*
2527
* @author Stephane Nicoll
2628
* @author Phillip Webb
29+
* @author Yanming Zhou
2730
* @since 6.0
2831
* @param <T> the type of the first argument to the function
2932
* @param <U> the type of the second argument to the function
@@ -96,6 +99,33 @@ public R apply(T t, U u) {
9699
};
97100
}
98101

102+
/**
103+
* Return a new {@link ThrowingBiFunction} where the {@link #apply(Object, Object)}
104+
* method will throw original checked exceptions.
105+
* @return the replacement {@link ThrowingBiFunction} instance
106+
*/
107+
@SuppressWarnings("NullAway")
108+
default ThrowingBiFunction<T, U, R> checked() {
109+
ThrowingBiFunction<T, U, R> function = this;
110+
return new ThrowingBiFunction<>() {
111+
@Override
112+
public R applyWithException(T t, U u) throws Exception {
113+
return function.applyWithException(t, u);
114+
}
115+
116+
@Override
117+
public R apply(T t, U u) {
118+
try {
119+
return function.applyWithException(t, u);
120+
}
121+
catch (Exception ex) {
122+
throwAsUnchecked(ex);
123+
return null; // Never happens
124+
}
125+
}
126+
};
127+
}
128+
99129
/**
100130
* Lambda friendly convenience method that can be used to create a
101131
* {@link ThrowingBiFunction} where the {@link #apply(Object, Object)}

spring-core/src/main/java/org/springframework/util/function/ThrowingConsumer.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,15 @@
1919
import java.util.function.BiFunction;
2020
import java.util.function.Consumer;
2121

22+
import static org.springframework.util.function.ThrowingFunction.throwAsUnchecked;
23+
2224
/**
2325
* A {@link Consumer} that allows invocation of code that throws a checked
2426
* exception.
2527
*
2628
* @author Stephane Nicoll
2729
* @author Phillip Webb
30+
* @author Yanming Zhou
2831
* @since 6.0
2932
* @param <T> the type of the input to the operation
3033
*/
@@ -88,6 +91,32 @@ public void accept(T t) {
8891
};
8992
}
9093

94+
/**
95+
* Return a new {@link ThrowingConsumer} where the {@link #accept(Object)}
96+
* method will throw original checked exceptions.
97+
* @return the replacement {@link ThrowingConsumer} instance
98+
*/
99+
@SuppressWarnings("NullAway")
100+
default ThrowingConsumer<T> checked() {
101+
ThrowingConsumer<T> supplier = this;
102+
return new ThrowingConsumer<>() {
103+
@Override
104+
public void acceptWithException(T t) throws Exception {
105+
supplier.acceptWithException(t);
106+
}
107+
108+
@Override
109+
public void accept(T t) {
110+
try {
111+
supplier.acceptWithException(t);
112+
}
113+
catch (Exception ex) {
114+
throwAsUnchecked(ex);
115+
}
116+
}
117+
};
118+
}
119+
91120
/**
92121
* Lambda friendly convenience method that can be used to create a
93122
* {@link ThrowingConsumer} where the {@link #accept(Object)} method wraps

spring-core/src/main/java/org/springframework/util/function/ThrowingFunction.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
*
2626
* @author Stephane Nicoll
2727
* @author Phillip Webb
28+
* @author Yanming Zhou
2829
* @since 6.0
2930
* @param <T> the type of the input to the function
3031
* @param <R> the type of the result of the function
@@ -91,6 +92,33 @@ public R apply(T t) {
9192
};
9293
}
9394

95+
/**
96+
* Return a new {@link ThrowingFunction} where the {@link #apply(Object)}
97+
* method will throw original checked exceptions.
98+
* @return the replacement {@link ThrowingFunction} instance
99+
*/
100+
@SuppressWarnings("NullAway")
101+
default ThrowingFunction<T, R> checked() {
102+
ThrowingFunction<T, R> function = this;
103+
return new ThrowingFunction<>() {
104+
@Override
105+
public R applyWithException(T t) throws Exception {
106+
return function.applyWithException(t);
107+
}
108+
109+
@Override
110+
public R apply(T t) {
111+
try {
112+
return function.applyWithException(t);
113+
}
114+
catch (Exception ex) {
115+
throwAsUnchecked(ex);
116+
return null; // Never happens
117+
}
118+
}
119+
};
120+
}
121+
94122
/**
95123
* Lambda friendly convenience method that can be used to create a
96124
* {@link ThrowingFunction} where the {@link #apply(Object)} method wraps
@@ -135,4 +163,9 @@ static <T, R> ThrowingFunction<T, R> of(ThrowingFunction<T, R> function,
135163
return function.throwing(exceptionWrapper);
136164
}
137165

166+
@SuppressWarnings ("unchecked")
167+
static <E extends Throwable> void throwAsUnchecked(Exception exception) throws E {
168+
throw (E) exception;
169+
}
170+
138171
}

spring-core/src/main/java/org/springframework/util/function/ThrowingSupplier.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,14 @@
1919
import java.util.function.BiFunction;
2020
import java.util.function.Supplier;
2121

22+
import static org.springframework.util.function.ThrowingFunction.throwAsUnchecked;
23+
2224
/**
2325
* A {@link Supplier} that allows invocation of code that throws a checked exception.
2426
*
2527
* @author Stephane Nicoll
2628
* @author Phillip Webb
29+
* @author Yanming Zhou
2730
* @since 6.0
2831
* @param <T> the type of results supplied by this supplier
2932
*/
@@ -86,6 +89,33 @@ public T get() {
8689
};
8790
}
8891

92+
/**
93+
* Return a new {@link ThrowingSupplier} where the {@link #get()}
94+
* method will throw original checked exceptions.
95+
* @return the replacement {@link ThrowingSupplier} instance
96+
*/
97+
@SuppressWarnings("NullAway")
98+
default ThrowingSupplier<T> checked() {
99+
ThrowingSupplier<T> supplier = this;
100+
return new ThrowingSupplier<>() {
101+
@Override
102+
public T getWithException() throws Exception {
103+
return supplier.getWithException();
104+
}
105+
106+
@Override
107+
public T get() {
108+
try {
109+
return supplier.getWithException();
110+
}
111+
catch (Exception ex) {
112+
throwAsUnchecked(ex);
113+
return null; // Never happens
114+
}
115+
}
116+
};
117+
}
118+
89119
/**
90120
* Lambda friendly convenience method that can be used to create a
91121
* {@link ThrowingSupplier} where the {@link #get()} method wraps any checked

spring-core/src/test/java/org/springframework/util/function/ThrowingBiFunctionTests.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,15 @@
2121
import org.junit.jupiter.api.Test;
2222

2323
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
24+
import static org.assertj.core.api.Assertions.assertThatIOException;
2425
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
2526
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
2627

2728
/**
2829
* Tests for {@link ThrowingBiFunction}.
2930
*
3031
* @author Phillip Webb
32+
* @author Yanming Zhou
3133
* @since 6.0
3234
*/
3335
class ThrowingBiFunctionTests {
@@ -76,6 +78,12 @@ void ofModifiesThrowException() {
7678
() -> function.apply(this, this)).withCauseInstanceOf(IOException.class);
7779
}
7880

81+
@Test
82+
void checked() {
83+
ThrowingBiFunction<Object, Object, Object> function = ThrowingBiFunction.of(this::throwIOException).checked();
84+
assertThatIOException().isThrownBy(() -> function.apply(this, this));
85+
}
86+
7987
private Object throwIOException(Object o, Object u) throws IOException {
8088
throw new IOException();
8189
}

spring-core/src/test/java/org/springframework/util/function/ThrowingConsumerTests.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,15 @@
2121
import org.junit.jupiter.api.Test;
2222

2323
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
24+
import static org.assertj.core.api.Assertions.assertThatIOException;
2425
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
2526
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
2627

2728
/**
2829
* Tests for {@link ThrowingConsumer}.
2930
*
3031
* @author Phillip Webb
32+
* @author Yanming Zhou
3133
* @since 6.0
3234
*/
3335
class ThrowingConsumerTests {
@@ -76,6 +78,12 @@ void ofModifiesThrownException() {
7678
() -> consumer.accept(this)).withCauseInstanceOf(IOException.class);
7779
}
7880

81+
@Test
82+
void checked() {
83+
ThrowingConsumer<Object> consumer = ThrowingConsumer.of(this::throwIOException).checked();
84+
assertThatIOException().isThrownBy(() -> consumer.accept(this));
85+
}
86+
7987
private void throwIOException(Object o) throws IOException {
8088
throw new IOException();
8189
}

spring-core/src/test/java/org/springframework/util/function/ThrowingFunctionTests.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,15 @@
2121
import org.junit.jupiter.api.Test;
2222

2323
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
24+
import static org.assertj.core.api.Assertions.assertThatIOException;
2425
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
2526
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
2627

2728
/**
2829
* Tests for {@link ThrowingFunction}.
2930
*
3031
* @author Phillip Webb
32+
* @author Yanming Zhou
3133
* @since 6.0
3234
*/
3335
class ThrowingFunctionTests {
@@ -76,6 +78,12 @@ void ofModifiesThrowException() {
7678
() -> function.apply(this)).withCauseInstanceOf(IOException.class);
7779
}
7880

81+
@Test
82+
void checked() {
83+
ThrowingFunction<Object, Object> function = ThrowingFunction.of(this::throwIOException).checked();
84+
assertThatIOException().isThrownBy(() -> function.apply(this));
85+
}
86+
7987
private Object throwIOException(Object o) throws IOException {
8088
throw new IOException();
8189
}

spring-core/src/test/java/org/springframework/util/function/ThrowingSupplierTests.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,15 @@
2121
import org.junit.jupiter.api.Test;
2222

2323
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
24+
import static org.assertj.core.api.Assertions.assertThatIOException;
2425
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
2526
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
2627

2728
/**
2829
* Tests for {@link ThrowingSupplier}.
2930
*
3031
* @author Phillip Webb
32+
* @author Yanming Zhou
3133
* @since 6.0
3234
*/
3335
class ThrowingSupplierTests {
@@ -77,6 +79,12 @@ void ofModifiesThrowException() {
7779
supplier::get).withCauseInstanceOf(IOException.class);
7880
}
7981

82+
@Test
83+
void checked() {
84+
ThrowingSupplier<Object> supplier = ThrowingSupplier.of(this::throwIOException).checked();
85+
assertThatIOException().isThrownBy(supplier::get);
86+
}
87+
8088
private Object throwIOException() throws IOException {
8189
throw new IOException();
8290
}

0 commit comments

Comments
 (0)