Carry on stacktrace and suppressed exceptions if exception is not serializable
This commit is contained in:
parent
6ee9a3d5f2
commit
0ac8c1bc55
|
@ -25,7 +25,10 @@ import java.io.IOException;
|
|||
|
||||
/**
|
||||
* This exception can be used to wrap a given, not serializable exception
|
||||
* to serialize via {@link StreamOutput#writeThrowable(Throwable)}
|
||||
* to serialize via {@link StreamOutput#writeThrowable(Throwable)}.
|
||||
* This class will perserve the stacktrace as well as the suppressed exceptions of
|
||||
* the throwable it was created with instead of it's own. The stacktrace has no indication
|
||||
* of where this exception was created.
|
||||
*/
|
||||
public final class NotSerializableExceptionWrapper extends ElasticsearchException {
|
||||
|
||||
|
@ -34,6 +37,10 @@ public final class NotSerializableExceptionWrapper extends ElasticsearchExceptio
|
|||
public NotSerializableExceptionWrapper(Throwable other) {
|
||||
super(other.getMessage(), other.getCause());
|
||||
this.name = ElasticsearchException.getExceptionName(other);
|
||||
setStackTrace(other.getStackTrace());
|
||||
for (Throwable otherSuppressed : other.getSuppressed()) {
|
||||
addSuppressed(otherSuppressed);
|
||||
}
|
||||
}
|
||||
|
||||
public NotSerializableExceptionWrapper(StreamInput in) throws IOException {
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
|
||||
package org.elasticsearch.common.io.stream;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonLocation;
|
||||
import com.fasterxml.jackson.core.JsonParseException;
|
||||
import org.apache.lucene.index.CorruptIndexException;
|
||||
import org.apache.lucene.index.IndexFormatTooNewException;
|
||||
import org.apache.lucene.index.IndexFormatTooOldException;
|
||||
|
|
|
@ -39,6 +39,8 @@ import org.elasticsearch.indices.IndexMissingException;
|
|||
import org.elasticsearch.rest.RestStatus;
|
||||
import org.elasticsearch.search.SearchShardTarget;
|
||||
import org.elasticsearch.test.ElasticsearchTestCase;
|
||||
import org.elasticsearch.test.VersionUtils;
|
||||
import org.elasticsearch.test.hamcrest.ElasticsearchAssertions;
|
||||
import org.elasticsearch.transport.RemoteTransportException;
|
||||
import org.junit.Test;
|
||||
|
||||
|
@ -293,9 +295,10 @@ public class ElasticsearchExceptionTests extends ElasticsearchTestCase {
|
|||
assertEquals(e.getCause().getClass(), e.getCause().getClass());
|
||||
assertArrayEquals(e.getStackTrace(), ex.getStackTrace());
|
||||
assertTrue(e.getStackTrace().length > 1);
|
||||
ElasticsearchAssertions.assertVersionSerializable(VersionUtils.randomVersion(getRandom()), t);
|
||||
ElasticsearchAssertions.assertVersionSerializable(VersionUtils.randomVersion(getRandom()), ex);
|
||||
ElasticsearchAssertions.assertVersionSerializable(VersionUtils.randomVersion(getRandom()), e);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -18,14 +18,16 @@
|
|||
*/
|
||||
package org.elasticsearch;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonLocation;
|
||||
import com.fasterxml.jackson.core.JsonParseException;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Sets;
|
||||
import org.codehaus.groovy.runtime.typehandling.GroovyCastException;
|
||||
import org.elasticsearch.action.FailedNodeException;
|
||||
import org.elasticsearch.action.RoutingMissingException;
|
||||
import org.elasticsearch.action.TimestampParsingException;
|
||||
import org.elasticsearch.action.search.SearchPhaseExecutionException;
|
||||
import org.elasticsearch.action.search.ShardSearchFailure;
|
||||
import org.elasticsearch.cluster.block.ClusterBlock;
|
||||
import org.elasticsearch.cluster.block.ClusterBlockException;
|
||||
import org.elasticsearch.cluster.metadata.SnapshotId;
|
||||
import org.elasticsearch.cluster.node.DiscoveryNode;
|
||||
|
@ -33,7 +35,6 @@ import org.elasticsearch.cluster.routing.*;
|
|||
import org.elasticsearch.common.breaker.CircuitBreakingException;
|
||||
import org.elasticsearch.common.io.PathUtils;
|
||||
import org.elasticsearch.common.io.stream.*;
|
||||
import org.elasticsearch.common.transport.InetSocketTransportAddress;
|
||||
import org.elasticsearch.common.transport.LocalTransportAddress;
|
||||
import org.elasticsearch.common.unit.ByteSizeValue;
|
||||
import org.elasticsearch.common.xcontent.*;
|
||||
|
@ -63,6 +64,8 @@ import org.elasticsearch.search.warmer.IndexWarmerMissingException;
|
|||
import org.elasticsearch.snapshots.SnapshotException;
|
||||
import org.elasticsearch.test.ElasticsearchTestCase;
|
||||
import org.elasticsearch.test.TestSearchContext;
|
||||
import org.elasticsearch.test.VersionUtils;
|
||||
import org.elasticsearch.test.hamcrest.ElasticsearchAssertions;
|
||||
import org.elasticsearch.transport.ActionNotFoundTransportException;
|
||||
import org.elasticsearch.transport.ActionTransportException;
|
||||
import org.elasticsearch.transport.ConnectTransportException;
|
||||
|
@ -179,7 +182,8 @@ public class ExceptionSerializationTests extends ElasticsearchTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
private <T extends ElasticsearchException> T serialize(T exception) throws IOException {
|
||||
private <T extends Throwable> T serialize(T exception) throws IOException {
|
||||
ElasticsearchAssertions.assertVersionSerializable(VersionUtils.randomVersion(random()), exception);
|
||||
BytesStreamOutput out = new BytesStreamOutput();
|
||||
out.writeThrowable(exception);
|
||||
StreamInput in = StreamInput.wrap(out.bytes());
|
||||
|
@ -552,5 +556,26 @@ public class ExceptionSerializationTests extends ElasticsearchTestCase {
|
|||
assertEquals("{\"type\":\"null_pointer_exception\",\"reason\":null}", toXContent(ex));
|
||||
ex = serialize(new NotSerializableExceptionWrapper(new IllegalArgumentException("nono!")));
|
||||
assertEquals("{\"type\":\"illegal_argument_exception\",\"reason\":\"nono!\"}", toXContent(ex));
|
||||
|
||||
Throwable[] unknowns = new Throwable[] {
|
||||
new JsonParseException("foobar", new JsonLocation(new Object(), 1,2,3,4)),
|
||||
new GroovyCastException("boom boom boom"),
|
||||
new IOException("booom")
|
||||
};
|
||||
for (Throwable t : unknowns) {
|
||||
if (randomBoolean()) {
|
||||
t.addSuppressed(new IOException("suppressed"));
|
||||
t.addSuppressed(new NullPointerException());
|
||||
}
|
||||
Throwable deserialized = serialize(t);
|
||||
assertTrue(deserialized instanceof NotSerializableExceptionWrapper);
|
||||
assertArrayEquals(t.getStackTrace(), deserialized.getStackTrace());
|
||||
assertEquals(t.getSuppressed().length, deserialized.getSuppressed().length);
|
||||
if (t.getSuppressed().length > 0) {
|
||||
assertTrue(deserialized.getSuppressed()[0] instanceof NotSerializableExceptionWrapper);
|
||||
assertArrayEquals(t.getSuppressed()[0].getStackTrace(), deserialized.getSuppressed()[0].getStackTrace());
|
||||
assertTrue(deserialized.getSuppressed()[1] instanceof NullPointerException);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,6 +60,7 @@ import org.elasticsearch.common.Nullable;
|
|||
import org.elasticsearch.common.bytes.BytesReference;
|
||||
import org.elasticsearch.common.io.stream.BytesStreamOutput;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.common.io.stream.Streamable;
|
||||
import org.elasticsearch.rest.RestStatus;
|
||||
import org.elasticsearch.search.SearchHit;
|
||||
|
@ -650,6 +651,32 @@ public class ElasticsearchAssertions {
|
|||
|
||||
}
|
||||
|
||||
public static void assertVersionSerializable(Version version, final Throwable t) {
|
||||
ElasticsearchAssertions.assertVersionSerializable(version, new ThrowableWrapper(t));
|
||||
}
|
||||
|
||||
private static final class ThrowableWrapper implements Streamable {
|
||||
Throwable throwable;
|
||||
public ThrowableWrapper(Throwable t) {
|
||||
throwable = t;
|
||||
}
|
||||
|
||||
public ThrowableWrapper() {
|
||||
throwable = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFrom(StreamInput in) throws IOException {
|
||||
throwable = in.readThrowable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
out.writeThrowable(throwable);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static Streamable tryCreateNewInstance(Streamable streamable) throws NoSuchMethodException, InstantiationException,
|
||||
IllegalAccessException, InvocationTargetException {
|
||||
try {
|
||||
|
|
Loading…
Reference in New Issue