summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorElliott Hughes <enh@google.com>2013-05-14 17:40:17 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2013-05-14 17:40:18 +0000
commitc86b6a1addc08cfc3a3a6587ca46ad1be363d408 (patch)
treed82da049833bec9396bb6d66234144bcf03e552c
parent0230da3614fd012851bd42898dcd1f4db1c57223 (diff)
parentc2f2aaaae219c69d50eee6549d507c91e9a08519 (diff)
downloadlibcore-c86b6a1addc08cfc3a3a6587ca46ad1be363d408.zip
libcore-c86b6a1addc08cfc3a3a6587ca46ad1be363d408.tar.gz
libcore-c86b6a1addc08cfc3a3a6587ca46ad1be363d408.tar.bz2
Merge "Fix java.lang.Throwable's protected constructor."
-rw-r--r--luni/src/main/java/java/lang/Throwable.java85
-rw-r--r--luni/src/test/java/libcore/java/lang/ThrowableTest.java35
2 files changed, 76 insertions, 44 deletions
diff --git a/luni/src/main/java/java/lang/Throwable.java b/luni/src/main/java/java/lang/Throwable.java
index 6bb8fa1..f5005c0 100644
--- a/luni/src/main/java/java/lang/Throwable.java
+++ b/luni/src/main/java/java/lang/Throwable.java
@@ -81,63 +81,66 @@ public class Throwable implements java.io.Serializable {
* Constructs a new {@code Throwable} that includes the current stack trace.
*/
public Throwable() {
+ this.stackTrace = EmptyArray.STACK_TRACE_ELEMENT;
fillInStackTrace();
}
/**
* Constructs a new {@code Throwable} with the current stack trace and the
- * specified detail message.
- *
- * @param detailMessage
- * the detail message for this {@code Throwable}.
+ * given detail message.
*/
public Throwable(String detailMessage) {
- this();
this.detailMessage = detailMessage;
+ this.stackTrace = EmptyArray.STACK_TRACE_ELEMENT;
+ fillInStackTrace();
}
/**
* Constructs a new {@code Throwable} with the current stack trace, the
- * specified detail message and the specified cause.
- *
- * @param detailMessage
- * the detail message for this {@code Throwable}.
- * @param throwable
- * the cause of this {@code Throwable}.
+ * given detail message and cause.
*/
- public Throwable(String detailMessage, Throwable throwable) {
- this();
+ public Throwable(String detailMessage, Throwable cause) {
this.detailMessage = detailMessage;
- cause = throwable;
+ this.cause = cause;
+ this.stackTrace = EmptyArray.STACK_TRACE_ELEMENT;
+ fillInStackTrace();
}
/**
* Constructs a new {@code Throwable} with the current stack trace and the
- * specified cause.
- *
- * @param throwable
- * the cause of this {@code Throwable}.
+ * given cause.
*/
- public Throwable(Throwable throwable) {
- this();
- this.detailMessage = throwable == null ? null : throwable.toString();
- cause = throwable;
+ public Throwable(Throwable cause) {
+ this.detailMessage = cause == null ? null : cause.toString();
+ this.cause = cause;
+ this.stackTrace = EmptyArray.STACK_TRACE_ELEMENT;
+ fillInStackTrace();
}
/**
* Constructs a new {@code Throwable} with the current stack trace, the
* specified detail message and the specified cause.
*
- * @param enableSuppression if false, throwables passed to {@link
- * #addSuppressed(Throwable)} will be silently discarded.
+ * @param enableSuppression if false, {@link #addSuppressed(Throwable)} will be a no-op.
+ * @param writableStackTrace if false, {@link #fillInStackTrace} will not be called,
+ * this object's {@code stackTrace} will be null,
+ * calls to {@link #fillInStackTrace} and {@link #setStackTrace} will be no-ops,
+ * and {@link #getStackTrace} will return a zero-length array.
* @since 1.7
* @hide 1.7
*/
- protected Throwable(String detailMessage, Throwable cause, boolean enableSuppression) {
- this(detailMessage, cause);
+ protected Throwable(String detailMessage, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
+ this.detailMessage = detailMessage;
+ this.cause = cause;
if (!enableSuppression) {
this.suppressedExceptions = null;
}
+ if (writableStackTrace) {
+ this.stackTrace = EmptyArray.STACK_TRACE_ELEMENT;
+ fillInStackTrace();
+ } else {
+ this.stackTrace = null;
+ }
}
/**
@@ -157,31 +160,30 @@ public class Throwable implements java.io.Serializable {
* @return this {@code Throwable} instance.
*/
public Throwable fillInStackTrace() {
- // Fill in the intermediate representation
+ if (stackTrace == null) {
+ return this; // writableStackTrace was false.
+ }
+ // Fill in the intermediate representation.
stackState = nativeFillInStackTrace();
- // Mark the full representation as empty
- stackTrace = null;
+ // Mark the full representation as in need of update.
+ stackTrace = EmptyArray.STACK_TRACE_ELEMENT;
return this;
}
/**
- * Returns the extra information message which was provided when this
+ * Returns the detail message which was provided when this
* {@code Throwable} was created. Returns {@code null} if no message was
* provided at creation time.
- *
- * @return this {@code Throwable}'s detail message.
*/
public String getMessage() {
return detailMessage;
}
/**
- * Returns the extra information message which was provided when this
+ * Returns the detail message which was provided when this
* {@code Throwable} was created. Returns {@code null} if no message was
* provided at creation time. Subclasses may override this method to return
* localized text for the message. Android returns the regular detail message.
- *
- * @return this {@code Throwable}'s localized detail message.
*/
public String getLocalizedMessage() {
return getMessage();
@@ -218,6 +220,9 @@ public class Throwable implements java.io.Serializable {
* @see #printStackTrace()
*/
public void setStackTrace(StackTraceElement[] trace) {
+ if (stackTrace == null) {
+ return; // writableStackTrace was false.
+ }
StackTraceElement[] newTrace = trace.clone();
for (int i = 0; i < newTrace.length; i++) {
if (newTrace[i] == null) {
@@ -263,15 +268,17 @@ public class Throwable implements java.io.Serializable {
/**
* Returns an array of StackTraceElement. Each StackTraceElement
* represents a entry on the stack.
- *
- * @return an array of StackTraceElement representing the stack
*/
private StackTraceElement[] getInternalStackTrace() {
- if (stackTrace == null) {
+ if (stackTrace == EmptyArray.STACK_TRACE_ELEMENT) {
stackTrace = nativeGetStackTrace(stackState);
stackState = null; // Clean up intermediate representation
+ return stackTrace;
+ } else if (stackTrace == null) {
+ return EmptyArray.STACK_TRACE_ELEMENT;
+ } else {
+ return stackTrace;
}
- return stackTrace;
}
/**
diff --git a/luni/src/test/java/libcore/java/lang/ThrowableTest.java b/luni/src/test/java/libcore/java/lang/ThrowableTest.java
index 1906784..7c8ae66 100644
--- a/luni/src/test/java/libcore/java/lang/ThrowableTest.java
+++ b/luni/src/test/java/libcore/java/lang/ThrowableTest.java
@@ -38,10 +38,35 @@ public class ThrowableTest extends TestCase {
}
}
+ public void testNonWritableStackTrace() {
+ try {
+ // The 4th argument, writableStackTrace, is false...
+ throw new SuppressionsThrowable("hi", null, true, false);
+ } catch (Throwable th) {
+ assertEquals("hi", th.getMessage());
+
+ // We see an empty stack trace.
+ assertEquals(0, th.getStackTrace().length);
+
+ // setStackTrace is a no-op.
+ th.setStackTrace(new StackTraceElement[] { new StackTraceElement("c", "m", "f", -2) });
+ assertEquals(0, th.getStackTrace().length);
+
+ // fillInStackTrace is a no-op.
+ th.fillInStackTrace();
+ assertEquals(0, th.getStackTrace().length);
+
+ // It's still possible to print an exception with writableStackTrace == false.
+ th.printStackTrace(new PrintWriter(new StringWriter()));
+ }
+ }
+
private static class SuppressionsThrowable extends Throwable {
+ private static final long serialVersionUID = 202649043897209143L;
+
public SuppressionsThrowable(String detailMessage, Throwable throwable,
- boolean enableSuppression) {
- super(detailMessage, throwable, enableSuppression);
+ boolean enableSuppression, boolean writableStackTrace) {
+ super(detailMessage, throwable, enableSuppression, writableStackTrace);
}
}
@@ -78,7 +103,7 @@ public class ThrowableTest extends TestCase {
}
public void testAddSuppressedWithSuppressionDisabled() {
- Throwable throwable = new SuppressionsThrowable("foo", null, false);
+ Throwable throwable = new SuppressionsThrowable("foo", null, false, true);
assertSuppressed(throwable);
throwable.addSuppressed(new Throwable());
assertSuppressed(throwable);
@@ -246,7 +271,7 @@ public class ThrowableTest extends TestCase {
+ "4696f6e737400104c6a6176612f7574696c2f4c6973743b787070740003666f6f7572001e5b4c6a6"
+ "176612e6c616e672e537461636b5472616365456c656d656e743b02462a3c3cfd223902000078700"
+ "00000007078";
- Throwable throwable = new SuppressionsThrowable("foo", null, false);
+ Throwable throwable = new SuppressionsThrowable("foo", null, false, true);
throwable.setStackTrace(new StackTraceElement[0]);
new SerializationTester<Throwable>(throwable, s) {
@Override protected boolean equals(Throwable a, Throwable b) {
@@ -275,7 +300,7 @@ public class ThrowableTest extends TestCase {
+ "0cb5ef71e0200014c0001637400164c6a6176612f7574696c2f436f6c6c656374696f6e3b7870737"
+ "200136a6176612e7574696c2e41727261794c6973747881d21d99c7619d03000149000473697a657"
+ "870000000007704000000007871007e000f78";
- Throwable throwable = new SuppressionsThrowable("foo", null, true);
+ Throwable throwable = new SuppressionsThrowable("foo", null, true, true);
throwable.setStackTrace(new StackTraceElement[0]);
new SerializationTester<Throwable>(throwable, s) {
@Override protected boolean equals(Throwable a, Throwable b) {