Skip to content

Introduce default method checked() for throwable functional interface #33825

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,15 @@

import java.util.function.BiFunction;

import static org.springframework.util.function.ThrowingFunction.throwAsUnchecked;

/**
* A {@link BiFunction} that allows invocation of code that throws a checked
* exception.
*
* @author Stephane Nicoll
* @author Phillip Webb
* @author Yanming Zhou
* @since 6.0
* @param <T> the type of the first argument to the function
* @param <U> the type of the second argument to the function
Expand Down Expand Up @@ -96,6 +99,33 @@ public R apply(T t, U u) {
};
}

/**
* Return a new {@link ThrowingBiFunction} where the {@link #apply(Object, Object)}
* method will throw original checked exceptions.
* @return the replacement {@link ThrowingBiFunction} instance
*/
@SuppressWarnings("NullAway")
default ThrowingBiFunction<T, U, R> checked() {
ThrowingBiFunction<T, U, R> function = this;
return new ThrowingBiFunction<>() {
@Override
public R applyWithException(T t, U u) throws Exception {
return function.applyWithException(t, u);
}

@Override
public R apply(T t, U u) {
try {
return function.applyWithException(t, u);
}
catch (Exception ex) {
throwAsUnchecked(ex);
return null; // Never happens
}
}
};
}

/**
* Lambda friendly convenience method that can be used to create a
* {@link ThrowingBiFunction} where the {@link #apply(Object, Object)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,15 @@
import java.util.function.BiFunction;
import java.util.function.Consumer;

import static org.springframework.util.function.ThrowingFunction.throwAsUnchecked;

/**
* A {@link Consumer} that allows invocation of code that throws a checked
* exception.
*
* @author Stephane Nicoll
* @author Phillip Webb
* @author Yanming Zhou
* @since 6.0
* @param <T> the type of the input to the operation
*/
Expand Down Expand Up @@ -88,6 +91,32 @@ public void accept(T t) {
};
}

/**
* Return a new {@link ThrowingConsumer} where the {@link #accept(Object)}
* method will throw original checked exceptions.
* @return the replacement {@link ThrowingConsumer} instance
*/
@SuppressWarnings("NullAway")
default ThrowingConsumer<T> checked() {
ThrowingConsumer<T> consumer = this;
return new ThrowingConsumer<>() {
@Override
public void acceptWithException(T t) throws Exception {
consumer.acceptWithException(t);
}

@Override
public void accept(T t) {
try {
consumer.acceptWithException(t);
}
catch (Exception ex) {
throwAsUnchecked(ex);
}
}
};
}

/**
* Lambda friendly convenience method that can be used to create a
* {@link ThrowingConsumer} where the {@link #accept(Object)} method wraps
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
*
* @author Stephane Nicoll
* @author Phillip Webb
* @author Yanming Zhou
* @since 6.0
* @param <T> the type of the input to the function
* @param <R> the type of the result of the function
Expand Down Expand Up @@ -91,6 +92,33 @@ public R apply(T t) {
};
}

/**
* Return a new {@link ThrowingFunction} where the {@link #apply(Object)}
* method will throw original checked exceptions.
* @return the replacement {@link ThrowingFunction} instance
*/
@SuppressWarnings("NullAway")
default ThrowingFunction<T, R> checked() {
ThrowingFunction<T, R> function = this;
return new ThrowingFunction<>() {
@Override
public R applyWithException(T t) throws Exception {
return function.applyWithException(t);
}

@Override
public R apply(T t) {
try {
return function.applyWithException(t);
}
catch (Exception ex) {
throwAsUnchecked(ex);
return null; // Never happens
}
}
};
}

