提交 4364dc20 编写于 作者: D darcy

7005628: Clarify NPE behavior of Throwable.addSuppressed(null)

Reviewed-by: dholmes, mchung, jjb
上级 c1da6382
/*
* Copyright (c) 1994, 2008, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -30,15 +30,18 @@ package java.lang;
* example, an integer "divide by zero" throws an
* instance of this class.
*
* {@code ArithmeticException} objects may be constructed by the
* virtual machine as if {@linkplain Throwable#Throwable(String,
* Throwable, boolean) suppression were disabled}.
*
* @author unascribed
* @since JDK1.0
*/
public
class ArithmeticException extends RuntimeException {
public class ArithmeticException extends RuntimeException {
private static final long serialVersionUID = 2256477558314496007L;
/**
* Constructs an <code>ArithmeticException</code> with no detail
* Constructs an {@code ArithmeticException} with no detail
* message.
*/
public ArithmeticException() {
......@@ -46,7 +49,7 @@ class ArithmeticException extends RuntimeException {
}
/**
* Constructs an <code>ArithmeticException</code> with the specified
* Constructs an {@code ArithmeticException} with the specified
* detail message.
*
* @param s the detail message.
......
/*
* Copyright (c) 1994, 2008, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -26,20 +26,24 @@
package java.lang;
/**
* Thrown when an application attempts to use <code>null</code> in a
* Thrown when an application attempts to use {@code null} in a
* case where an object is required. These include:
* <ul>
* <li>Calling the instance method of a <code>null</code> object.
* <li>Accessing or modifying the field of a <code>null</code> object.
* <li>Taking the length of <code>null</code> as if it were an array.
* <li>Accessing or modifying the slots of <code>null</code> as if it
* <li>Calling the instance method of a {@code null} object.
* <li>Accessing or modifying the field of a {@code null} object.
* <li>Taking the length of {@code null} as if it were an array.
* <li>Accessing or modifying the slots of {@code null} as if it
* were an array.
* <li>Throwing <code>null</code> as if it were a <code>Throwable</code>
* <li>Throwing {@code null} as if it were a {@code Throwable}
* value.
* </ul>
* <p>
* Applications should throw instances of this class to indicate
* other illegal uses of the <code>null</code> object.
* other illegal uses of the {@code null} object.
*
* {@code NullPointerException} objects may be constructed by the
* virtual machine as if {@linkplain Throwable#Throwable(String,
* Throwable, boolean) suppression were disabled}.
*
* @author unascribed
* @since JDK1.0
......@@ -49,14 +53,14 @@ class NullPointerException extends RuntimeException {
private static final long serialVersionUID = 5162710183389028792L;
/**
* Constructs a <code>NullPointerException</code> with no detail message.
* Constructs a {@code NullPointerException} with no detail message.
*/
public NullPointerException() {
super();
}
/**
* Constructs a <code>NullPointerException</code> with the specified
* Constructs a {@code NullPointerException} with the specified
* detail message.
*
* @param s the detail message.
......
/*
* Copyright (c) 1994, 2008, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -30,22 +30,25 @@ package java.lang;
* because it is out of memory, and no more memory could be made
* available by the garbage collector.
*
* {@code OutOfMemoryError} objects may be constructed by the virtual
* machine as if {@linkplain Throwable#Throwable(String, Throwable,
* boolean) suppression were disabled}.
*
* @author unascribed
* @since JDK1.0
*/
public
class OutOfMemoryError extends VirtualMachineError {
public class OutOfMemoryError extends VirtualMachineError {
private static final long serialVersionUID = 8228564086184010517L;
/**
* Constructs an <code>OutOfMemoryError</code> with no detail message.
* Constructs an {@code OutOfMemoryError} with no detail message.
*/
public OutOfMemoryError() {
super();
}
/**
* Constructs an <code>OutOfMemoryError</code> with the specified
* Constructs an {@code OutOfMemoryError} with the specified
* detail message.
*
* @param s the detail message.
......
......@@ -52,7 +52,7 @@ import java.util.*;
* throwable can {@linkplain Throwable#addSuppressed suppress} other
* throwables from being propagated. Finally, the throwable can also
* contain a <i>cause</i>: another throwable that caused this
* throwable to get thrown. The recording of this causal information
* throwable to be constructed. The recording of this causal information
* is referred to as the <i>chained exception</i> facility, as the
* cause can, itself, have a cause, and so on, leading to a "chain" of
* exceptions, each caused by another.
......@@ -282,6 +282,41 @@ public class Throwable implements Serializable {
this.cause = cause;
}
/**
* Constructs a new throwable with the specified detail message,
* cause, and {@linkplain #addSuppressed suppression} enabled or
* disabled. If suppression is disabled, {@link #getSuppressed}
* for this object will return a zero-length array and calls to
* {@link #addSuppressed} that would otherwise append an exception
* to the suppressed list will have no effect.
*
* <p>Note that the other constructors of {@code Throwable} treat
* suppression as being enabled. Subclasses of {@code Throwable}
* should document any conditions under which suppression is
* disabled. Disabling of suppression should only occur in
* exceptional circumstances where special requirements exist,
* such as a virtual machine reusing exception objects under
* low-memory situations.
*
* @param message the detail message.
* @param cause the cause. (A {@code null} value is permitted,
* and indicates that the cause is nonexistent or unknown.)
* @param enableSuppression whether or not suppression is enabled or disabled
*
* @see OutOfMemoryError
* @see NullPointerException
* @see ArithmeticException
* @since 1.7
*/
protected Throwable(String message, Throwable cause,
boolean enableSuppression) {
fillInStackTrace();
detailMessage = message;
this.cause = cause;
if (!enableSuppression)
suppressedExceptions = null;
}
/**
* Returns the detail message string of this throwable.
*
......@@ -830,13 +865,10 @@ public class Throwable implements Serializable {
* typically called (automatically and implicitly) by the {@code
* try}-with-resources statement.
*
* If the first exception to be suppressed is {@code null}, that
* indicates suppressed exception information will <em>not</em> be
* recorded for this exception. Subsequent calls to this method
* will not record any suppressed exceptions. Otherwise,
* attempting to suppress {@code null} after an exception has
* already been successfully suppressed results in a {@code
* NullPointerException}.
* <p>The suppression behavior is enabled <em>unless</em> disabled
* {@linkplain #Throwable(String, Throwable, boolean) via a
* constructor}. When suppression is disabled, this method does
* nothing other than to validate its argument.
*
* <p>Note that when one exception {@linkplain
* #initCause(Throwable) causes} another exception, the first
......@@ -874,33 +906,23 @@ public class Throwable implements Serializable {
* suppressed exceptions
* @throws IllegalArgumentException if {@code exception} is this
* throwable; a throwable cannot suppress itself.
* @throws NullPointerException if {@code exception} is null and
* an exception has already been suppressed by this exception
* @throws NullPointerException if {@code exception} is {@code null}
* @since 1.7
*/
public final synchronized void addSuppressed(Throwable exception) {
if (exception == this)
throw new IllegalArgumentException(SELF_SUPPRESSION_MESSAGE);
if (exception == null) {
if (suppressedExceptions == SUPPRESSED_SENTINEL) {
suppressedExceptions = null; // No suppression information recorded
return;
} else
throw new NullPointerException(NULL_CAUSE_MESSAGE);
} else {
assert exception != null && exception != this;
if (exception == null)
throw new NullPointerException(NULL_CAUSE_MESSAGE);
if (suppressedExceptions == null) // Suppressed exceptions not recorded
return;
if (suppressedExceptions == null) // Suppressed exceptions not recorded
return;
if (suppressedExceptions == SUPPRESSED_SENTINEL)
suppressedExceptions = new ArrayList<>(1);
if (suppressedExceptions == SUPPRESSED_SENTINEL)
suppressedExceptions = new ArrayList<>(1);
assert suppressedExceptions != SUPPRESSED_SENTINEL;
suppressedExceptions.add(exception);
}
suppressedExceptions.add(exception);
}
private static final Throwable[] EMPTY_THROWABLE_ARRAY = new Throwable[0];
......@@ -910,7 +932,9 @@ public class Throwable implements Serializable {
* suppressed, typically by the {@code try}-with-resources
* statement, in order to deliver this exception.
*
* If no exceptions were suppressed, an empty array is returned.
* If no exceptions were suppressed or {@linkplain
* Throwable(String, Throwable, boolean) suppression is disabled},
* an empty array is returned.
*
* @return an array containing all of the exceptions that were
* suppressed to deliver this exception.
......
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -26,7 +26,7 @@ import java.util.*;
/*
* @test
* @bug 6911258 6962571 6963622 6991528
* @bug 6911258 6962571 6963622 6991528 7005628
* @summary Basic tests of suppressed exceptions
* @author Joseph D. Darcy
*/
......@@ -50,14 +50,6 @@ public class SuppressedExceptions {
} catch (IllegalArgumentException iae) {
; // Expected
}
throwable.addSuppressed(null); // Immutable suppression list
try {
throwable.addSuppressed(throwable);
throw new RuntimeException("IllegalArgumentException for self-suppresion not thrown.");
} catch (IllegalArgumentException iae) {
; // Expected
}
}
private static void basicSupressionTest() {
......@@ -153,19 +145,19 @@ public class SuppressedExceptions {
(byte)0x02, (byte)0x00, (byte)0x00, (byte)0x78, (byte)0x70,
};
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bais);
Object o = ois.readObject();
Throwable throwable = (Throwable) o;
try(ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bais)) {
Object o = ois.readObject();
Throwable throwable = (Throwable) o;
System.err.println("TESTING SERIALIZED EXCEPTION");
System.err.println("TESTING SERIALIZED EXCEPTION");
Throwable[] t0 = throwable.getSuppressed();
if (t0.length != 0) { // Will fail if t0 is null.
throw new RuntimeException(message);
Throwable[] t0 = throwable.getSuppressed();
if (t0.length != 0) { // Will fail if t0 is null.
throw new RuntimeException(message);
}
throwable.printStackTrace();
}
throwable.printStackTrace();
}
private static void selfReference() {
......@@ -183,8 +175,7 @@ public class SuppressedExceptions {
}
private static void noModification() {
Throwable t = new Throwable();
t.addSuppressed(null);
Throwable t = new NoSuppression(false);
Throwable[] t0 = t.getSuppressed();
if (t0.length != 0)
......@@ -196,5 +187,24 @@ public class SuppressedExceptions {
t0 = t.getSuppressed();
if (t0.length != 0)
throw new RuntimeException("Bad nonzero length of suppressed exceptions.");
Throwable suppressed = new ArithmeticException();
t = new NoSuppression(true); // Suppression enabled
// Make sure addSuppressed(null) throws an NPE
try {
t.addSuppressed(null);
} catch(NullPointerException e) {
; // Expected
}
t.addSuppressed(suppressed);
t0 = t.getSuppressed();
if (t0.length != 1 || t0[0] != suppressed)
throw new RuntimeException("Expected suppression did not occur.");
}
private static class NoSuppression extends Throwable {
public NoSuppression(boolean enableSuppression) {
super("The medium.", null, enableSuppression);
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册