CORDA-3152: Register custom serializers for jackson as well as amqp

This commit is contained in:
Ryan Fowler 2019-10-14 14:09:17 +01:00
parent 22a8108099
commit bfa460bc07
30 changed files with 320 additions and 108 deletions

View File

@ -51,6 +51,7 @@ import net.corda.core.utilities.toHexString
import net.corda.serialization.internal.AllWhitelist import net.corda.serialization.internal.AllWhitelist
import net.corda.serialization.internal.amqp.SerializerFactoryBuilder import net.corda.serialization.internal.amqp.SerializerFactoryBuilder
import net.corda.serialization.internal.amqp.hasCordaSerializable import net.corda.serialization.internal.amqp.hasCordaSerializable
import net.corda.serialization.internal.amqp.registerCustomSerializers
import java.math.BigDecimal import java.math.BigDecimal
import java.security.PublicKey import java.security.PublicKey
import java.security.cert.CertPath import java.security.cert.CertPath
@ -116,8 +117,10 @@ private class CordaSerializableClassIntrospector(private val context: Module.Set
} }
private class CordaSerializableBeanSerializerModifier : BeanSerializerModifier() { private class CordaSerializableBeanSerializerModifier : BeanSerializerModifier() {
// We need to pass in a SerializerFactory when scanning for properties, but don't actually do any serialisation so any will do. // We need to pass in a SerializerFactory when scanning for properties, but don't actually do any serialisation so any will do.
private val serializerFactory = SerializerFactoryBuilder.build(AllWhitelist, javaClass.classLoader) private val serializerFactory = SerializerFactoryBuilder.build(AllWhitelist, javaClass.classLoader).also {
registerCustomSerializers(it)
}
override fun changeProperties(config: SerializationConfig, override fun changeProperties(config: SerializationConfig,
beanDesc: BeanDescription, beanDesc: BeanDescription,
@ -125,7 +128,9 @@ private class CordaSerializableBeanSerializerModifier : BeanSerializerModifier()
val beanClass = beanDesc.beanClass val beanClass = beanDesc.beanClass
if (hasCordaSerializable(beanClass) && !SerializeAsToken::class.java.isAssignableFrom(beanClass)) { if (hasCordaSerializable(beanClass) && !SerializeAsToken::class.java.isAssignableFrom(beanClass)) {
val typeInformation = serializerFactory.getTypeInformation(beanClass) val typeInformation = serializerFactory.getTypeInformation(beanClass)
val propertyNames = typeInformation.propertiesOrEmptyMap.mapNotNull { if (it.value.isCalculated) null else it.key } val propertyNames = typeInformation.propertiesOrEmptyMap.mapNotNull {
if (it.value.isCalculated) null else it.key
}
beanProperties.removeIf { it.name !in propertyNames } beanProperties.removeIf { it.name !in propertyNames }
} }
return beanProperties return beanProperties

View File

@ -85,7 +85,12 @@ val _inheritableContextSerializationEnv = InheritableThreadLocalToggleField<Seri
} }
} }
private val serializationEnvFields = listOf(_nodeSerializationEnv, _driverSerializationEnv, _contextSerializationEnv, _inheritableContextSerializationEnv) private val serializationEnvFields = listOf(
_nodeSerializationEnv,
_driverSerializationEnv,
_contextSerializationEnv,
_inheritableContextSerializationEnv
)
val _allEnabledSerializationEnvs: List<Pair<String, SerializationEnvironment>> val _allEnabledSerializationEnvs: List<Pair<String, SerializationEnvironment>>
get() = serializationEnvFields.mapNotNull { it.get()?.let { env -> Pair(it.name, env) } } get() = serializationEnvFields.mapNotNull { it.get()?.let { env -> Pair(it.name, env) } }
@ -94,7 +99,8 @@ val effectiveSerializationEnv: SerializationEnvironment
get() { get() {
return _allEnabledSerializationEnvs.let { return _allEnabledSerializationEnvs.let {
checkNotNull(it.singleOrNull()?.second) { checkNotNull(it.singleOrNull()?.second) {
"Expected exactly 1 of {${serializationEnvFields.joinToString(", ") { it.name }}} but got: {${it.joinToString(", ") { it.first }}}" "Expected exactly 1 of {${serializationEnvFields.joinToString(", ") { it.name }}} " +
"but got: {${it.joinToString(", ") { it.first }}}"
} }
} }
} }

View File

