Add UncheckedFuture.

Add UncheckedException.
Add UncheckedExecutionException.
Add UncheckedTimeoutException.
Add UncheckedInterruptedException.
This commit is contained in:
Gary Gregory 2021-08-29 13:51:56 -04:00
parent 8d30dfb09f
commit 5afd54ce67
12 changed files with 607 additions and 0 deletions

View File

@ -73,6 +73,11 @@ The <action> type attribute can be add,update,fix,remove.
<action type="add" dev="ggregory" due-to="Gary Gregory">Add BooleanConsumer.</action>
<action type="add" dev="ggregory" due-to="Gary Gregory">Add IntToCharFunction.</action>
<action type="add" dev="ggregory" due-to="Gary Gregory">Add IntStreams.</action>
<action type="add" dev="ggregory" due-to="Gary Gregory">Add UncheckedFuture.</action>
<action type="add" dev="ggregory" due-to="Gary Gregory">Add UncheckedException.</action>
<action type="add" dev="ggregory" due-to="Gary Gregory">Add UncheckedExecutionException.</action>
<action type="add" dev="ggregory" due-to="Gary Gregory">Add UncheckedTimeoutException.</action>
<action type="add" dev="ggregory" due-to="Gary Gregory">Add UncheckedInterruptedException.</action>
<!-- UPDATE -->
<action type="update" dev="ggregory" due-to="Dependabot, Gary Gregory">Bump spotbugs-maven-plugin from 4.2.0 to 4.2.3 #735.</action>
<action type="update" dev="ggregory" due-to="Dependabot, XenoAmess">Bump Bump actions/cache from v2.1.4 to v2.1.6 #742, #752, #764.</action>

View File

@ -0,0 +1,42 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.lang3.concurrent;
import java.util.concurrent.ExecutionException;
import org.apache.commons.lang3.exception.UncheckedException;
/**
* Unchecked {@link ExecutionException}.
*
* @since 3.13.0
*/
public class UncheckedExecutionException extends UncheckedException {
private static final long serialVersionUID = 1L;
/**
* Constructs an instance initialized to the given {@code cause}.
*
* @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method). (A @{code null} value
* is permitted, and indicates that the cause is nonexistent or unknown.)
*/
public UncheckedExecutionException(final Throwable cause) {
super(cause);
}
}

View File

@ -0,0 +1,90 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.lang3.concurrent;
import java.util.Collection;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.stream.Collectors;
import org.apache.commons.lang3.exception.UncheckedInterruptedException;
/**
* An {@link Future} that throws unchecked instead checked exceptions.
*
* @param <V> The result type returned by this Future's {@link #get()} and {@link #get(long, TimeUnit)} methods.
* @see Future
* @see Exception
* @since 3.13.0
*/
public interface UncheckedFuture<V> extends Future<V> {
/**
* Maps the given instances as unchecked.
*
* @param <T> The result type returned by this Future's {@link #get()} and {@link #get(long, TimeUnit)} methods.
*
* @param futures The Futures to uncheck.
* @return a new collection.
*/
static <T> Collection<UncheckedFuture<T>> on(final Collection<Future<T>> futures) {
return futures.stream().map(UncheckedFuture::on).collect(Collectors.toList());
}
/**
* Creates a new instance on the given Future.
*
* @param <T> The result type returned by this Future's {@link #get()} and {@link #get(long, TimeUnit)} methods.
*
* @param future The Future to uncheck.
* @return a new instance.
*/
static <T> UncheckedFuture<T> on(final Future<T> future) {
return new UncheckedFutureImpl<>(future);
}
/**
* Gets per {@link Future#get()} but rethrows checked exceptions as unchecked.
* <p>
* The default mapping from checked to unchecked is:
* </p>
* <ul>
* <li>{@link InterruptedException} \u2192 {@link UncheckedInterruptedException}</li>
* <li>{@link ExecutionException} \u2192 {@link UncheckedExecutionException}</li>
* </ul>
*/
@Override
V get();
/**
* Gets per {@link Future#get(long, TimeUnit)} but rethrows checked exceptions as unchecked.
* <p>
* The default mapping from checked to unchecked is:
* </p>
* <ul>
* <li>{@link InterruptedException} \u2192 {@link UncheckedInterruptedException}</li>
* <li>{@link ExecutionException} \u2192 {@link UncheckedExecutionException}</li>
* <li>{@link TimeoutException} \u2192 {@link UncheckedTimeoutException}</li>
* </ul>
*/
@Override
V get(long timeout, TimeUnit unit);
}