/**
* Lambda friendly convenience method that can be used to create a
* {@link ThrowingFunction} where the {@link #apply(Object)} method wraps
Expand Down Expand Up @@ -135,4 +163,9 @@ static <T, R> ThrowingFunction<T, R> of(ThrowingFunction<T, R> function,
return function.throwing(exceptionWrapper);
}

@SuppressWarnings ("unchecked")
static <E extends Throwable> void throwAsUnchecked(Exception exception) throws E {
throw (E) exception;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,14 @@
import java.util.function.BiFunction;
import java.util.function.Supplier;

import static org.springframework.util.function.ThrowingFunction.throwAsUnchecked;

/**
* A {@link Supplier} that allows invocation of code that throws a checked exception.
*
* @author Stephane Nicoll
* @author Phillip Webb
* @author Yanming Zhou
* @since 6.0
* @param <T> the type of results supplied by this supplier
*/
Expand Down Expand Up @@ -86,6 +89,33 @@ public T get() {
};
}

/**
* Return a new {@link ThrowingSupplier} where the {@link #get()}
* method will throw original checked exceptions.
* @return the replacement {@link ThrowingSupplier} instance
*/
@SuppressWarnings("NullAway")
default ThrowingSupplier<T> checked() {
ThrowingSupplier<T> supplier = this;
return new ThrowingSupplier<>() {
@Override
public T getWithException() throws Exception {
return supplier.getWithException();
}

@Override
public T get() {
try {
return supplier.getWithException();
}
catch (Exception ex) {
throwAsUnchecked(ex);
return null; // Never happens
}
}
};
}

/**
* Lambda friendly convenience method that can be used to create a
* {@link ThrowingSupplier} where the {@link #get()} method wraps any checked
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,15 @@
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatIOException;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;

/**
* Tests for {@link ThrowingBiFunction}.
*
* @author Phillip Webb
* @author Yanming Zhou
* @since 6.0
*/
class ThrowingBiFunctionTests {
Expand Down Expand Up @@ -76,6 +78,12 @@ void ofModifiesThrowException() {
() -> function.apply(this, this)).withCauseInstanceOf(IOException.class);
}

@Test
void checked() {
ThrowingBiFunction<Object, Object, Object> function = ThrowingBiFunction.of(this::throwIOException).checked();
assertThatIOException().isThrownBy(() -> function.apply(this, this));
}

private Object throwIOException(Object o, Object u) throws IOException {
throw new IOException();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,15 @@
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatIOException;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;

/**
* Tests for {@link ThrowingConsumer}.
*
* @author Phillip Webb
* @author Yanming Zhou
* @since 6.0
*/
class ThrowingConsumerTests {
Expand Down Expand Up @@ -76,6 +78,12 @@ void ofModifiesThrownException() {
() -> consumer.accept(this)).withCauseInstanceOf(IOException.class);
}

@Test
void checked() {
ThrowingConsumer<Object> consumer = ThrowingConsumer.of(this::throwIOException).checked();
assertThatIOException().isThrownBy(() -> consumer.accept(this));
}

private void throwIOException(Object o) throws IOException {
throw new IOException();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,15 @@
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatIOException;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;

/**
* Tests for {@link ThrowingFunction}.
*
* @author Phillip Webb
* @author Yanming Zhou
* @since 6.0
*/
class ThrowingFunctionTests {
Expand Down Expand Up @@ -76,6 +78,12 @@ void ofModifiesThrowException() {
() -> function.apply(this)).withCauseInstanceOf(IOException.class);
}

@Test
void checked() {
ThrowingFunction<Object, Object> function = ThrowingFunction.of(this::throwIOException).checked();
assertThatIOException().isThrownBy(() -> function.apply(this));
}

private Object throwIOException(Object o) throws IOException {
throw new IOException();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,15 @@
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatIOException;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;

/**
* Tests for {@link ThrowingSupplier}.
*
* @author Phillip Webb
* @author Yanming Zhou
* @since 6.0
*/
class ThrowingSupplierTests {
Expand Down Expand Up @@ -77,6 +79,12 @@ void ofModifiesThrowException() {
supplier::get).withCauseInstanceOf(IOException.class);
}

@Test
void checked() {
ThrowingSupplier<Object> supplier = ThrowingSupplier.of(this::throwIOException).checked();
assertThatIOException().isThrownBy(supplier::get);
}

private Object throwIOException() throws IOException {
throw new IOException();
}
Expand Down