@ -6,7 +6,8 @@ import net.corda.core.DeleteForDJVM
import net.corda.core.KeepForDJVM import net.corda.core.KeepForDJVM
import net.corda.core.StubOutForDJVM import net.corda.core.StubOutForDJVM
import net.corda.core.cordapp.Cordapp import net.corda.core.cordapp.Cordapp
import net.corda.core.internal.* import net.corda.core.internal.toSynchronised
import net.corda.core.internal.uncheckedCast
import net.corda.core.serialization.* import net.corda.core.serialization.*
import net.corda.core.utilities.ByteSequence import net.corda.core.utilities.ByteSequence
import net.corda.serialization.internal.CordaSerializationMagic import net.corda.serialization.internal.CordaSerializationMagic
@ -46,14 +47,20 @@ abstract class AbstractAMQPSerializationScheme(
val sff: SerializerFactoryFactory = createSerializerFactoryFactory() val sff: SerializerFactoryFactory = createSerializerFactoryFactory()
) : SerializationScheme { ) : SerializationScheme {
@DeleteForDJVM @DeleteForDJVM
constructor(cordapps: List<Cordapp>) : this(cordapps.customSerializers, cordapps.serializationWhitelists, AccessOrderLinkedHashMap<SerializationFactoryCacheKey, SerializerFactory>(128).toSynchronised()) constructor(cordapps: List<Cordapp>) : this(
cordapps.customSerializers,
cordapps.serializationWhitelists,
AccessOrderLinkedHashMap<SerializationFactoryCacheKey, SerializerFactory>(128).toSynchronised()
)
// This is a bit gross but a broader check for ConcurrentMap is not allowed inside DJVM. // This is a bit gross but a broader check for ConcurrentMap is not allowed inside DJVM.
private val serializerFactoriesForContexts: MutableMap<SerializationFactoryCacheKey, SerializerFactory> = if (maybeNotConcurrentSerializerFactoriesForContexts is AccessOrderLinkedHashMap<*, *>) { private val serializerFactoriesForContexts: MutableMap<SerializationFactoryCacheKey, SerializerFactory> =
Collections.synchronizedMap(maybeNotConcurrentSerializerFactoriesForContexts) if (maybeNotConcurrentSerializerFactoriesForContexts is
} else { AccessOrderLinkedHashMap<SerializationFactoryCacheKey, SerializerFactory>) {
maybeNotConcurrentSerializerFactoriesForContexts Collections.synchronizedMap(maybeNotConcurrentSerializerFactoriesForContexts)
} } else {
maybeNotConcurrentSerializerFactoriesForContexts
}
companion object { companion object {
private val serializationWhitelists: List<SerializationWhitelist> by lazy { listOf(DefaultWhitelist) } private val serializationWhitelists: List<SerializationWhitelist> by lazy { listOf(DefaultWhitelist) }
@ -68,45 +75,16 @@ abstract class AbstractAMQPSerializationScheme(
} }
private fun registerCustomSerializers(context: SerializationContext, factory: SerializerFactory) { private fun registerCustomSerializers(context: SerializationContext, factory: SerializerFactory) {
with(factory) { factory.register(publicKeySerializer)
register(publicKeySerializer) registerCustomSerializers(factory)
register(net.corda.serialization.internal.amqp.custom.PrivateKeySerializer)
register(net.corda.serialization.internal.amqp.custom.ThrowableSerializer(this))
register(net.corda.serialization.internal.amqp.custom.BigDecimalSerializer)
register(net.corda.serialization.internal.amqp.custom.BigIntegerSerializer)
register(net.corda.serialization.internal.amqp.custom.CurrencySerializer)
register(net.corda.serialization.internal.amqp.custom.OpaqueBytesSubSequenceSerializer(this))
register(net.corda.serialization.internal.amqp.custom.InstantSerializer(this))
register(net.corda.serialization.internal.amqp.custom.DurationSerializer(this))
register(net.corda.serialization.internal.amqp.custom.LocalDateSerializer(this))
register(net.corda.serialization.internal.amqp.custom.LocalDateTimeSerializer(this))
register(net.corda.serialization.internal.amqp.custom.LocalTimeSerializer(this))
register(net.corda.serialization.internal.amqp.custom.ZonedDateTimeSerializer(this))
register(net.corda.serialization.internal.amqp.custom.ZoneIdSerializer(this))
register(net.corda.serialization.internal.amqp.custom.OffsetTimeSerializer(this))
register(net.corda.serialization.internal.amqp.custom.OffsetDateTimeSerializer(this))
register(net.corda.serialization.internal.amqp.custom.OptionalSerializer(this))
register(net.corda.serialization.internal.amqp.custom.YearSerializer(this))
register(net.corda.serialization.internal.amqp.custom.YearMonthSerializer(this))
register(net.corda.serialization.internal.amqp.custom.MonthDaySerializer(this))
register(net.corda.serialization.internal.amqp.custom.PeriodSerializer(this))
register(net.corda.serialization.internal.amqp.custom.ClassSerializer(this))
register(net.corda.serialization.internal.amqp.custom.X509CertificateSerializer)
register(net.corda.serialization.internal.amqp.custom.X509CRLSerializer)
register(net.corda.serialization.internal.amqp.custom.CertPathSerializer(this))
register(net.corda.serialization.internal.amqp.custom.StringBufferSerializer)
register(net.corda.serialization.internal.amqp.custom.InputStreamSerializer)
register(net.corda.serialization.internal.amqp.custom.BitSetSerializer(this))
register(net.corda.serialization.internal.amqp.custom.EnumSetSerializer(this))
register(net.corda.serialization.internal.amqp.custom.ContractAttachmentSerializer(this))
registerNonDeterministicSerializers(factory)
}
// This step is registering custom serializers, which have been added after node initialisation (i.e. via attachments during transaction verification). // This step is registering custom serializers, which have been added after node initialisation (i.e. via attachments during
// Note: the order between the registration of customSerializers and cordappCustomSerializers must be preserved as-is. The reason is the following: // transaction verification).
// Currently, the serialization infrastructure does not support multiple versions of a class (the first one that is registered dominates). // Note: the order between the registration of customSerializers and cordappCustomSerializers must be preserved as-is. The reason
// As a result, when inside a context with attachments class loader, we prioritize serializers loaded on-demand from attachments to serializers that had been // is the following:
// loaded during node initialisation, by scanning the cordapps folder. // Currently, the serialization infrastructure does not support multiple versions of a class (the first one that is
// registered dominates). As a result, when inside a context with attachments class loader, we prioritize serializers loaded
// on-demand from attachments to serializers that had been loaded during node initialisation, by scanning the cordapps folder.
context.customSerializers.forEach { customSerializer -> context.customSerializers.forEach { customSerializer ->
factory.registerExternal(CorDappCustomSerializer(customSerializer, factory)) factory.registerExternal(CorDappCustomSerializer(customSerializer, factory))
} }
@ -126,22 +104,12 @@ abstract class AbstractAMQPSerializationScheme(
factory.addToWhitelist(*it.whitelist.toTypedArray()) factory.addToWhitelist(*it.whitelist.toTypedArray())
} }
cordappSerializationWhitelists.forEach { cordappSerializationWhitelists.forEach {
it.whitelist.forEach { it.whitelist.forEach { clazz ->
clazz -> factory.addToWhitelist(clazz) factory.addToWhitelist(clazz)
} }
} }
} }
/*
* Register the serializers which will be excluded from the DJVM.
*/
@StubOutForDJVM
private fun registerNonDeterministicSerializers(factory: SerializerFactory) {
with(factory) {
register(net.corda.serialization.internal.amqp.custom.SimpleStringSerializer)
}
}
protected abstract fun rpcClientSerializerFactory(context: SerializationContext): SerializerFactory protected abstract fun rpcClientSerializerFactory(context: SerializationContext): SerializerFactory
protected abstract fun rpcServerSerializerFactory(context: SerializationContext): SerializerFactory protected abstract fun rpcServerSerializerFactory(context: SerializationContext): SerializerFactory
@ -189,3 +157,49 @@ abstract class AbstractAMQPSerializationScheme(
protected fun canDeserializeVersion(magic: CordaSerializationMagic) = magic == amqpMagic protected fun canDeserializeVersion(magic: CordaSerializationMagic) = magic == amqpMagic
} }
fun registerCustomSerializers(factory: SerializerFactory) {
with(factory) {
register(net.corda.serialization.internal.amqp.custom.PrivateKeySerializer)
register(net.corda.serialization.internal.amqp.custom.ThrowableSerializer(this))
register(net.corda.serialization.internal.amqp.custom.BigDecimalSerializer)
register(net.corda.serialization.internal.amqp.custom.BigIntegerSerializer)
register(net.corda.serialization.internal.amqp.custom.CurrencySerializer)
register(net.corda.serialization.internal.amqp.custom.OpaqueBytesSubSequenceSerializer(this))
register(net.corda.serialization.internal.amqp.custom.InstantSerializer(this))
register(net.corda.serialization.internal.amqp.custom.DurationSerializer(this))
register(net.corda.serialization.internal.amqp.custom.LocalDateSerializer(this))
register(net.corda.serialization.internal.amqp.custom.LocalDateTimeSerializer(this))
register(net.corda.serialization.internal.amqp.custom.LocalTimeSerializer(this))
register(net.corda.serialization.internal.amqp.custom.ZonedDateTimeSerializer(this))
register(net.corda.serialization.internal.amqp.custom.ZoneIdSerializer(this))
register(net.corda.serialization.internal.amqp.custom.OffsetTimeSerializer(this))
register(net.corda.serialization.internal.amqp.custom.OffsetDateTimeSerializer(this))
register(net.corda.serialization.internal.amqp.custom.OptionalSerializer(this))
register(net.corda.serialization.internal.amqp.custom.YearSerializer(this))
register(net.corda.serialization.internal.amqp.custom.YearMonthSerializer(this))
register(net.corda.serialization.internal.amqp.custom.MonthDaySerializer(this))
register(net.corda.serialization.internal.amqp.custom.PeriodSerializer(this))
register(net.corda.serialization.internal.amqp.custom.ClassSerializer(this))
register(net.corda.serialization.internal.amqp.custom.X509CertificateSerializer)
register(net.corda.serialization.internal.amqp.custom.X509CRLSerializer)
register(net.corda.serialization.internal.amqp.custom.CertPathSerializer(this))
register(net.corda.serialization.internal.amqp.custom.StringBufferSerializer)
register(net.corda.serialization.internal.amqp.custom.InputStreamSerializer)
register(net.corda.serialization.internal.amqp.custom.BitSetSerializer(this))
register(net.corda.serialization.internal.amqp.custom.EnumSetSerializer(this))
register(net.corda.serialization.internal.amqp.custom.ContractAttachmentSerializer(this))
}
registerNonDeterministicSerializers(factory)
}
/*
* Register the serializers which will be excluded from the DJVM.
*/
@StubOutForDJVM
private fun registerNonDeterministicSerializers(factory: SerializerFactory) {
with(factory) {
register(net.corda.serialization.internal.amqp.custom.SimpleStringSerializer)
}
}

