mirror of
https://github.com/corda/corda.git
synced 2025-06-05 09:00:53 +00:00
Correctly unwrap MissingAttachmentException. (#1454)
This commit is contained in:
parent
88a6002246
commit
691d9ea0bc
@ -134,6 +134,7 @@ interface SerializationContext {
|
|||||||
* Helper method to return a new context based on this context with the appropriate class loader constructed from the passed attachment identifiers.
|
* Helper method to return a new context based on this context with the appropriate class loader constructed from the passed attachment identifiers.
|
||||||
* (Requires the attachment storage to have been enabled).
|
* (Requires the attachment storage to have been enabled).
|
||||||
*/
|
*/
|
||||||
|
@Throws(MissingAttachmentsException::class)
|
||||||
fun withAttachmentsClassLoader(attachmentHashes: List<SecureHash>): SerializationContext
|
fun withAttachmentsClassLoader(attachmentHashes: List<SecureHash>): SerializationContext
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -20,6 +20,7 @@ import java.io.ByteArrayOutputStream
|
|||||||
import java.io.NotSerializableException
|
import java.io.NotSerializableException
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
import java.util.concurrent.ExecutionException
|
||||||
|
|
||||||
val attachmentsClassLoaderEnabledPropertyName = "attachments.class.loader.enabled"
|
val attachmentsClassLoaderEnabledPropertyName = "attachments.class.loader.enabled"
|
||||||
|
|
||||||
@ -42,10 +43,15 @@ data class SerializationContextImpl(override val preferredSerializationVersion:
|
|||||||
|
|
||||||
private val cache: Cache<List<SecureHash>, AttachmentsClassLoader> = CacheBuilder.newBuilder().weakValues().maximumSize(1024).build()
|
private val cache: Cache<List<SecureHash>, AttachmentsClassLoader> = CacheBuilder.newBuilder().weakValues().maximumSize(1024).build()
|
||||||
|
|
||||||
// We need to cache the AttachmentClassLoaders to avoid too many contexts, since the class loader is part of cache key for the context.
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* We need to cache the AttachmentClassLoaders to avoid too many contexts, since the class loader is part of cache key for the context.
|
||||||
|
*/
|
||||||
override fun withAttachmentsClassLoader(attachmentHashes: List<SecureHash>): SerializationContext {
|
override fun withAttachmentsClassLoader(attachmentHashes: List<SecureHash>): SerializationContext {
|
||||||
properties[attachmentsClassLoaderEnabledPropertyName] as? Boolean ?: false || return this
|
properties[attachmentsClassLoaderEnabledPropertyName] as? Boolean ?: false || return this
|
||||||
val serializationContext = properties[serializationContextKey] as? SerializeAsTokenContextImpl ?: return this // Some tests don't set one.
|
val serializationContext = properties[serializationContextKey] as? SerializeAsTokenContextImpl ?: return this // Some tests don't set one.
|
||||||
|
try {
|
||||||
return withClassLoader(cache.get(attachmentHashes) {
|
return withClassLoader(cache.get(attachmentHashes) {
|
||||||
val missing = ArrayList<SecureHash>()
|
val missing = ArrayList<SecureHash>()
|
||||||
val attachments = ArrayList<Attachment>()
|
val attachments = ArrayList<Attachment>()
|
||||||
@ -55,6 +61,10 @@ data class SerializationContextImpl(override val preferredSerializationVersion:
|
|||||||
missing.isNotEmpty() && throw MissingAttachmentsException(missing)
|
missing.isNotEmpty() && throw MissingAttachmentsException(missing)
|
||||||
AttachmentsClassLoader(attachments)
|
AttachmentsClassLoader(attachments)
|
||||||
})
|
})
|
||||||
|
} catch (e: ExecutionException) {
|
||||||
|
// Caught from within the cache get, so unwrap.
|
||||||
|
throw e.cause!!
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun withProperty(property: Any, value: Any): SerializationContext {
|
override fun withProperty(property: Any, value: Any): SerializationContext {
|
||||||
|
@ -10,7 +10,6 @@ import net.corda.core.internal.declaredField
|
|||||||
import net.corda.core.node.ServiceHub
|
import net.corda.core.node.ServiceHub
|
||||||
import net.corda.core.node.services.AttachmentStorage
|
import net.corda.core.node.services.AttachmentStorage
|
||||||
import net.corda.core.serialization.*
|
import net.corda.core.serialization.*
|
||||||
import net.corda.core.serialization.SerializationFactory
|
|
||||||
import net.corda.core.transactions.LedgerTransaction
|
import net.corda.core.transactions.LedgerTransaction
|
||||||
import net.corda.core.transactions.TransactionBuilder
|
import net.corda.core.transactions.TransactionBuilder
|
||||||
import net.corda.core.utilities.ByteSequence
|
import net.corda.core.utilities.ByteSequence
|
||||||
@ -377,4 +376,24 @@ class AttachmentClassLoaderTests : TestDependencyInjectionBase() {
|
|||||||
// Then deserialize with the attachment class loader associated with the attachment
|
// Then deserialize with the attachment class loader associated with the attachment
|
||||||
serialized.deserialize(context = inboundContext)
|
serialized.deserialize(context = inboundContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test loading a class with attachment missing during deserialization`() {
|
||||||
|
val child = ClassLoaderForTests()
|
||||||
|
val contractClass = Class.forName("net.corda.contracts.isolated.AnotherDummyContract", true, child)
|
||||||
|
val contract = contractClass.newInstance() as DummyContractBackdoor
|
||||||
|
val storage = MockAttachmentStorage()
|
||||||
|
val attachmentRef = SecureHash.randomSHA256()
|
||||||
|
val outboundContext = SerializationFactory.defaultFactory.defaultContext.withClassLoader(child)
|
||||||
|
// Serialize with custom context to avoid populating the default context with the specially loaded class
|
||||||
|
val serialized = contract.serialize(context = outboundContext)
|
||||||
|
|
||||||
|
// Then deserialize with the attachment class loader associated with the attachment
|
||||||
|
val e = assertFailsWith(MissingAttachmentsException::class) {
|
||||||
|
// We currently ignore annotations in attachments, so manually whitelist.
|
||||||
|
val inboundContext = SerializationFactory.defaultFactory.defaultContext.withWhitelisted(contract.javaClass).withAttachmentStorage(storage).withAttachmentsClassLoader(listOf(attachmentRef))
|
||||||
|
serialized.deserialize(context = inboundContext)
|
||||||
|
}
|
||||||
|
assertEquals(attachmentRef, e.ids.single())
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user