8186265: Make toString() methods of "task" objects more useful
Reviewed-by: martin, psandoz, rriggs, dholmes, darcy
This commit is contained in:
parent
2ea646cc20
commit
229cce5f44
src/java.base/share/classes/java/util/concurrent
test/jdk/java/util/concurrent
@ -2490,13 +2490,13 @@ public class CompletableFuture<T> implements Future<T>, CompletionStage<T> {
|
||||
for (Completion p = stack; p != null; p = p.next)
|
||||
++count;
|
||||
return super.toString() +
|
||||
((r == null) ?
|
||||
((count == 0) ?
|
||||
"[Not completed]" :
|
||||
"[Not completed, " + count + " dependents]") :
|
||||
(((r instanceof AltResult) && ((AltResult)r).ex != null) ?
|
||||
"[Completed exceptionally]" :
|
||||
"[Completed normally]"));
|
||||
((r == null)
|
||||
? ((count == 0)
|
||||
? "[Not completed]"
|
||||
: "[Not completed, " + count + " dependents]")
|
||||
: (((r instanceof AltResult) && ((AltResult)r).ex != null)
|
||||
? "[Completed exceptionally: " + ((AltResult)r).ex + "]"
|
||||
: "[Completed normally]"));
|
||||
}
|
||||
|
||||
// jdk9 additions
|
||||
|
@ -514,6 +514,9 @@ public class Executors {
|
||||
task.run();
|
||||
return result;
|
||||
}
|
||||
public String toString() {
|
||||
return super.toString() + "[Wrapped task = " + task + "]";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -540,6 +543,10 @@ public class Executors {
|
||||
throw e.getException();
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return super.toString() + "[Wrapped task = " + task + "]";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -592,6 +599,10 @@ public class Executors {
|
||||
throw e.getException();
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return super.toString() + "[Wrapped task = " + task + "]";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1375,6 +1375,9 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||
public final void setRawResult(T v) { result = v; }
|
||||
public final boolean exec() { runnable.run(); return true; }
|
||||
public final void run() { invoke(); }
|
||||
public String toString() {
|
||||
return super.toString() + "[Wrapped task = " + runnable + "]";
|
||||
}
|
||||
private static final long serialVersionUID = 5232453952276885070L;
|
||||
}
|
||||
|
||||
@ -1392,6 +1395,9 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||
public final void setRawResult(Void v) { }
|
||||
public final boolean exec() { runnable.run(); return true; }
|
||||
public final void run() { invoke(); }
|
||||
public String toString() {
|
||||
return super.toString() + "[Wrapped task = " + runnable + "]";
|
||||
}
|
||||
private static final long serialVersionUID = 5232453952276885070L;
|
||||
}
|
||||
|
||||
@ -1437,6 +1443,9 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||
}
|
||||
}
|
||||
public final void run() { invoke(); }
|
||||
public String toString() {
|
||||
return super.toString() + "[Wrapped task = " + callable + "]";
|
||||
}
|
||||
private static final long serialVersionUID = 2838392045355241008L;
|
||||
}
|
||||
|
||||
|
@ -480,6 +480,41 @@ public class FutureTask<V> implements RunnableFuture<V> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of this FutureTask.
|
||||
*
|
||||
* @implSpec
|
||||
* The default implementation returns a string identifying this
|
||||
* FutureTask, as well as its completion state. The state, in
|
||||
* brackets, contains one of the strings {@code "Completed Normally"},
|
||||
* {@code "Completed Exceptionally"}, {@code "Cancelled"}, or {@code
|
||||
* "Not completed"}.
|
||||
*
|
||||
* @return a string representation of this FutureTask
|
||||
*/
|
||||
public String toString() {
|
||||
final String status;
|
||||
switch (state) {
|
||||
case NORMAL:
|
||||
status = "[Completed normally]";
|
||||
break;
|
||||
case EXCEPTIONAL:
|
||||
status = "[Completed exceptionally: " + outcome + "]";
|
||||
break;
|
||||
case CANCELLED:
|
||||
case INTERRUPTING:
|
||||
case INTERRUPTED:
|
||||
status = "[Cancelled]";
|
||||
break;
|
||||
default:
|
||||
final Callable<?> callable = this.callable;
|
||||
status = (callable == null)
|
||||
? "[Not completed]"
|
||||
: "[Not completed, task = " + callable + "]";
|
||||
}
|
||||
return super.toString() + status;
|
||||
}
|
||||
|
||||
// VarHandle mechanics
|
||||
private static final VarHandle STATE;
|
||||
private static final VarHandle RUNNER;
|
||||
|
@ -74,7 +74,7 @@ public class Basic {
|
||||
check(!cf.isCompletedExceptionally(), "Expected isCompletedExceptionally to return false");
|
||||
check(!cf.isCancelled(), "Expected isCancelled to be false");
|
||||
check(!cf.cancel(true), "Expected cancel to return false");
|
||||
check(cf.toString().contains("[Completed normally]"));
|
||||
check(cf.toString().matches(".*\\[.*Completed normally.*\\]"));
|
||||
check(cf.complete(null) == false, "Expected complete() to fail");
|
||||
check(cf.completeExceptionally(new Throwable()) == false,
|
||||
"Expected completeExceptionally() to fail");
|
||||
@ -106,7 +106,7 @@ public class Basic {
|
||||
check(cf.isCompletedExceptionally(), "Expected isCompletedExceptionally");
|
||||
check(cf.isCancelled() == cancelled, "Expected isCancelled: " + cancelled + ", got:" + cf.isCancelled());
|
||||
check(cf.cancel(true) == cancelled, "Expected cancel: " + cancelled + ", got:" + cf.cancel(true));
|
||||
check(cf.toString().contains("[Completed exceptionally]")); // ## TODO: 'E'xceptionally
|
||||
check(cf.toString().matches(".*\\[.*Completed exceptionally.*\\]")); // ## TODO: 'E'xceptionally
|
||||
check(cf.complete((T)new Object()) == false, "Expected complete() to fail");
|
||||
check(cf.completeExceptionally(new Throwable()) == false,
|
||||
"Expected completeExceptionally() to fail, already completed");
|
||||
|
@ -86,7 +86,7 @@ public class CompletableFutureTest extends JSR166TestCase {
|
||||
void checkIncomplete(CompletableFuture<?> f) {
|
||||
assertFalse(f.isDone());
|
||||
assertFalse(f.isCancelled());
|
||||
assertTrue(f.toString().contains("Not completed"));
|
||||
assertTrue(f.toString().matches(".*\\[.*Not completed.*\\]"));
|
||||
try {
|
||||
assertNull(f.getNow(null));
|
||||
} catch (Throwable fail) { threadUnexpectedException(fail); }
|
||||
@ -109,7 +109,7 @@ public class CompletableFutureTest extends JSR166TestCase {
|
||||
assertTrue(f.isDone());
|
||||
assertFalse(f.isCancelled());
|
||||
assertFalse(f.isCompletedExceptionally());
|
||||
assertTrue(f.toString().contains("[Completed normally]"));
|
||||
assertTrue(f.toString().matches(".*\\[.*Completed normally.*\\]"));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -165,7 +165,7 @@ public class CompletableFutureTest extends JSR166TestCase {
|
||||
assertFalse(f.isCancelled());
|
||||
assertTrue(f.isDone());
|
||||
assertTrue(f.isCompletedExceptionally());
|
||||
assertTrue(f.toString().contains("[Completed exceptionally]"));
|
||||
assertTrue(f.toString().matches(".*\\[.*Completed exceptionally.*\\]"));
|
||||
}
|
||||
|
||||
void checkCompletedWithWrappedCFException(CompletableFuture<?> f) {
|
||||
@ -220,7 +220,7 @@ public class CompletableFutureTest extends JSR166TestCase {
|
||||
assertTrue(f.isDone());
|
||||
assertTrue(f.isCompletedExceptionally());
|
||||
assertTrue(f.isCancelled());
|
||||
assertTrue(f.toString().contains("[Completed exceptionally]"));
|
||||
assertTrue(f.toString().matches(".*\\[.*Completed exceptionally.*\\]"));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -356,23 +356,40 @@ public class CompletableFutureTest extends JSR166TestCase {
|
||||
/**
|
||||
* toString indicates current completion state
|
||||
*/
|
||||
public void testToString() {
|
||||
CompletableFuture<String> f;
|
||||
|
||||
f = new CompletableFuture<String>();
|
||||
assertTrue(f.toString().contains("[Not completed]"));
|
||||
public void testToString_incomplete() {
|
||||
CompletableFuture<String> f = new CompletableFuture<String>();
|
||||
assertTrue(f.toString().matches(".*\\[.*Not completed.*\\]"));
|
||||
if (testImplementationDetails)
|
||||
assertEquals(identityString(f) + "[Not completed]",
|
||||
f.toString());
|
||||
}
|
||||
|
||||
public void testToString_normal() {
|
||||
CompletableFuture<String> f = new CompletableFuture<String>();
|
||||
assertTrue(f.complete("foo"));
|
||||
assertTrue(f.toString().contains("[Completed normally]"));
|
||||
assertTrue(f.toString().matches(".*\\[.*Completed normally.*\\]"));
|
||||
if (testImplementationDetails)
|
||||
assertEquals(identityString(f) + "[Completed normally]",
|
||||
f.toString());
|
||||
}
|
||||
|
||||
f = new CompletableFuture<String>();
|
||||
public void testToString_exception() {
|
||||
CompletableFuture<String> f = new CompletableFuture<String>();
|
||||
assertTrue(f.completeExceptionally(new IndexOutOfBoundsException()));
|
||||
assertTrue(f.toString().contains("[Completed exceptionally]"));
|
||||
assertTrue(f.toString().matches(".*\\[.*Completed exceptionally.*\\]"));
|
||||
if (testImplementationDetails)
|
||||
assertTrue(f.toString().startsWith(
|
||||
identityString(f) + "[Completed exceptionally: "));
|
||||
}
|
||||
|
||||
public void testToString_cancelled() {
|
||||
for (boolean mayInterruptIfRunning : new boolean[] { true, false }) {
|
||||
f = new CompletableFuture<String>();
|
||||
CompletableFuture<String> f = new CompletableFuture<String>();
|
||||
assertTrue(f.cancel(mayInterruptIfRunning));
|
||||
assertTrue(f.toString().contains("[Completed exceptionally]"));
|
||||
assertTrue(f.toString().matches(".*\\[.*Completed exceptionally.*\\]"));
|
||||
if (testImplementationDetails)
|
||||
assertTrue(f.toString().startsWith(
|
||||
identityString(f) + "[Completed exceptionally: "));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -613,4 +613,56 @@ public class ExecutorsTest extends JSR166TestCase {
|
||||
} catch (NullPointerException success) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* callable(runnable, x).toString() contains toString of wrapped task
|
||||
*/
|
||||
public void testCallable_withResult_toString() {
|
||||
if (testImplementationDetails) {
|
||||
Runnable r = () -> {};
|
||||
Callable<String> c = Executors.callable(r, "");
|
||||
assertEquals(
|
||||
identityString(c) + "[Wrapped task = " + r.toString() + "]",
|
||||
c.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* callable(runnable).toString() contains toString of wrapped task
|
||||
*/
|
||||
public void testCallable_toString() {
|
||||
if (testImplementationDetails) {
|
||||
Runnable r = () -> {};
|
||||
Callable<Object> c = Executors.callable(r);
|
||||
assertEquals(
|
||||
identityString(c) + "[Wrapped task = " + r.toString() + "]",
|
||||
c.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* privilegedCallable(callable).toString() contains toString of wrapped task
|
||||
*/
|
||||
public void testPrivilegedCallable_toString() {
|
||||
if (testImplementationDetails) {
|
||||
Callable<String> c = () -> "";
|
||||
Callable<String> priv = Executors.privilegedCallable(c);
|
||||
assertEquals(
|
||||
identityString(priv) + "[Wrapped task = " + c.toString() + "]",
|
||||
priv.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* privilegedCallableUsingCurrentClassLoader(callable).toString()
|
||||
* contains toString of wrapped task
|
||||
*/
|
||||
public void testPrivilegedCallableUsingCurrentClassLoader_toString() {
|
||||
if (testImplementationDetails) {
|
||||
Callable<String> c = () -> "";
|
||||
Callable<String> priv = Executors.privilegedCallableUsingCurrentClassLoader(c);
|
||||
assertEquals(
|
||||
identityString(priv) + "[Wrapped task = " + c.toString() + "]",
|
||||
priv.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
@ -1675,4 +1676,42 @@ public class ForkJoinTaskTest extends JSR166TestCase {
|
||||
testInvokeOnPool(mainPool(), a);
|
||||
}
|
||||
|
||||
/**
|
||||
* adapt(runnable).toString() contains toString of wrapped task
|
||||
*/
|
||||
public void testAdapt_Runnable_toString() {
|
||||
if (testImplementationDetails) {
|
||||
Runnable r = () -> {};
|
||||
ForkJoinTask<?> task = ForkJoinTask.adapt(r);
|
||||
assertEquals(
|
||||
identityString(task) + "[Wrapped task = " + r.toString() + "]",
|
||||
task.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* adapt(runnable, x).toString() contains toString of wrapped task
|
||||
*/
|
||||
public void testAdapt_Runnable_withResult_toString() {
|
||||
if (testImplementationDetails) {
|
||||
Runnable r = () -> {};
|
||||
ForkJoinTask<String> task = ForkJoinTask.adapt(r, "");
|
||||
assertEquals(
|
||||
identityString(task) + "[Wrapped task = " + r.toString() + "]",
|
||||
task.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* adapt(callable).toString() contains toString of wrapped task
|
||||
*/
|
||||
public void testAdapt_Callable_toString() {
|
||||
if (testImplementationDetails) {
|
||||
Callable<String> c = () -> "";
|
||||
ForkJoinTask<String> task = ForkJoinTask.adapt(c);
|
||||
assertEquals(
|
||||
identityString(task) + "[Wrapped task = " + c.toString() + "]",
|
||||
task.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -861,4 +861,45 @@ public class FutureTaskTest extends JSR166TestCase {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* toString indicates current completion state
|
||||
*/
|
||||
public void testToString_incomplete() {
|
||||
FutureTask<String> f = new FutureTask<String>(() -> "");
|
||||
assertTrue(f.toString().matches(".*\\[.*Not completed.*\\]"));
|
||||
if (testImplementationDetails)
|
||||
assertTrue(f.toString().startsWith(
|
||||
identityString(f) + "[Not completed, task ="));
|
||||
}
|
||||
|
||||
public void testToString_normal() {
|
||||
FutureTask<String> f = new FutureTask<String>(() -> "");
|
||||
f.run();
|
||||
assertTrue(f.toString().matches(".*\\[.*Completed normally.*\\]"));
|
||||
if (testImplementationDetails)
|
||||
assertEquals(identityString(f) + "[Completed normally]",
|
||||
f.toString());
|
||||
}
|
||||
|
||||
public void testToString_exception() {
|
||||
FutureTask<String> f = new FutureTask<String>(
|
||||
() -> { throw new ArithmeticException(); });
|
||||
f.run();
|
||||
assertTrue(f.toString().matches(".*\\[.*Completed exceptionally.*\\]"));
|
||||
if (testImplementationDetails)
|
||||
assertTrue(f.toString().startsWith(
|
||||
identityString(f) + "[Completed exceptionally: "));
|
||||
}
|
||||
|
||||
public void testToString_cancelled() {
|
||||
for (boolean mayInterruptIfRunning : new boolean[] { true, false }) {
|
||||
FutureTask<String> f = new FutureTask<String>(() -> "");
|
||||
assertTrue(f.cancel(mayInterruptIfRunning));
|
||||
assertTrue(f.toString().matches(".*\\[.*Cancelled.*\\]"));
|
||||
if (testImplementationDetails)
|
||||
assertEquals(identityString(f) + "[Cancelled]",
|
||||
f.toString());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -571,6 +571,7 @@ public class JSR166TestCase extends TestCase {
|
||||
"DoubleAdderTest",
|
||||
"ForkJoinPool8Test",
|
||||
"ForkJoinTask8Test",
|
||||
"HashMapTest",
|
||||
"LinkedBlockingDeque8Test",
|
||||
"LinkedBlockingQueue8Test",
|
||||
"LongAccumulatorTest",
|
||||
@ -1940,6 +1941,18 @@ public class JSR166TestCase extends TestCase {
|
||||
Collections.shuffle(Arrays.asList(array), ThreadLocalRandom.current());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the same String as would be returned by {@link
|
||||
* Object#toString}, whether or not the given object's class
|
||||
* overrides toString().
|
||||
*
|
||||
* @see System#identityHashCode
|
||||
*/
|
||||
static String identityString(Object x) {
|
||||
return x.getClass().getName()
|
||||
+ "@" + Integer.toHexString(System.identityHashCode(x));
|
||||
}
|
||||
|
||||
// --- Shared assertions for Executor tests ---
|
||||
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user