mirror of
https://github.com/corda/corda.git
synced 2025-02-01 08:48:09 +00:00
CORDA-540: Expose and fix AMQP serialization problem with UniquenessException (#1470)
This commit is contained in:
parent
1565b395b6
commit
64963d587c
@ -1,5 +1,6 @@
|
||||
package net.corda.core.node.services
|
||||
|
||||
import net.corda.core.CordaException
|
||||
import net.corda.core.contracts.StateRef
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.identity.Party
|
||||
@ -32,5 +33,4 @@ interface UniquenessProvider {
|
||||
data class ConsumingTx(val id: SecureHash, val inputIndex: Int, val requestingParty: Party)
|
||||
}
|
||||
|
||||
@CordaSerializable
|
||||
class UniquenessException(val error: UniquenessProvider.Conflict) : Exception()
|
||||
class UniquenessException(val error: UniquenessProvider.Conflict) : CordaException(UniquenessException::class.java.name)
|
@ -0,0 +1,26 @@
|
||||
package net.corda.core.serialization
|
||||
|
||||
import net.corda.core.contracts.StateRef
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.node.services.UniquenessException
|
||||
import net.corda.core.node.services.UniquenessProvider
|
||||
import net.corda.testing.DUMMY_PARTY
|
||||
import net.corda.testing.TestDependencyInjectionBase
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class UniquenessExceptionSerializationTest : TestDependencyInjectionBase() {
|
||||
|
||||
@Test
|
||||
fun testSerializationRoundTrip() {
|
||||
val txhash = SecureHash.randomSHA256()
|
||||
val txHash2 = SecureHash.randomSHA256()
|
||||
val stateHistory: Map<StateRef, UniquenessProvider.ConsumingTx> = mapOf(StateRef(txhash, 0) to UniquenessProvider.ConsumingTx(txHash2, 1, DUMMY_PARTY))
|
||||
val conflict = UniquenessProvider.Conflict(stateHistory)
|
||||
val instance = UniquenessException(conflict)
|
||||
|
||||
val instanceOnTheOtherSide = instance.serialize().deserialize()
|
||||
|
||||
assertEquals(instance.error, instanceOnTheOtherSide.error)
|
||||
}
|
||||
}
|
@ -37,6 +37,7 @@ class MapSerializer(private val declaredType: ParameterizedType, factory: Serial
|
||||
}
|
||||
|
||||
fun deriveParameterizedType(declaredType: Type, declaredClass: Class<*>, actualClass: Class<*>?): ParameterizedType {
|
||||
declaredClass.checkSupportedMapType()
|
||||
if(supportedTypes.containsKey(declaredClass)) {
|
||||
// Simple case - it is already known to be a map.
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
@ -71,7 +72,7 @@ class MapSerializer(private val declaredType: ParameterizedType, factory: Serial
|
||||
}
|
||||
|
||||
override fun writeObject(obj: Any, data: Data, type: Type, output: SerializationOutput) {
|
||||
obj.javaClass.checkNotUnsupportedHashMap()
|
||||
obj.javaClass.checkSupportedMapType()
|
||||
// Write described
|
||||
data.withDescribed(typeNotation.descriptor) {
|
||||
// Write map
|
||||
@ -96,7 +97,7 @@ class MapSerializer(private val declaredType: ParameterizedType, factory: Serial
|
||||
input.readObjectOrNull(entry.value, schema, declaredType.actualTypeArguments[1])
|
||||
}
|
||||
|
||||
internal fun Class<*>.checkNotUnsupportedHashMap() {
|
||||
internal fun Class<*>.checkSupportedMapType() {
|
||||
if (HashMap::class.java.isAssignableFrom(this) && !LinkedHashMap::class.java.isAssignableFrom(this)) {
|
||||
throw IllegalArgumentException(
|
||||
"Map type $this is unstable under iteration. Suggested fix: use java.util.LinkedHashMap instead.")
|
||||
|
@ -75,7 +75,7 @@ class SerializerFactory(val whitelist: ClassWhitelist, cl: ClassLoader) {
|
||||
(Map::class.java.isAssignableFrom(declaredClass) ||
|
||||
(actualClass != null && Map::class.java.isAssignableFrom(actualClass))) -> {
|
||||
val declaredTypeAmended= MapSerializer.deriveParameterizedType(declaredType, declaredClass, actualClass)
|
||||
serializersByType.computeIfAbsent(declaredClass) {
|
||||
serializersByType.computeIfAbsent(declaredTypeAmended) {
|
||||
makeMapSerializer(declaredTypeAmended)
|
||||
}
|
||||
}
|
||||
@ -288,7 +288,7 @@ class SerializerFactory(val whitelist: ClassWhitelist, cl: ClassLoader) {
|
||||
|
||||
private fun makeMapSerializer(declaredType: ParameterizedType): AMQPSerializer<Any> {
|
||||
val rawType = declaredType.rawType as Class<*>
|
||||
rawType.checkNotUnsupportedHashMap()
|
||||
rawType.checkSupportedMapType()
|
||||
return MapSerializer(declaredType, this)
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,7 @@ class ThrowableSerializer(factory: SerializerFactory) : CustomSerializer.Proxy<T
|
||||
extraProperties[prop.name] = prop.readMethod!!.invoke(obj)
|
||||
}
|
||||
} catch(e: NotSerializableException) {
|
||||
logger.warn("Unexpected exception", e)
|
||||
}
|
||||
obj.originalMessage
|
||||
} else {
|
||||
|
@ -2,10 +2,9 @@ package net.corda.nodeapi.internal.serialization.amqp
|
||||
|
||||
import org.assertj.core.api.Assertions
|
||||
import org.junit.Test
|
||||
import java.io.NotSerializableException
|
||||
import java.util.*
|
||||
|
||||
class DeserializeCollectionTests {
|
||||
class DeserializeMapTests {
|
||||
companion object {
|
||||
/**
|
||||
* If you want to see the schema encoded into the envelope after serialisation change this to true
|
||||
@ -82,7 +81,7 @@ class DeserializeCollectionTests {
|
||||
|
||||
// expected to throw
|
||||
Assertions.assertThatThrownBy { TestSerializationOutput(VERBOSE, sf).serialize(c) }
|
||||
.isInstanceOf(NotSerializableException::class.java).hasMessageContaining("Cannot derive map type for declaredType")
|
||||
.isInstanceOf(IllegalArgumentException::class.java).hasMessageContaining("Unable to serialise deprecated type class java.util.Hashtable. Suggested fix: prefer java.util.map implementations")
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -92,7 +91,7 @@ class DeserializeCollectionTests {
|
||||
|
||||
// expect this to throw
|
||||
Assertions.assertThatThrownBy { TestSerializationOutput(VERBOSE, sf).serialize(c) }
|
||||
.isInstanceOf(NotSerializableException::class.java).hasMessageContaining("Cannot derive map type for declaredType")
|
||||
.isInstanceOf(IllegalArgumentException::class.java).hasMessageContaining("Map type class java.util.HashMap is unstable under iteration. Suggested fix: use java.util.LinkedHashMap instead.")
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -101,7 +100,7 @@ class DeserializeCollectionTests {
|
||||
val c = C (WeakHashMap (mapOf("A" to 1, "B" to 2)))
|
||||
|
||||
Assertions.assertThatThrownBy { TestSerializationOutput(VERBOSE, sf).serialize(c) }
|
||||
.isInstanceOf(NotSerializableException::class.java).hasMessageContaining("Cannot derive map type for declaredType")
|
||||
.isInstanceOf(IllegalArgumentException::class.java).hasMessageContaining("Weak references with map types not supported. Suggested fix: use java.util.LinkedHashMap instead.")
|
||||
}
|
||||
|
||||
@Test
|
||||
|
Loading…
x
Reference in New Issue
Block a user