View File

@ -9,7 +9,13 @@ import java.util.*
* A serializer that writes out a [BitSet] as an integer number of bits, plus the necessary number of bytes to encode that * A serializer that writes out a [BitSet] as an integer number of bits, plus the necessary number of bytes to encode that
* many bits. * many bits.
*/ */
class BitSetSerializer(factory: SerializerFactory) : CustomSerializer.Proxy<BitSet, BitSetSerializer.BitSetProxy>(BitSet::class.java, BitSetProxy::class.java, factory) { class BitSetSerializer(
factory: SerializerFactory
) : CustomSerializer.Proxy<BitSet, BitSetSerializer.BitSetProxy>(
BitSet::class.java,
BitSetProxy::class.java,
factory
) {
override fun toProxy(obj: BitSet): BitSetProxy = BitSetProxy(obj.toByteArray()) override fun toProxy(obj: BitSet): BitSetProxy = BitSetProxy(obj.toByteArray())
override fun fromProxy(proxy: BitSetProxy): BitSet = BitSet.valueOf(proxy.bytes) override fun fromProxy(proxy: BitSetProxy): BitSet = BitSet.valueOf(proxy.bytes)

View File

@ -8,8 +8,13 @@ import java.security.cert.CertPath
import java.security.cert.CertificateException import java.security.cert.CertificateException
import java.security.cert.CertificateFactory import java.security.cert.CertificateFactory
class CertPathSerializer(factory: SerializerFactory) class CertPathSerializer(
: CustomSerializer.Proxy<CertPath, CertPathSerializer.CertPathProxy>(CertPath::class.java, CertPathProxy::class.java, factory) { factory: SerializerFactory
) : CustomSerializer.Proxy<CertPath, CertPathSerializer.CertPathProxy>(
CertPath::class.java,
CertPathProxy::class.java,
factory
) {
override fun toProxy(obj: CertPath): CertPathProxy = CertPathProxy(obj.type, obj.encoded) override fun toProxy(obj: CertPath): CertPathProxy = CertPathProxy(obj.type, obj.encoded)
override fun fromProxy(proxy: CertPathProxy): CertPath { override fun fromProxy(proxy: CertPathProxy): CertPath {

View File

@ -6,7 +6,6 @@ import net.corda.core.utilities.trace
import net.corda.serialization.internal.amqp.AMQPNotSerializableException import net.corda.serialization.internal.amqp.AMQPNotSerializableException
import net.corda.serialization.internal.amqp.CustomSerializer import net.corda.serialization.internal.amqp.CustomSerializer
import net.corda.serialization.internal.amqp.LocalSerializerFactory import net.corda.serialization.internal.amqp.LocalSerializerFactory
import net.corda.serialization.internal.amqp.SerializerFactory
import net.corda.serialization.internal.amqp.custom.ClassSerializer.ClassProxy import net.corda.serialization.internal.amqp.custom.ClassSerializer.ClassProxy
/** /**

View File

@ -15,16 +15,27 @@ import java.security.PublicKey
* A serializer for [ContractAttachment] that uses a proxy object to write out the full attachment eagerly. * A serializer for [ContractAttachment] that uses a proxy object to write out the full attachment eagerly.
* @param factory the serializerFactory * @param factory the serializerFactory
*/ */
class ContractAttachmentSerializer(factory: SerializerFactory) : CustomSerializer.Proxy<ContractAttachment, class ContractAttachmentSerializer(
ContractAttachmentSerializer.ContractAttachmentProxy>(ContractAttachment::class.java, factory: SerializerFactory
ContractAttachmentProxy::class.java, factory) { ) : CustomSerializer.Proxy<ContractAttachment, ContractAttachmentSerializer.ContractAttachmentProxy>(
ContractAttachment::class.java,
ContractAttachmentProxy::class.java,
factory
) {
override fun toProxy(obj: ContractAttachment): ContractAttachmentProxy { override fun toProxy(obj: ContractAttachment): ContractAttachmentProxy {
val bytes = try { val bytes = try {
obj.attachment.open().readFully() obj.attachment.open().readFully()
} catch (e: Exception) { } catch (e: Exception) {
throw MissingAttachmentsException(listOf(obj.id)) throw MissingAttachmentsException(listOf(obj.id))
} }
return ContractAttachmentProxy(GeneratedAttachment(bytes, obj.uploader), obj.contract, obj.additionalContracts, obj.uploader, obj.signerKeys, obj.version) return ContractAttachmentProxy(
GeneratedAttachment(bytes, obj.uploader),
obj.contract,
obj.additionalContracts,
obj.uploader,
obj.signerKeys,
obj.version
)
} }
override fun fromProxy(proxy: ContractAttachmentProxy): ContractAttachment { override fun fromProxy(proxy: ContractAttachmentProxy): ContractAttachment {
@ -32,5 +43,12 @@ class ContractAttachmentSerializer(factory: SerializerFactory) : CustomSerialize
} }
@KeepForDJVM @KeepForDJVM
data class ContractAttachmentProxy(val attachment: Attachment, val contract: ContractClassName, val contracts: Set<ContractClassName>, val uploader: String?, val signers: List<PublicKey>, val version: Int) data class ContractAttachmentProxy(
val attachment: Attachment,
val contract: ContractClassName,
val contracts: Set<ContractClassName>,
val uploader: String?,
val signers: List<PublicKey>,
val version: Int
)
} }

View File

@ -6,7 +6,10 @@ import java.util.*
/** /**
* A custom serializer for the [Currency] class, utilizing the currency code string representation. * A custom serializer for the [Currency] class, utilizing the currency code string representation.
*/ */
object CurrencySerializer : CustomSerializer.ToString<Currency>(Currency::class.java, object CurrencySerializer
: CustomSerializer.ToString<Currency>(
Currency::class.java,
withInheritance = false, withInheritance = false,
maker = { Currency.getInstance(it) }, maker = { Currency.getInstance(it) },
unmaker = { it.currencyCode }) unmaker = { it.currencyCode }
)

View File

@ -8,7 +8,13 @@ import java.time.Duration
/** /**
* A serializer for [Duration] that uses a proxy object to write out the seconds and the nanos. * A serializer for [Duration] that uses a proxy object to write out the seconds and the nanos.
*/ */
class DurationSerializer(factory: SerializerFactory) : CustomSerializer.Proxy<Duration, DurationSerializer.DurationProxy>(Duration::class.java, DurationProxy::class.java, factory) { class DurationSerializer(
factory: SerializerFactory
) : CustomSerializer.Proxy<Duration, DurationSerializer.DurationProxy>(
Duration::class.java,
DurationProxy::class.java,
factory
) {
override fun toProxy(obj: Duration): DurationProxy = DurationProxy(obj.seconds, obj.nano) override fun toProxy(obj: Duration): DurationProxy = DurationProxy(obj.seconds, obj.nano)
override fun fromProxy(proxy: DurationProxy): Duration = Duration.ofSeconds(proxy.seconds, proxy.nanos.toLong()) override fun fromProxy(proxy: DurationProxy): Duration = Duration.ofSeconds(proxy.seconds, proxy.nanos.toLong())

View File

@ -10,7 +10,13 @@ import java.util.*
/** /**
* A serializer that writes out an [EnumSet] as a type, plus list of instances in the set. * A serializer that writes out an [EnumSet] as a type, plus list of instances in the set.
*/ */
class EnumSetSerializer(factory: SerializerFactory) : CustomSerializer.Proxy<EnumSet<*>, EnumSetSerializer.EnumSetProxy>(EnumSet::class.java, EnumSetProxy::class.java, factory) { class EnumSetSerializer(
factory: SerializerFactory
) : CustomSerializer.Proxy<EnumSet<*>, EnumSetSerializer.EnumSetProxy>(
EnumSet::class.java,
EnumSetProxy::class.java,
factory
) {
override val additionalSerializers: Iterable<CustomSerializer<out Any>> = listOf(ClassSerializer(factory)) override val additionalSerializers: Iterable<CustomSerializer<out Any>> = listOf(ClassSerializer(factory))
override fun toProxy(obj: EnumSet<*>): EnumSetProxy = EnumSetProxy(elementType(obj), obj.toList()) override fun toProxy(obj: EnumSet<*>): EnumSetProxy = EnumSetProxy(elementType(obj), obj.toList())

View File

@ -11,7 +11,10 @@ import java.lang.reflect.Type
/** /**
* A serializer that writes out the content of an input stream as bytes and deserializes into a [ByteArrayInputStream]. * A serializer that writes out the content of an input stream as bytes and deserializes into a [ByteArrayInputStream].
*/ */
object InputStreamSerializer : CustomSerializer.Implements<InputStream>(InputStream::class.java) { object InputStreamSerializer
: CustomSerializer.Implements<InputStream>(
InputStream::class.java
) {
override val revealSubclassesInSchema: Boolean = true override val revealSubclassesInSchema: Boolean = true
override val schemaForDocumentation = Schema( override val schemaForDocumentation = Schema(

View File

@ -8,7 +8,13 @@ import java.time.Instant
/** /**
* A serializer for [Instant] that uses a proxy object to write out the seconds since the epoch and the nanos. * A serializer for [Instant] that uses a proxy object to write out the seconds since the epoch and the nanos.
*/ */
class InstantSerializer(factory: SerializerFactory) : CustomSerializer.Proxy<Instant, InstantSerializer.InstantProxy>(Instant::class.java, InstantProxy::class.java, factory) { class InstantSerializer(
factory: SerializerFactory
) : CustomSerializer.Proxy<Instant, InstantSerializer.InstantProxy>(
Instant::class.java,
InstantProxy::class.java,
factory
) {
override fun toProxy(obj: Instant): InstantProxy = InstantProxy(obj.epochSecond, obj.nano) override fun toProxy(obj: Instant): InstantProxy = InstantProxy(obj.epochSecond, obj.nano)
override fun fromProxy(proxy: InstantProxy): Instant = Instant.ofEpochSecond(proxy.epochSeconds, proxy.nanos.toLong()) override fun fromProxy(proxy: InstantProxy): Instant = Instant.ofEpochSecond(proxy.epochSeconds, proxy.nanos.toLong())

View File

@ -8,7 +8,13 @@ import java.time.LocalDate
/** /**
* A serializer for [LocalDate] that uses a proxy object to write out the year, month and day. * A serializer for [LocalDate] that uses a proxy object to write out the year, month and day.
*/ */
class LocalDateSerializer(factory: SerializerFactory) : CustomSerializer.Proxy<LocalDate, LocalDateSerializer.LocalDateProxy>(LocalDate::class.java, LocalDateProxy::class.java, factory) { class LocalDateSerializer(
factory: SerializerFactory
) : CustomSerializer.Proxy<LocalDate, LocalDateSerializer.LocalDateProxy>(
LocalDate::class.java,
LocalDateProxy::class.java,
factory
) {
override fun toProxy(obj: LocalDate): LocalDateProxy = LocalDateProxy(obj.year, obj.monthValue.toByte(), obj.dayOfMonth.toByte()) override fun toProxy(obj: LocalDate): LocalDateProxy = LocalDateProxy(obj.year, obj.monthValue.toByte(), obj.dayOfMonth.toByte())
override fun fromProxy(proxy: LocalDateProxy): LocalDate = LocalDate.of(proxy.year, proxy.month.toInt(), proxy.day.toInt()) override fun fromProxy(proxy: LocalDateProxy): LocalDate = LocalDate.of(proxy.year, proxy.month.toInt(), proxy.day.toInt())

View File

@ -10,8 +10,17 @@ import java.time.LocalTime
/** /**
* A serializer for [LocalDateTime] that uses a proxy object to write out the date and time. * A serializer for [LocalDateTime] that uses a proxy object to write out the date and time.
*/ */
class LocalDateTimeSerializer(factory: SerializerFactory) : CustomSerializer.Proxy<LocalDateTime, LocalDateTimeSerializer.LocalDateTimeProxy>(LocalDateTime::class.java, LocalDateTimeProxy::class.java, factory) { class LocalDateTimeSerializer(
override val additionalSerializers: Iterable<CustomSerializer<out Any>> = listOf(LocalDateSerializer(factory), LocalTimeSerializer(factory)) factory: SerializerFactory
) : CustomSerializer.Proxy<LocalDateTime, LocalDateTimeSerializer.LocalDateTimeProxy>(
LocalDateTime::class.java,
LocalDateTimeProxy::class.java,
factory
) {
override val additionalSerializers: Iterable<CustomSerializer<out Any>> = listOf(
LocalDateSerializer(factory),
LocalTimeSerializer(factory)
)
override fun toProxy(obj: LocalDateTime): LocalDateTimeProxy = LocalDateTimeProxy(obj.toLocalDate(), obj.toLocalTime()) override fun toProxy(obj: LocalDateTime): LocalDateTimeProxy = LocalDateTimeProxy(obj.toLocalDate(), obj.toLocalTime())

View File

@ -8,10 +8,26 @@ import java.time.LocalTime
/** /**
* A serializer for [LocalTime] that uses a proxy object to write out the hours, minutes, seconds and the nanos. * A serializer for [LocalTime] that uses a proxy object to write out the hours, minutes, seconds and the nanos.
*/ */
class LocalTimeSerializer(factory: SerializerFactory) : CustomSerializer.Proxy<LocalTime, LocalTimeSerializer.LocalTimeProxy>(LocalTime::class.java, LocalTimeProxy::class.java, factory) { class LocalTimeSerializer(
override fun toProxy(obj: LocalTime): LocalTimeProxy = LocalTimeProxy(obj.hour.toByte(), obj.minute.toByte(), obj.second.toByte(), obj.nano) factory: SerializerFactory
) : CustomSerializer.Proxy<LocalTime, LocalTimeSerializer.LocalTimeProxy>(
LocalTime::class.java,
LocalTimeProxy::class.java,
factory
) {
override fun toProxy(obj: LocalTime): LocalTimeProxy = LocalTimeProxy(
obj.hour.toByte(),
obj.minute.toByte(),
obj.second.toByte(),
obj.nano
)
override fun fromProxy(proxy: LocalTimeProxy): LocalTime = LocalTime.of(proxy.hour.toInt(), proxy.minute.toInt(), proxy.second.toInt(), proxy.nano) override fun fromProxy(proxy: LocalTimeProxy): LocalTime = LocalTime.of(
proxy.hour.toInt(),
proxy.minute.toInt(),
proxy.second.toInt(),
proxy.nano
)
@KeepForDJVM @KeepForDJVM
data class LocalTimeProxy(val hour: Byte, val minute: Byte, val second: Byte, val nano: Int) data class LocalTimeProxy(val hour: Byte, val minute: Byte, val second: Byte, val nano: Int)

View File

@ -8,8 +8,9 @@ import java.time.MonthDay
/** /**
* A serializer for [MonthDay] that uses a proxy object to write out the integer form. * A serializer for [MonthDay] that uses a proxy object to write out the integer form.
*/ */
class MonthDaySerializer(factory: SerializerFactory) class MonthDaySerializer(
: CustomSerializer.Proxy<MonthDay, MonthDaySerializer.MonthDayProxy>( factory: SerializerFactory
) : CustomSerializer.Proxy<MonthDay, MonthDaySerializer.MonthDayProxy>(
MonthDay::class.java, MonthDayProxy::class.java, factory MonthDay::class.java, MonthDayProxy::class.java, factory
) { ) {
override fun toProxy(obj: MonthDay): MonthDayProxy = MonthDayProxy(obj.monthValue.toByte(), obj.dayOfMonth.toByte()) override fun toProxy(obj: MonthDay): MonthDayProxy = MonthDayProxy(obj.monthValue.toByte(), obj.dayOfMonth.toByte())

View File

@ -10,8 +10,17 @@ import java.time.ZoneOffset
/** /**
* A serializer for [OffsetDateTime] that uses a proxy object to write out the date and zone offset. * A serializer for [OffsetDateTime] that uses a proxy object to write out the date and zone offset.
*/ */
class OffsetDateTimeSerializer(factory: SerializerFactory) : CustomSerializer.Proxy<OffsetDateTime, OffsetDateTimeSerializer.OffsetDateTimeProxy>(OffsetDateTime::class.java, OffsetDateTimeProxy::class.java, factory) { class OffsetDateTimeSerializer(
override val additionalSerializers: Iterable<CustomSerializer<out Any>> = listOf(LocalDateTimeSerializer(factory), ZoneIdSerializer(factory)) factory: SerializerFactory
) : CustomSerializer.Proxy<OffsetDateTime, OffsetDateTimeSerializer.OffsetDateTimeProxy>(
OffsetDateTime::class.java,
OffsetDateTimeProxy::class.java,
factory
) {
override val additionalSerializers: Iterable<CustomSerializer<out Any>> = listOf(
LocalDateTimeSerializer(factory),
ZoneIdSerializer(factory)
)
override fun toProxy(obj: OffsetDateTime): OffsetDateTimeProxy = OffsetDateTimeProxy(obj.toLocalDateTime(), obj.offset) override fun toProxy(obj: OffsetDateTime): OffsetDateTimeProxy = OffsetDateTimeProxy(obj.toLocalDateTime(), obj.offset)

View File

@ -10,8 +10,17 @@ import java.time.ZoneOffset
/** /**
* A serializer for [OffsetTime] that uses a proxy object to write out the time and zone offset. * A serializer for [OffsetTime] that uses a proxy object to write out the time and zone offset.
*/ */
class OffsetTimeSerializer(factory: SerializerFactory) : CustomSerializer.Proxy<OffsetTime, OffsetTimeSerializer.OffsetTimeProxy>(OffsetTime::class.java, OffsetTimeProxy::class.java, factory) { class OffsetTimeSerializer(
override val additionalSerializers: Iterable<CustomSerializer<out Any>> = listOf(LocalTimeSerializer(factory), ZoneIdSerializer(factory)) factory: SerializerFactory
) : CustomSerializer.Proxy<OffsetTime, OffsetTimeSerializer.OffsetTimeProxy>(
OffsetTime::class.java,
OffsetTimeProxy::class.java,
factory
) {
override val additionalSerializers: Iterable<CustomSerializer<out Any>> = listOf(
LocalTimeSerializer(factory),
ZoneIdSerializer(factory)
)
override fun toProxy(obj: OffsetTime): OffsetTimeProxy = OffsetTimeProxy(obj.toLocalTime(), obj.offset) override fun toProxy(obj: OffsetTime): OffsetTimeProxy = OffsetTimeProxy(obj.toLocalTime(), obj.offset)

View File

@ -10,8 +10,13 @@ import net.corda.serialization.internal.amqp.SerializerFactory
* to save on network bandwidth * to save on network bandwidth
* Uses [OpaqueBytes] as a proxy * Uses [OpaqueBytes] as a proxy
*/ */
class OpaqueBytesSubSequenceSerializer(factory: SerializerFactory) : class OpaqueBytesSubSequenceSerializer(
CustomSerializer.Proxy<OpaqueBytesSubSequence, OpaqueBytes>(OpaqueBytesSubSequence::class.java, OpaqueBytes::class.java, factory) { factory: SerializerFactory
) : CustomSerializer.Proxy<OpaqueBytesSubSequence, OpaqueBytes>(
OpaqueBytesSubSequence::class.java,
OpaqueBytes::class.java,
factory
) {
override val additionalSerializers: Iterable<CustomSerializer<out Any>> = emptyList() override val additionalSerializers: Iterable<CustomSerializer<out Any>> = emptyList()
override fun toProxy(obj: OpaqueBytesSubSequence): OpaqueBytes = OpaqueBytes(obj.copyBytes()) override fun toProxy(obj: OpaqueBytesSubSequence): OpaqueBytes = OpaqueBytes(obj.copyBytes())
override fun fromProxy(proxy: OpaqueBytes): OpaqueBytesSubSequence = OpaqueBytesSubSequence(proxy.bytes, proxy.offset, proxy.size) override fun fromProxy(proxy: OpaqueBytes): OpaqueBytesSubSequence = OpaqueBytesSubSequence(proxy.bytes, proxy.offset, proxy.size)

View File

@ -3,13 +3,18 @@ package net.corda.serialization.internal.amqp.custom
import net.corda.core.KeepForDJVM import net.corda.core.KeepForDJVM
import net.corda.serialization.internal.amqp.CustomSerializer import net.corda.serialization.internal.amqp.CustomSerializer
import net.corda.serialization.internal.amqp.SerializerFactory import net.corda.serialization.internal.amqp.SerializerFactory
import java.time.OffsetTime
import java.util.* import java.util.*
/** /**
* A serializer for [Optional] that uses a proxy object to write out the value stored in the optional or [Optional.EMPTY]. * A serializer for [Optional] that uses a proxy object to write out the value stored in the optional or [Optional.EMPTY].
*/ */
class OptionalSerializer(factory: SerializerFactory) : CustomSerializer.Proxy<Optional<*>, OptionalSerializer.OptionalProxy>(Optional::class.java, OptionalProxy::class.java, factory) { class OptionalSerializer(
factory: SerializerFactory
) : CustomSerializer.Proxy<Optional<*>, OptionalSerializer.OptionalProxy>(
Optional::class.java,
OptionalProxy::class.java,
factory
) {
public override fun toProxy(obj: java.util.Optional<*>): OptionalProxy { public override fun toProxy(obj: java.util.Optional<*>): OptionalProxy {
return OptionalProxy(obj.orElse(null)) return OptionalProxy(obj.orElse(null))

View File

@ -8,7 +8,13 @@ import java.time.Period
/** /**
* A serializer for [Period] that uses a proxy object to write out the integer form. * A serializer for [Period] that uses a proxy object to write out the integer form.
*/ */
class PeriodSerializer(factory: SerializerFactory) : CustomSerializer.Proxy<Period, PeriodSerializer.PeriodProxy>(Period::class.java, PeriodProxy::class.java, factory) { class PeriodSerializer(
factory: SerializerFactory
) : CustomSerializer.Proxy<Period, PeriodSerializer.PeriodProxy>(
Period::class.java,
PeriodProxy::class.java,
factory
) {
override fun toProxy(obj: Period): PeriodProxy = PeriodProxy(obj.years, obj.months, obj.days) override fun toProxy(obj: Period): PeriodProxy = PeriodProxy(obj.years, obj.months, obj.days)
override fun fromProxy(proxy: PeriodProxy): Period = Period.of(proxy.years, proxy.months, proxy.days) override fun fromProxy(proxy: PeriodProxy): Period = Period.of(proxy.years, proxy.months, proxy.days)

View File

@ -9,9 +9,19 @@ import org.apache.qpid.proton.codec.Data
import java.lang.reflect.Type import java.lang.reflect.Type
import java.security.PrivateKey import java.security.PrivateKey
object PrivateKeySerializer : CustomSerializer.Implements<PrivateKey>(PrivateKey::class.java) { object PrivateKeySerializer
: CustomSerializer.Implements<PrivateKey>(
PrivateKey::class.java
) {
override val schemaForDocumentation = Schema(listOf(RestrictedType(type.toString(), "", listOf(type.toString()), AMQPTypeIdentifiers.primitiveTypeName(ByteArray::class.java), descriptor, emptyList()))) override val schemaForDocumentation = Schema(listOf(RestrictedType(
type.toString(),
"",
listOf(type.toString()),
AMQPTypeIdentifiers.primitiveTypeName(ByteArray::class.java),
descriptor,
emptyList()
)))
override fun writeDescribedObject(obj: PrivateKey, data: Data, type: Type, output: SerializationOutput, override fun writeDescribedObject(obj: PrivateKey, data: Data, type: Type, output: SerializationOutput,
context: SerializationContext context: SerializationContext

View File

@ -10,8 +10,18 @@ import java.security.PublicKey
/** /**
* A serializer that writes out a public key in X.509 format. * A serializer that writes out a public key in X.509 format.
*/ */
object PublicKeySerializer : CustomSerializer.Implements<PublicKey>(PublicKey::class.java) { object PublicKeySerializer
override val schemaForDocumentation = Schema(listOf(RestrictedType(type.toString(), "", listOf(type.toString()), AMQPTypeIdentifiers.primitiveTypeName(ByteArray::class.java), descriptor, emptyList()))) : CustomSerializer.Implements<PublicKey>(
PublicKey::class.java
) {
override val schemaForDocumentation = Schema(listOf(RestrictedType(
type.toString(),
"",
listOf(type.toString()),
AMQPTypeIdentifiers.primitiveTypeName(ByteArray::class.java),
descriptor,
emptyList()
)))
override fun writeDescribedObject(obj: PublicKey, data: Data, type: Type, output: SerializationOutput, override fun writeDescribedObject(obj: PublicKey, data: Data, type: Type, output: SerializationOutput,
context: SerializationContext context: SerializationContext

View File

@ -11,7 +11,13 @@ import net.corda.serialization.internal.model.LocalTypeInformation
import java.io.NotSerializableException import java.io.NotSerializableException
@KeepForDJVM @KeepForDJVM
class ThrowableSerializer(factory: LocalSerializerFactory) : CustomSerializer.Proxy<Throwable, ThrowableSerializer.ThrowableProxy>(Throwable::class.java, ThrowableProxy::class.java, factory) { class ThrowableSerializer(
factory: LocalSerializerFactory
) : CustomSerializer.Proxy<Throwable, ThrowableSerializer.ThrowableProxy>(
Throwable::class.java,
ThrowableProxy::class.java,
factory
) {
companion object { companion object {
private val logger = contextLogger() private val logger = contextLogger()

View File

@ -7,7 +7,10 @@ import java.lang.reflect.Type
import java.security.cert.CertificateFactory import java.security.cert.CertificateFactory
import java.security.cert.X509CRL import java.security.cert.X509CRL
object X509CRLSerializer : CustomSerializer.Implements<X509CRL>(X509CRL::class.java) { object X509CRLSerializer
: CustomSerializer.Implements<X509CRL>(
X509CRL::class.java
) {
override val schemaForDocumentation = Schema(listOf(RestrictedType( override val schemaForDocumentation = Schema(listOf(RestrictedType(
type.toString(), type.toString(),
"", "",

View File

@ -7,7 +7,10 @@ import java.lang.reflect.Type
import java.security.cert.CertificateFactory import java.security.cert.CertificateFactory
import java.security.cert.X509Certificate import java.security.cert.X509Certificate
object X509CertificateSerializer : CustomSerializer.Implements<X509Certificate>(X509Certificate::class.java) { object X509CertificateSerializer
: CustomSerializer.Implements<X509Certificate>(
X509Certificate::class.java
) {
override val schemaForDocumentation = Schema(listOf(RestrictedType( override val schemaForDocumentation = Schema(listOf(RestrictedType(
type.toString(), type.toString(),
"", "",

View File

@ -8,7 +8,13 @@ import java.time.YearMonth
/** /**
* A serializer for [YearMonth] that uses a proxy object to write out the integer form. * A serializer for [YearMonth] that uses a proxy object to write out the integer form.
*/ */
class YearMonthSerializer(factory: SerializerFactory) : CustomSerializer.Proxy<YearMonth, YearMonthSerializer.YearMonthProxy>(YearMonth::class.java, YearMonthProxy::class.java, factory) { class YearMonthSerializer(
factory: SerializerFactory
) : CustomSerializer.Proxy<YearMonth, YearMonthSerializer.YearMonthProxy>(
YearMonth::class.java,
YearMonthProxy::class.java,
factory
) {
override fun toProxy(obj: YearMonth): YearMonthProxy = YearMonthProxy(obj.year, obj.monthValue.toByte()) override fun toProxy(obj: YearMonth): YearMonthProxy = YearMonthProxy(obj.year, obj.monthValue.toByte())
override fun fromProxy(proxy: YearMonthProxy): YearMonth = YearMonth.of(proxy.year, proxy.month.toInt()) override fun fromProxy(proxy: YearMonthProxy): YearMonth = YearMonth.of(proxy.year, proxy.month.toInt())

View File

@ -8,7 +8,13 @@ import java.time.Year
/** /**
* A serializer for [Year] that uses a proxy object to write out the integer form. * A serializer for [Year] that uses a proxy object to write out the integer form.
*/ */
class YearSerializer(factory: SerializerFactory) : CustomSerializer.Proxy<Year, YearSerializer.YearProxy>(Year::class.java, YearProxy::class.java, factory) { class YearSerializer(
factory: SerializerFactory
) : CustomSerializer.Proxy<Year, YearSerializer.YearProxy>(
Year::class.java,
YearProxy::class.java,
factory
) {
override fun toProxy(obj: Year): YearProxy = YearProxy(obj.value) override fun toProxy(obj: Year): YearProxy = YearProxy(obj.value)
override fun fromProxy(proxy: YearProxy): Year = Year.of(proxy.year) override fun fromProxy(proxy: YearProxy): Year = Year.of(proxy.year)

View File

@ -8,7 +8,13 @@ import java.time.ZoneId
/** /**
* A serializer for [ZoneId] that uses a proxy object to write out the string form. * A serializer for [ZoneId] that uses a proxy object to write out the string form.
*/ */
class ZoneIdSerializer(factory: SerializerFactory) : CustomSerializer.Proxy<ZoneId, ZoneIdSerializer.ZoneIdProxy>(ZoneId::class.java, ZoneIdProxy::class.java, factory) { class ZoneIdSerializer(
factory: SerializerFactory
) : CustomSerializer.Proxy<ZoneId, ZoneIdSerializer.ZoneIdProxy>(
ZoneId::class.java,
ZoneIdProxy::class.java,
factory
) {
override val revealSubclassesInSchema: Boolean = true override val revealSubclassesInSchema: Boolean = true
override fun toProxy(obj: ZoneId): ZoneIdProxy = ZoneIdProxy(obj.id) override fun toProxy(obj: ZoneId): ZoneIdProxy = ZoneIdProxy(obj.id)

View File

@ -12,22 +12,41 @@ import java.time.ZonedDateTime
/** /**
* A serializer for [ZonedDateTime] that uses a proxy object to write out the date, time, offset and zone. * A serializer for [ZonedDateTime] that uses a proxy object to write out the date, time, offset and zone.
*/ */
class ZonedDateTimeSerializer(factory: SerializerFactory) : CustomSerializer.Proxy<ZonedDateTime, ZonedDateTimeSerializer.ZonedDateTimeProxy>(ZonedDateTime::class.java, ZonedDateTimeProxy::class.java, factory) { class ZonedDateTimeSerializer(
factory: SerializerFactory
) : CustomSerializer.Proxy<ZonedDateTime, ZonedDateTimeSerializer.ZonedDateTimeProxy>(
ZonedDateTime::class.java,
ZonedDateTimeProxy::class.java,
factory
) {
// Java deserialization of `ZonedDateTime` uses a private method. We will resolve this somewhat statically // Java deserialization of `ZonedDateTime` uses a private method. We will resolve this somewhat statically
// so that any change to internals of `ZonedDateTime` is detected early. // so that any change to internals of `ZonedDateTime` is detected early.
companion object { companion object {
val ofLenient: Method = ZonedDateTime::class.java.getDeclaredMethod("ofLenient", LocalDateTime::class.java, ZoneOffset::class.java, ZoneId::class.java) val ofLenient: Method = ZonedDateTime::class.java.getDeclaredMethod(
"ofLenient",
LocalDateTime::class.java,
ZoneOffset::class.java,
ZoneId::class.java
)
init { init {
ofLenient.isAccessible = true ofLenient.isAccessible = true
} }
} }
override val additionalSerializers: Iterable<CustomSerializer<out Any>> = listOf(LocalDateTimeSerializer(factory), ZoneIdSerializer(factory)) override val additionalSerializers: Iterable<CustomSerializer<out Any>> = listOf(
LocalDateTimeSerializer(factory),
ZoneIdSerializer(factory)
)
override fun toProxy(obj: ZonedDateTime): ZonedDateTimeProxy = ZonedDateTimeProxy(obj.toLocalDateTime(), obj.offset, obj.zone) override fun toProxy(obj: ZonedDateTime): ZonedDateTimeProxy = ZonedDateTimeProxy(obj.toLocalDateTime(), obj.offset, obj.zone)
override fun fromProxy(proxy: ZonedDateTimeProxy): ZonedDateTime = ofLenient.invoke(null, proxy.dateTime, proxy.offset, proxy.zone) as ZonedDateTime override fun fromProxy(proxy: ZonedDateTimeProxy): ZonedDateTime = ofLenient.invoke(
null,
proxy.dateTime,
proxy.offset,
proxy.zone
) as ZonedDateTime
@KeepForDJVM @KeepForDJVM
data class ZonedDateTimeProxy(val dateTime: LocalDateTime, val offset: ZoneOffset, val zone: ZoneId) data class ZonedDateTimeProxy(val dateTime: LocalDateTime, val offset: ZoneOffset, val zone: ZoneId)