mirror of
https://github.com/corda/corda.git
synced 2024-12-19 04:57:58 +00:00
Merge branch 'release/os/4.4' of https://github.com/corda/corda into nnagy-os4.4-os4.5-20200426-2
Conflicts: node-api/src/main/kotlin/net/corda/nodeapi/internal/persistence/HibernateConfiguration.kt node-api/src/main/kotlin/net/corda/nodeapi/internal/rpc/client/AMQPClientSerializationScheme.kt
This commit is contained in:
commit
8eab8653cd
@ -141,6 +141,10 @@ object DefaultKryoCustomizer {
|
||||
register(ContractUpgradeWireTransaction::class.java, ContractUpgradeWireTransactionSerializer)
|
||||
register(ContractUpgradeFilteredTransaction::class.java, ContractUpgradeFilteredTransactionSerializer)
|
||||
|
||||
addDefaultSerializer(Iterator::class.java) {kryo, type ->
|
||||
IteratorSerializer(type, CompatibleFieldSerializer<Iterator<*>>(kryo, type).apply { setIgnoreSyntheticFields(false) })
|
||||
}
|
||||
|
||||
for (whitelistProvider in serializationWhitelists) {
|
||||
val types = whitelistProvider.whitelist
|
||||
require(types.toSet().size == types.size) {
|
||||
|
@ -0,0 +1,52 @@
|
||||
package net.corda.node.serialization.kryo
|
||||
|
||||
import com.esotericsoftware.kryo.Kryo
|
||||
import com.esotericsoftware.kryo.Serializer
|
||||
import com.esotericsoftware.kryo.io.Input
|
||||
import com.esotericsoftware.kryo.io.Output
|
||||
import java.lang.reflect.Field
|
||||
|
||||
class IteratorSerializer(type: Class<*>, private val serializer: Serializer<Iterator<*>>) : Serializer<Iterator<*>>(false, false) {
|
||||
|
||||
private val iterableReferenceField = findField(type, "this\$0")?.apply { isAccessible = true }
|
||||
private val expectedModCountField = findField(type, "expectedModCount")?.apply { isAccessible = true }
|
||||
private val iterableReferenceFieldType = iterableReferenceField?.type
|
||||
private val modCountField = when (iterableReferenceFieldType) {
|
||||
null -> null
|
||||
else -> findField(iterableReferenceFieldType, "modCount")?.apply { isAccessible = true }
|
||||
}
|
||||
|
||||
override fun write(kryo: Kryo, output: Output, obj: Iterator<*>) {
|
||||
serializer.write(kryo, output, obj)
|
||||
}
|
||||
|
||||
override fun read(kryo: Kryo, input: Input, type: Class<Iterator<*>>): Iterator<*> {
|
||||
val iterator = serializer.read(kryo, input, type)
|
||||
return fixIterator(iterator)
|
||||
}
|
||||
|
||||
private fun fixIterator(iterator: Iterator<*>) : Iterator<*> {
|
||||
|
||||
// Set expectedModCount of iterator
|
||||
val iterableInstance = iterableReferenceField?.get(iterator) ?: return iterator
|
||||
val modCountValue = modCountField?.getInt(iterableInstance) ?: return iterator
|
||||
expectedModCountField?.setInt(iterator, modCountValue)
|
||||
|
||||
return iterator
|
||||
}
|
||||
|
||||
/**
|
||||
* Find field in clazz or any superclass
|
||||
*/
|
||||
private fun findField(clazz: Class<*>, fieldName: String): Field? {
|
||||
return clazz.declaredFields.firstOrNull { x -> x.name == fieldName } ?: when {
|
||||
clazz.superclass != null -> {
|
||||
// Look in superclasses
|
||||
findField(clazz.superclass, fieldName)
|
||||
}
|
||||
else -> null // Not found
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,122 @@
|
||||
package net.corda.node.serialization.kryo
|
||||
|
||||
import com.nhaarman.mockito_kotlin.doReturn
|
||||
import com.nhaarman.mockito_kotlin.whenever
|
||||
import net.corda.core.serialization.EncodingWhitelist
|
||||
import net.corda.core.serialization.internal.CheckpointSerializationContext
|
||||
import net.corda.core.serialization.internal.checkpointDeserialize
|
||||
import net.corda.core.serialization.internal.checkpointSerialize
|
||||
import net.corda.serialization.internal.AllWhitelist
|
||||
import net.corda.serialization.internal.CheckpointSerializationContextImpl
|
||||
import net.corda.serialization.internal.CordaSerializationEncoding
|
||||
import net.corda.testing.core.internal.CheckpointSerializationEnvironmentRule
|
||||
import net.corda.testing.internal.rigorousMock
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.Parameterized
|
||||
import org.junit.runners.Parameterized.Parameters
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
import kotlin.collections.HashMap
|
||||
import kotlin.collections.HashSet
|
||||
import kotlin.collections.LinkedHashMap
|
||||
import kotlin.collections.LinkedHashSet
|
||||
|
||||
@RunWith(Parameterized::class)
|
||||
class ArrayListItrConcurrentModificationException(private val compression: CordaSerializationEncoding?) {
|
||||
companion object {
|
||||
@Parameters(name = "{0}")
|
||||
@JvmStatic
|
||||
fun compression() = arrayOf<CordaSerializationEncoding?>(null) + CordaSerializationEncoding.values()
|
||||
}
|
||||
|
||||
@get:Rule
|
||||
val serializationRule = CheckpointSerializationEnvironmentRule(inheritable = true)
|
||||
private lateinit var context: CheckpointSerializationContext
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
context = CheckpointSerializationContextImpl(
|
||||
deserializationClassLoader = javaClass.classLoader,
|
||||
whitelist = AllWhitelist,
|
||||
properties = emptyMap(),
|
||||
objectReferencesEnabled = true,
|
||||
encoding = compression,
|
||||
encodingWhitelist = rigorousMock<EncodingWhitelist>().also {
|
||||
if (compression != null) doReturn(true).whenever(it).acceptEncoding(compression)
|
||||
})
|
||||
}
|
||||
|
||||
@Test(timeout=300_000)
|
||||
fun `ArrayList iterator can checkpoint without error`() {
|
||||
runTestWithCollection(ArrayList())
|
||||
}
|
||||
|
||||
@Test(timeout=300_000)
|
||||
fun `HashSet iterator can checkpoint without error`() {
|
||||
runTestWithCollection(HashSet())
|
||||
}
|
||||
|
||||
@Test(timeout=300_000)
|
||||
fun `LinkedHashSet iterator can checkpoint without error`() {
|
||||
runTestWithCollection(LinkedHashSet())
|
||||
}
|
||||
|
||||
@Test(timeout=300_000)
|
||||
fun `HashMap iterator can checkpoint without error`() {
|
||||
runTestWithCollection(HashMap())
|
||||
}
|
||||
|
||||
@Test(timeout=300_000)
|
||||
fun `LinkedHashMap iterator can checkpoint without error`() {
|
||||
runTestWithCollection(LinkedHashMap())
|
||||
}
|
||||
|
||||
@Test(timeout=300_000)
|
||||
fun `LinkedList iterator can checkpoint without error`() {
|
||||
runTestWithCollection(LinkedList())
|
||||
}
|
||||
|
||||
private data class TestCheckpoint<C,I>(val list: C, val iterator: I)
|
||||
|
||||
private fun runTestWithCollection(collection: MutableCollection<Int>) {
|
||||
|
||||
for (i in 1..100) {
|
||||
collection.add(i)
|
||||
}
|
||||
|
||||
val iterator = collection.iterator()
|
||||
iterator.next()
|
||||
|
||||
val checkpoint = TestCheckpoint(collection, iterator)
|
||||
|
||||
val serializedBytes = checkpoint.checkpointSerialize(context)
|
||||
val deserializedCheckpoint = serializedBytes.checkpointDeserialize(context)
|
||||
|
||||
assertThat(deserializedCheckpoint.list).isEqualTo(collection)
|
||||
assertThat(deserializedCheckpoint.iterator.next()).isEqualTo(2)
|
||||
assertThat(deserializedCheckpoint.iterator.hasNext()).isTrue()
|
||||
}
|
||||
|
||||
private fun runTestWithCollection(collection: MutableMap<Int, Int>) {
|
||||
|
||||
for (i in 1..100) {
|
||||
collection[i] = i
|
||||
}
|
||||
|
||||
val iterator = collection.iterator()
|
||||
iterator.next()
|
||||
|
||||
val checkpoint = TestCheckpoint(collection, iterator)
|
||||
|
||||
val serializedBytes = checkpoint.checkpointSerialize(context)
|
||||
val deserializedCheckpoint = serializedBytes.checkpointDeserialize(context)
|
||||
|
||||
assertThat(deserializedCheckpoint.list).isEqualTo(collection)
|
||||
assertThat(deserializedCheckpoint.iterator.next().key).isEqualTo(2)
|
||||
assertThat(deserializedCheckpoint.iterator.hasNext()).isTrue()
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user