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
|
* 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 {
|
public final class NotSerializableExceptionWrapper extends ElasticsearchException {
|
||||||
|
|
||||||
|
@ -34,6 +37,10 @@ public final class NotSerializableExceptionWrapper extends ElasticsearchExceptio
|
||||||
public NotSerializableExceptionWrapper(Throwable other) {
|
public NotSerializableExceptionWrapper(Throwable other) {
|
||||||
super(other.getMessage(), other.getCause());
|
super(other.getMessage(), other.getCause());
|
||||||
this.name = ElasticsearchException.getExceptionName(other);
|
this.name = ElasticsearchException.getExceptionName(other);
|
||||||
|
setStackTrace(other.getStackTrace());
|
||||||
|
for (Throwable otherSuppressed : other.getSuppressed()) {
|
||||||
|
addSuppressed(otherSuppressed);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public NotSerializableExceptionWrapper(StreamInput in) throws IOException {
|
public NotSerializableExceptionWrapper(StreamInput in) throws IOException {
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
|
|
||||||
package org.elasticsearch.common.io.stream;
|
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.CorruptIndexException;
|
||||||
import org.apache.lucene.index.IndexFormatTooNewException;
|
import org.apache.lucene.index.IndexFormatTooNewException;
|
||||||
import org.apache.lucene.index.IndexFormatTooOldException;
|
import org.apache.lucene.index.IndexFormatTooOldException;
|
||||||
|
|
|
@ -39,6 +39,8 @@ import org.elasticsearch.indices.IndexMissingException;
|
||||||
import org.elasticsearch.rest.RestStatus;
|
import org.elasticsearch.rest.RestStatus;
|
||||||
import org.elasticsearch.search.SearchShardTarget;
|
import org.elasticsearch.search.SearchShardTarget;
|
||||||
import org.elasticsearch.test.ElasticsearchTestCase;
|
import org.elasticsearch.test.ElasticsearchTestCase;
|
||||||
|
import org.elasticsearch.test.VersionUtils;
|
||||||
|
import org.elasticsearch.test.hamcrest.ElasticsearchAssertions;
|
||||||
import org.elasticsearch.transport.RemoteTransportException;
|
import org.elasticsearch.transport.RemoteTransportException;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
@ -293,9 +295,10 @@ public class ElasticsearchExceptionTests extends ElasticsearchTestCase {
|
||||||
assertEquals(e.getCause().getClass(), e.getCause().getClass());
|
assertEquals(e.getCause().getClass(), e.getCause().getClass());
|
||||||
assertArrayEquals(e.getStackTrace(), ex.getStackTrace());
|
assertArrayEquals(e.getStackTrace(), ex.getStackTrace());
|
||||||
assertTrue(e.getStackTrace().length > 1);
|
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;
|
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.ImmutableSet;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
|
import org.codehaus.groovy.runtime.typehandling.GroovyCastException;
|
||||||
import org.elasticsearch.action.FailedNodeException;
|
import org.elasticsearch.action.FailedNodeException;
|
||||||
import org.elasticsearch.action.RoutingMissingException;
|
import org.elasticsearch.action.RoutingMissingException;
|
||||||
import org.elasticsearch.action.TimestampParsingException;
|
import org.elasticsearch.action.TimestampParsingException;
|
||||||
import org.elasticsearch.action.search.SearchPhaseExecutionException;
|
import org.elasticsearch.action.search.SearchPhaseExecutionException;
|
||||||
import org.elasticsearch.action.search.ShardSearchFailure;
|
import org.elasticsearch.action.search.ShardSearchFailure;
|
||||||
import org.elasticsearch.cluster.block.ClusterBlock;
|
|
||||||
import org.elasticsearch.cluster.block.ClusterBlockException;
|
import org.elasticsearch.cluster.block.ClusterBlockException;
|
||||||
import org.elasticsearch.cluster.metadata.SnapshotId;
|
import org.elasticsearch.cluster.metadata.SnapshotId;
|
||||||
import org.elasticsearch.cluster.node.DiscoveryNode;
|
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.breaker.CircuitBreakingException;
|
||||||
import org.elasticsearch.common.io.PathUtils;
|
import org.elasticsearch.common.io.PathUtils;
|
||||||
import org.elasticsearch.common.io.stream.*;
|
import org.elasticsearch.common.io.stream.*;
|
||||||
import org.elasticsearch.common.transport.InetSocketTransportAddress;
|
|
||||||
import org.elasticsearch.common.transport.LocalTransportAddress;
|
import org.elasticsearch.common.transport.LocalTransportAddress;
|
||||||
import org.elasticsearch.common.unit.ByteSizeValue;
|
import org.elasticsearch.common.unit.ByteSizeValue;
|
||||||
import org.elasticsearch.common.xcontent.*;
|
import org.elasticsearch.common.xcontent.*;
|
||||||
|
@ -63,6 +64,8 @@ import org.elasticsearch.search.warmer.IndexWarmerMissingException;
|
||||||
import org.elasticsearch.snapshots.SnapshotException;
|
import org.elasticsearch.snapshots.SnapshotException;
|
||||||
import org.elasticsearch.test.ElasticsearchTestCase;
|
import org.elasticsearch.test.ElasticsearchTestCase;
|
||||||
import org.elasticsearch.test.TestSearchContext;
|
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.ActionNotFoundTransportException;
|
||||||
import org.elasticsearch.transport.ActionTransportException;
|
import org.elasticsearch.transport.ActionTransportException;
|
||||||
import org.elasticsearch.transport.ConnectTransportException;
|
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();
|
BytesStreamOutput out = new BytesStreamOutput();
|
||||||
out.writeThrowable(exception);
|
out.writeThrowable(exception);
|
||||||
StreamInput in = StreamInput.wrap(out.bytes());
|
StreamInput in = StreamInput.wrap(out.bytes());
|
||||||
|
@ -552,5 +556,26 @@ public class ExceptionSerializationTests extends ElasticsearchTestCase {
|
||||||
assertEquals("{\"type\":\"null_pointer_exception\",\"reason\":null}", toXContent(ex));
|
assertEquals("{\"type\":\"null_pointer_exception\",\"reason\":null}", toXContent(ex));
|
||||||
ex = serialize(new NotSerializableExceptionWrapper(new IllegalArgumentException("nono!")));
|
ex = serialize(new NotSerializableExceptionWrapper(new IllegalArgumentException("nono!")));
|
||||||
assertEquals("{\"type\":\"illegal_argument_exception\",\"reason\":\"nono!\"}", toXContent(ex));
|
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.bytes.BytesReference;
|
||||||
import org.elasticsearch.common.io.stream.BytesStreamOutput;
|
import org.elasticsearch.common.io.stream.BytesStreamOutput;
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.common.io.stream.Streamable;
|
import org.elasticsearch.common.io.stream.Streamable;
|
||||||
import org.elasticsearch.rest.RestStatus;
|
import org.elasticsearch.rest.RestStatus;
|
||||||
import org.elasticsearch.search.SearchHit;
|
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,
|
private static Streamable tryCreateNewInstance(Streamable streamable) throws NoSuchMethodException, InstantiationException,
|
||||||
IllegalAccessException, InvocationTargetException {
|
IllegalAccessException, InvocationTargetException {
|
||||||
try {
|
try {
|
||||||
|
|
Loading…
Reference in New Issue