
org.wildfly.clustering.marshalling.protostream.ExceptionMarshaller Maven / Gradle / Ivy
/*
* Copyright The WildFly Authors
* SPDX-License-Identifier: Apache-2.0
*/
package org.wildfly.clustering.marshalling.protostream;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.LinkedList;
import java.util.List;
import org.infinispan.protostream.descriptors.WireType;
/**
* Generic marshaller for a Throwable.
* @author Paul Ferraro
* @param the target type of this marshaller
*/
public class ExceptionMarshaller implements ProtoStreamMarshaller {
private static final int CLASS_INDEX = 1;
private static final int MESSAGE_INDEX = 2;
private static final int CAUSE_INDEX = 3;
private static final int STACK_TRACE_ELEMENT_INDEX = 4;
private static final int SUPPRESSED_INDEX = 5;
private final Class exceptionClass;
public ExceptionMarshaller(Class exceptionClass) {
this.exceptionClass = exceptionClass;
}
@Override
public Class extends E> getJavaClass() {
return this.exceptionClass;
}
@Override
public E readFrom(ProtoStreamReader reader) throws IOException {
Class exceptionClass = this.exceptionClass;
String message = null;
Throwable cause = null;
List stackTrace = new LinkedList<>();
List suppressed = new LinkedList<>();
while (!reader.isAtEnd()) {
int tag = reader.readTag();
switch (WireType.getTagFieldNumber(tag)) {
case CLASS_INDEX:
exceptionClass = reader.readObject(Class.class);
break;
case MESSAGE_INDEX:
message = reader.readString();
break;
case CAUSE_INDEX:
cause = reader.readAny(Throwable.class);
break;
case STACK_TRACE_ELEMENT_INDEX:
stackTrace.add(reader.readObject(StackTraceElement.class));
break;
case SUPPRESSED_INDEX:
suppressed.add(reader.readAny(Throwable.class));
break;
default:
reader.skipField(tag);
}
}
E exception = this.createException(exceptionClass, message, cause);
if (!stackTrace.isEmpty()) {
exception.setStackTrace(stackTrace.toArray(new StackTraceElement[0]));
}
for (Throwable e : suppressed) {
exception.addSuppressed(e);
}
return exception;
}
@Override
public void writeTo(ProtoStreamWriter writer, E exception) throws IOException {
if (this.exceptionClass == Throwable.class) {
writer.writeObject(CLASS_INDEX, exception.getClass());
}
String message = exception.getMessage();
Throwable cause = exception.getCause();
// Avoid serializing redundant message
if ((message != null) && ((cause == null) || !cause.toString().equals(message))) {
writer.writeString(MESSAGE_INDEX, message);
}
if (cause != null) {
writer.writeAny(CAUSE_INDEX, cause);
}
for (StackTraceElement element : exception.getStackTrace()) {
writer.writeObject(STACK_TRACE_ELEMENT_INDEX, element);
}
for (Throwable suppressed : exception.getSuppressed()) {
writer.writeAny(SUPPRESSED_INDEX, suppressed);
}
}
private E createException(Class exceptionClass, String message, Throwable cause) throws IOException {
Constructor emptyConstructor = this.getConstructor(exceptionClass);
Constructor messageConstructor = this.getConstructor(exceptionClass, String.class);
Constructor causeConstructor = this.getConstructor(exceptionClass, Throwable.class);
Constructor messageCauseConstructor = this.getConstructor(exceptionClass, String.class, Throwable.class);
try {
if (cause != null) {
if (message != null) {
if (messageCauseConstructor != null) {
return messageCauseConstructor.newInstance(message, cause);
}
} else {
if (causeConstructor != null) {
return causeConstructor.newInstance(cause);
}
}
}
E exception = (message != null) ? ((messageConstructor != null) ? messageConstructor.newInstance(message) : null) : ((emptyConstructor != null) ? emptyConstructor.newInstance() : null);
if (exception == null) {
throw new NoSuchMethodException(String.format("%s(%s)", exceptionClass.getName(), (message != null) ? String.class.getName() : ""));
}
if (cause != null) {
exception.initCause(cause);
}
return exception;
} catch (NoSuchMethodException | InvocationTargetException | InstantiationException | IllegalAccessException e) {
throw new IOException(e);
}
}
private Constructor getConstructor(Class exceptionClass, Class>... parameterTypes) {
try {
return exceptionClass.getConstructor(parameterTypes);
} catch (NoSuchMethodException e) {
return null;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy