mirror of
https://github.com/corda/corda.git
synced 2025-06-16 06:08:13 +00:00
CORDA-540: Add a property to make sending stacktraces optional in AMQP mode (#1458)
This commit is contained in:
@ -60,7 +60,7 @@ abstract class SerializationFactory {
|
|||||||
* Allow subclasses to temporarily mark themselves as the current factory for the current thread during serialization/deserialization.
|
* Allow subclasses to temporarily mark themselves as the current factory for the current thread during serialization/deserialization.
|
||||||
* Will restore the prior context on exiting the block.
|
* Will restore the prior context on exiting the block.
|
||||||
*/
|
*/
|
||||||
protected fun <T> asCurrent(block: SerializationFactory.() -> T): T {
|
fun <T> asCurrent(block: SerializationFactory.() -> T): T {
|
||||||
val priorContext = _currentFactory.get()
|
val priorContext = _currentFactory.get()
|
||||||
_currentFactory.set(this)
|
_currentFactory.set(this)
|
||||||
try {
|
try {
|
||||||
|
@ -2,6 +2,7 @@ package net.corda.nodeapi.internal.serialization.amqp
|
|||||||
|
|
||||||
import com.google.common.primitives.Primitives
|
import com.google.common.primitives.Primitives
|
||||||
import com.google.common.reflect.TypeToken
|
import com.google.common.reflect.TypeToken
|
||||||
|
import net.corda.core.serialization.SerializationContext
|
||||||
import org.apache.qpid.proton.codec.Data
|
import org.apache.qpid.proton.codec.Data
|
||||||
import java.beans.IndexedPropertyDescriptor
|
import java.beans.IndexedPropertyDescriptor
|
||||||
import java.beans.Introspector
|
import java.beans.Introspector
|
||||||
@ -230,3 +231,10 @@ internal fun suitableForObjectReference(type: Type): Boolean {
|
|||||||
val clazz = type.asClass()
|
val clazz = type.asClass()
|
||||||
return type != ByteArray::class.java && (clazz != null && !clazz.isPrimitive && !Primitives.unwrap(clazz).isPrimitive)
|
return type != ByteArray::class.java && (clazz != null && !clazz.isPrimitive && !Primitives.unwrap(clazz).isPrimitive)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Common properties that are to be used in the [SerializationContext.properties] to alter serialization behavior/content
|
||||||
|
*/
|
||||||
|
internal enum class CommonPropertyNames {
|
||||||
|
IncludeInternalInfo,
|
||||||
|
}
|
@ -2,11 +2,9 @@ package net.corda.nodeapi.internal.serialization.amqp.custom
|
|||||||
|
|
||||||
import net.corda.core.CordaRuntimeException
|
import net.corda.core.CordaRuntimeException
|
||||||
import net.corda.core.CordaThrowable
|
import net.corda.core.CordaThrowable
|
||||||
|
import net.corda.core.serialization.SerializationFactory
|
||||||
import net.corda.core.utilities.loggerFor
|
import net.corda.core.utilities.loggerFor
|
||||||
import net.corda.nodeapi.internal.serialization.amqp.CustomSerializer
|
import net.corda.nodeapi.internal.serialization.amqp.*
|
||||||
import net.corda.nodeapi.internal.serialization.amqp.SerializerFactory
|
|
||||||
import net.corda.nodeapi.internal.serialization.amqp.constructorForDeserialization
|
|
||||||
import net.corda.nodeapi.internal.serialization.amqp.propertiesForSerialization
|
|
||||||
import java.io.NotSerializableException
|
import java.io.NotSerializableException
|
||||||
|
|
||||||
class ThrowableSerializer(factory: SerializerFactory) : CustomSerializer.Proxy<Throwable, ThrowableSerializer.ThrowableProxy>(Throwable::class.java, ThrowableProxy::class.java, factory) {
|
class ThrowableSerializer(factory: SerializerFactory) : CustomSerializer.Proxy<Throwable, ThrowableSerializer.ThrowableProxy>(Throwable::class.java, ThrowableProxy::class.java, factory) {
|
||||||
@ -33,7 +31,14 @@ class ThrowableSerializer(factory: SerializerFactory) : CustomSerializer.Proxy<T
|
|||||||
} else {
|
} else {
|
||||||
obj.message
|
obj.message
|
||||||
}
|
}
|
||||||
return ThrowableProxy(obj.javaClass.name, message, obj.stackTrace, obj.cause, obj.suppressed, extraProperties)
|
val stackTraceToInclude = if (shouldIncludeInternalInfo()) obj.stackTrace else emptyArray()
|
||||||
|
return ThrowableProxy(obj.javaClass.name, message, stackTraceToInclude, obj.cause, obj.suppressed, extraProperties)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun shouldIncludeInternalInfo(): Boolean {
|
||||||
|
val currentContext = SerializationFactory.currentFactory?.currentContext
|
||||||
|
val includeInternalInfo = currentContext?.properties?.get(CommonPropertyNames.IncludeInternalInfo)
|
||||||
|
return true == includeInternalInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun fromProxy(proxy: ThrowableProxy): Throwable {
|
override fun fromProxy(proxy: ThrowableProxy): Throwable {
|
||||||
|
@ -9,6 +9,7 @@ import net.corda.core.crypto.SecureHash
|
|||||||
import net.corda.core.flows.FlowException
|
import net.corda.core.flows.FlowException
|
||||||
import net.corda.core.identity.AbstractParty
|
import net.corda.core.identity.AbstractParty
|
||||||
import net.corda.core.serialization.CordaSerializable
|
import net.corda.core.serialization.CordaSerializable
|
||||||
|
import net.corda.core.serialization.SerializationFactory
|
||||||
import net.corda.core.transactions.LedgerTransaction
|
import net.corda.core.transactions.LedgerTransaction
|
||||||
import net.corda.nodeapi.RPCException
|
import net.corda.nodeapi.RPCException
|
||||||
import net.corda.nodeapi.internal.serialization.AbstractAMQPSerializationScheme
|
import net.corda.nodeapi.internal.serialization.AbstractAMQPSerializationScheme
|
||||||
@ -18,6 +19,7 @@ import net.corda.nodeapi.internal.serialization.amqp.SerializerFactory.Companion
|
|||||||
import net.corda.testing.BOB_IDENTITY
|
import net.corda.testing.BOB_IDENTITY
|
||||||
import net.corda.testing.MEGA_CORP
|
import net.corda.testing.MEGA_CORP
|
||||||
import net.corda.testing.MEGA_CORP_PUBKEY
|
import net.corda.testing.MEGA_CORP_PUBKEY
|
||||||
|
import net.corda.testing.withTestSerialization
|
||||||
import org.apache.qpid.proton.amqp.*
|
import org.apache.qpid.proton.amqp.*
|
||||||
import org.apache.qpid.proton.codec.DecoderImpl
|
import org.apache.qpid.proton.codec.DecoderImpl
|
||||||
import org.apache.qpid.proton.codec.EncoderImpl
|
import org.apache.qpid.proton.codec.EncoderImpl
|
||||||
@ -418,10 +420,18 @@ class SerializationOutputTests {
|
|||||||
factory2.register(net.corda.nodeapi.internal.serialization.amqp.custom.ThrowableSerializer(factory2))
|
factory2.register(net.corda.nodeapi.internal.serialization.amqp.custom.ThrowableSerializer(factory2))
|
||||||
|
|
||||||
val t = IllegalAccessException("message").fillInStackTrace()
|
val t = IllegalAccessException("message").fillInStackTrace()
|
||||||
val desThrowable = serdes(t, factory, factory2, false) as Throwable
|
|
||||||
|
val desThrowable = serdesThrowableWithInternalInfo(t, factory, factory2, false)
|
||||||
assertSerializedThrowableEquivalent(t, desThrowable)
|
assertSerializedThrowableEquivalent(t, desThrowable)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun serdesThrowableWithInternalInfo(t: Throwable, factory: SerializerFactory, factory2: SerializerFactory, expectedEqual: Boolean = true): Throwable = withTestSerialization {
|
||||||
|
val newContext = SerializationFactory.defaultFactory.defaultContext.withProperty(CommonPropertyNames.IncludeInternalInfo, true)
|
||||||
|
|
||||||
|
val deserializedObj = SerializationFactory.defaultFactory.asCurrent { withCurrentContext(newContext) { serdes(t, factory, factory2, expectedEqual) } }
|
||||||
|
return deserializedObj
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test complex throwables serialize`() {
|
fun `test complex throwables serialize`() {
|
||||||
val factory = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader())
|
val factory = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader())
|
||||||
@ -437,7 +447,7 @@ class SerializationOutputTests {
|
|||||||
throw IllegalStateException("Layer 2", t)
|
throw IllegalStateException("Layer 2", t)
|
||||||
}
|
}
|
||||||
} catch(t: Throwable) {
|
} catch(t: Throwable) {
|
||||||
val desThrowable = serdes(t, factory, factory2, false)
|
val desThrowable = serdesThrowableWithInternalInfo(t, factory, factory2, false)
|
||||||
assertSerializedThrowableEquivalent(t, desThrowable)
|
assertSerializedThrowableEquivalent(t, desThrowable)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -469,7 +479,7 @@ class SerializationOutputTests {
|
|||||||
throw e
|
throw e
|
||||||
}
|
}
|
||||||
} catch(t: Throwable) {
|
} catch(t: Throwable) {
|
||||||
val desThrowable = serdes(t, factory, factory2, false)
|
val desThrowable = serdesThrowableWithInternalInfo(t, factory, factory2, false)
|
||||||
assertSerializedThrowableEquivalent(t, desThrowable)
|
assertSerializedThrowableEquivalent(t, desThrowable)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -483,7 +493,7 @@ class SerializationOutputTests {
|
|||||||
factory2.register(net.corda.nodeapi.internal.serialization.amqp.custom.ThrowableSerializer(factory2))
|
factory2.register(net.corda.nodeapi.internal.serialization.amqp.custom.ThrowableSerializer(factory2))
|
||||||
|
|
||||||
val obj = FlowException("message").fillInStackTrace()
|
val obj = FlowException("message").fillInStackTrace()
|
||||||
serdes(obj, factory, factory2)
|
serdesThrowableWithInternalInfo(obj, factory, factory2)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -495,7 +505,7 @@ class SerializationOutputTests {
|
|||||||
factory2.register(net.corda.nodeapi.internal.serialization.amqp.custom.ThrowableSerializer(factory2))
|
factory2.register(net.corda.nodeapi.internal.serialization.amqp.custom.ThrowableSerializer(factory2))
|
||||||
|
|
||||||
val obj = RPCException("message").fillInStackTrace()
|
val obj = RPCException("message").fillInStackTrace()
|
||||||
serdes(obj, factory, factory2)
|
serdesThrowableWithInternalInfo(obj, factory, factory2)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
Reference in New Issue
Block a user