View File

@ -0,0 +1,81 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.lang3.concurrent;
import java.util.Objects;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.apache.commons.lang3.exception.UncheckedInterruptedException;
/**
* An {@link Future} implementation that throws unchecked instead of checked exceptions.
*
* @see Future
* @since 3.13.0
*/
class UncheckedFutureImpl<V> implements UncheckedFuture<V> {
private final Future<V> future;
UncheckedFutureImpl(final Future<V> future) {
this.future = Objects.requireNonNull(future, "future");
}
@Override
public boolean cancel(final boolean mayInterruptIfRunning) {
return future.cancel(mayInterruptIfRunning);
}
@Override
public V get() {
try {
return future.get();
} catch (final InterruptedException e) {
throw new UncheckedInterruptedException(e);
} catch (final ExecutionException e) {
throw new UncheckedExecutionException(e);
}
}
@Override
public V get(final long timeout, final TimeUnit unit) {
try {
return future.get(timeout, unit);
} catch (final InterruptedException e) {
throw new UncheckedInterruptedException(e);
} catch (final ExecutionException e) {
throw new UncheckedExecutionException(e);
} catch (final TimeoutException e) {
throw new UncheckedTimeoutException(e);
}
}
@Override
public boolean isCancelled() {
return future.isCancelled();
}
@Override
public boolean isDone() {
return future.isDone();
}
}

View File

@ -0,0 +1,42 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.lang3.concurrent;
import java.util.concurrent.TimeoutException;
import org.apache.commons.lang3.exception.UncheckedException;
/**
* Unchecked {@link TimeoutException}.
*
* @since 3.13.0
*/
public class UncheckedTimeoutException extends UncheckedException {
private static final long serialVersionUID = 1L;
/**
* Constructs an instance initialized to the given {@code cause}.
*
* @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method). (A @{code null} value
* is permitted, and indicates that the cause is nonexistent or unknown.)
*/
public UncheckedTimeoutException(final Throwable cause) {
super(cause);
}
}

View File

@ -0,0 +1,41 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.lang3.exception;
/**
* Abstracts the concept of wrapping a checked exception as unchecked.
* <p>
* Subclasses should only be used to wrapped checked exception.
* </p>
*
* @since 3.13.0
*/
public class UncheckedException extends RuntimeException {
private static final long serialVersionUID = 1L;
/**
* Constructs an instance initialized to the given {@code cause}.
*
* @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method). (A @{code null} value
* is permitted, and indicates that the cause is nonexistent or unknown.)
*/
public UncheckedException(final Throwable cause) {
super(cause);
}
}

View File

@ -0,0 +1,38 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.lang3.exception;
/**
* Unchecked {@link InterruptedException}.
*
* @since 3.13.0
*/
public class UncheckedInterruptedException extends UncheckedException {
private static final long serialVersionUID = 1L;
/**
* Constructs an instance initialized to the given {@code cause}.
*
* @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method). (A @{code null} value
* is permitted, and indicates that the cause is nonexistent or unknown.)
*/
public UncheckedInterruptedException(final Throwable cause) {
super(cause);
}
}

View File

@ -0,0 +1,34 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.lang3.concurrent;
import static org.junit.jupiter.api.Assertions.assertSame;
import org.junit.jupiter.api.Test;
/**
* Tests {@link UncheckedExecutionException}.
*/
public class UncheckedExecutionExceptionTest {
@Test
public void testConstructWithCause() {
Exception e = new Exception();
assertSame(e, new UncheckedExecutionException(e).getCause());
}
}

View File

@ -0,0 +1,132 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.lang3.concurrent;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.stream.Collectors;
import org.apache.commons.lang3.exception.UncheckedInterruptedException;
import org.junit.jupiter.api.Test;
/**
* Tests {@link UncheckedFuture}.
*/
public class UncheckedFutureTest {
private static class TestFuture<V> implements Future<V> {
private final V get;
private final Exception executionException;
TestFuture(final Exception throwable) {
this.get = null;
this.executionException = throwable;
}
TestFuture(final V get) {
this.get = get;
this.executionException = null;
}
@Override
public boolean cancel(final boolean mayInterruptIfRunning) {
return false;
}
@SuppressWarnings("unchecked") // Programming error if call site blows up at runtime.
private <T extends Exception> void checkExecutionException() throws T {
if (executionException != null) {
throw (T) executionException;
}
}
@Override
public V get() throws InterruptedException, ExecutionException {
checkExecutionException();
return get;
}
@Override
public V get(final long timeout, final TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
checkExecutionException();
return get;
}
@Override
public boolean isCancelled() {
return false;
}
@Override
public boolean isDone() {
return false;
}
}
@Test
public void testGetExecutionException() {
final ExecutionException e = new ExecutionException(new Exception());
assertThrows(UncheckedExecutionException.class, () -> UncheckedFuture.on(new TestFuture<>(e)).get());
}
@Test
public void testGetInterruptedException() {
final InterruptedException e = new InterruptedException();
assertThrows(UncheckedInterruptedException.class, () -> UncheckedFuture.on(new TestFuture<>(e)).get());
}
@Test
public void testGetLongExecutionException() {
final ExecutionException e = new ExecutionException(new Exception());
assertThrows(UncheckedExecutionException.class, () -> UncheckedFuture.on(new TestFuture<>(e)).get(1, TimeUnit.MICROSECONDS));
}
@Test
public void testGetLongInterruptedException() {
final InterruptedException e = new InterruptedException();
assertThrows(UncheckedInterruptedException.class, () -> UncheckedFuture.on(new TestFuture<>(e)).get(1, TimeUnit.MICROSECONDS));
}
@Test
public void testGetLongTimeoutException() {
final TimeoutException e = new TimeoutException();
assertThrows(UncheckedTimeoutException.class, () -> UncheckedFuture.on(new TestFuture<>(e)).get(1, TimeUnit.MICROSECONDS));
}
@Test
public void testOnCollection() {
final List<String> expected = Arrays.asList("Y", "Z");
final List<Future<String>> input = Arrays.asList(new TestFuture<>("Y"), new TestFuture<>("Z"));
assertEquals(expected, UncheckedFuture.on(input).stream().map(UncheckedFuture::get).collect(Collectors.toList()));
}
@Test
public void testOnFuture() {
assertEquals("Z", UncheckedFuture.on(new TestFuture<>("Z")).get());
}
}

View File

@ -0,0 +1,34 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.lang3.concurrent;
import static org.junit.jupiter.api.Assertions.assertSame;
import org.junit.jupiter.api.Test;
/**
* Tests {@link UncheckedTimeoutException}.
*/
public class UncheckedTimeoutExceptionTest {
@Test
public void testConstructWithCause() {
Exception e = new Exception();
assertSame(e, new UncheckedTimeoutException(e).getCause());
}
}

View File

@ -0,0 +1,34 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.lang3.exception;
import static org.junit.jupiter.api.Assertions.assertSame;
import org.junit.jupiter.api.Test;
/**
* Tests {@link UncheckedException}.
*/
public class UncheckedExceptionTest {
@Test
public void testConstructWithCause() {
Exception e = new Exception();
assertSame(e, new UncheckedException(e).getCause());
}
}

View File

@ -0,0 +1,34 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.lang3.exception;
import static org.junit.jupiter.api.Assertions.assertSame;
import org.junit.jupiter.api.Test;
/**
* Tests {@link UncheckedInterruptedException}.
*/
public class UncheckedInterruptedExceptionTest {
@Test
public void testConstructWithCause() {
Exception e = new Exception();
assertSame(e, new UncheckedInterruptedException(e).getCause());
}
}