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.amqp.SerializerFactoryBuilder
import net.corda.serialization.internal.amqp.hasCordaSerializable
import net.corda.serialization.internal.amqp.registerCustomSerializers
import java.math.BigDecimal
import java.security.PublicKey
import java.security.cert.CertPath
@ -116,8 +117,10 @@ private class CordaSerializableClassIntrospector(private val context: Module.Set
}
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.
private val serializerFactory = SerializerFactoryBuilder.build(AllWhitelist, javaClass.classLoader)
// 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).also {
registerCustomSerializers(it)
}
override fun changeProperties(config: SerializationConfig,
beanDesc: BeanDescription,
@ -125,7 +128,9 @@ private class CordaSerializableBeanSerializerModifier : BeanSerializerModifier()
val beanClass = beanDesc.beanClass
if (hasCordaSerializable(beanClass) && !SerializeAsToken::class.java.isAssignableFrom(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 }
}
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>>
get() = serializationEnvFields.mapNotNull { it.get()?.let { env -> Pair(it.name, env) } }
@ -94,7 +99,8 @@ val effectiveSerializationEnv: SerializationEnvironment
get() {
return _allEnabledSerializationEnvs.let {
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.StubOutForDJVM
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.utilities.ByteSequence
import net.corda.serialization.internal.CordaSerializationMagic
@ -46,14 +47,20 @@ abstract class AbstractAMQPSerializationScheme(
val sff: SerializerFactoryFactory = createSerializerFactoryFactory()
) : SerializationScheme {
@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.
private val serializerFactoriesForContexts: MutableMap<SerializationFactoryCacheKey, SerializerFactory> = if (maybeNotConcurrentSerializerFactoriesForContexts is AccessOrderLinkedHashMap<*, *>) {
Collections.synchronizedMap(maybeNotConcurrentSerializerFactoriesForContexts)
} else {
maybeNotConcurrentSerializerFactoriesForContexts
}
private val serializerFactoriesForContexts: MutableMap<SerializationFactoryCacheKey, SerializerFactory> =
if (maybeNotConcurrentSerializerFactoriesForContexts is
AccessOrderLinkedHashMap<SerializationFactoryCacheKey, SerializerFactory>) {
Collections.synchronizedMap(maybeNotConcurrentSerializerFactoriesForContexts)
} else {
maybeNotConcurrentSerializerFactoriesForContexts
}
companion object {
private val serializationWhitelists: List<SerializationWhitelist> by lazy { listOf(DefaultWhitelist) }
@ -68,45 +75,16 @@ abstract class AbstractAMQPSerializationScheme(
}
private fun registerCustomSerializers(context: SerializationContext, factory: SerializerFactory) {
with(factory) {
register(publicKeySerializer)
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)
}
factory.register(publicKeySerializer)
registerCustomSerializers(factory)
// This step is registering custom serializers, which have been added after node initialisation (i.e. via attachments during transaction verification).
// Note: the order between the registration of customSerializers and cordappCustomSerializers must be preserved as-is. The reason is the following:
// 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.
// This step is registering custom serializers, which have been added after node initialisation (i.e. via attachments during
// transaction verification).
// Note: the order between the registration of customSerializers and cordappCustomSerializers must be preserved as-is. The reason
// is the following:
// 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 ->
factory.registerExternal(CorDappCustomSerializer(customSerializer, factory))
}
@ -126,22 +104,12 @@ abstract class AbstractAMQPSerializationScheme(
factory.addToWhitelist(*it.whitelist.toTypedArray())
}
cordappSerializationWhitelists.forEach {
it.whitelist.forEach {
clazz -> factory.addToWhitelist(clazz)
it.whitelist.forEach { 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 rpcServerSerializerFactory(context: SerializationContext): SerializerFactory
@ -189,3 +157,49 @@ abstract class AbstractAMQPSerializationScheme(
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
* 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 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.CertificateFactory
class CertPathSerializer(factory: SerializerFactory)
: CustomSerializer.Proxy<CertPath, CertPathSerializer.CertPathProxy>(CertPath::class.java, CertPathProxy::class.java, factory) {
class CertPathSerializer(
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 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.CustomSerializer
import net.corda.serialization.internal.amqp.LocalSerializerFactory
import net.corda.serialization.internal.amqp.SerializerFactory
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.
* @param factory the serializerFactory
*/
class ContractAttachmentSerializer(factory: SerializerFactory) : CustomSerializer.Proxy<ContractAttachment,
ContractAttachmentSerializer.ContractAttachmentProxy>(ContractAttachment::class.java,
ContractAttachmentProxy::class.java, factory) {
class ContractAttachmentSerializer(
factory: SerializerFactory
) : CustomSerializer.Proxy<ContractAttachment, ContractAttachmentSerializer.ContractAttachmentProxy>(
ContractAttachment::class.java,
ContractAttachmentProxy::class.java,
factory
) {
override fun toProxy(obj: ContractAttachment): ContractAttachmentProxy {
val bytes = try {
obj.attachment.open().readFully()
} catch (e: Exception) {
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 {
@ -32,5 +43,12 @@ class ContractAttachmentSerializer(factory: SerializerFactory) : CustomSerialize
}
@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.
*/
object CurrencySerializer : CustomSerializer.ToString<Currency>(Currency::class.java,
object CurrencySerializer
: CustomSerializer.ToString<Currency>(
Currency::class.java,
withInheritance = false,
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.
*/
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 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.
*/
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 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].
*/
object InputStreamSerializer : CustomSerializer.Implements<InputStream>(InputStream::class.java) {
object InputStreamSerializer
: CustomSerializer.Implements<InputStream>(
InputStream::class.java
) {
override val revealSubclassesInSchema: Boolean = true
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.
*/
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 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.
*/
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 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.
*/
class LocalDateTimeSerializer(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))
class LocalDateTimeSerializer(
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())

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.
*/
class LocalTimeSerializer(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)
class LocalTimeSerializer(
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
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.
*/
class MonthDaySerializer(factory: SerializerFactory)
: CustomSerializer.Proxy<MonthDay, MonthDaySerializer.MonthDayProxy>(
class MonthDaySerializer(
factory: SerializerFactory
) : CustomSerializer.Proxy<MonthDay, MonthDaySerializer.MonthDayProxy>(
MonthDay::class.java, MonthDayProxy::class.java, factory
) {
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.
*/
class OffsetDateTimeSerializer(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))
class OffsetDateTimeSerializer(
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)

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.
*/
class OffsetTimeSerializer(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))
class OffsetTimeSerializer(
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)

View File

@ -10,8 +10,13 @@ import net.corda.serialization.internal.amqp.SerializerFactory
* to save on network bandwidth
* Uses [OpaqueBytes] as a proxy
*/
class OpaqueBytesSubSequenceSerializer(factory: SerializerFactory) :
CustomSerializer.Proxy<OpaqueBytesSubSequence, OpaqueBytes>(OpaqueBytesSubSequence::class.java, OpaqueBytes::class.java, factory) {
class OpaqueBytesSubSequenceSerializer(
factory: SerializerFactory
) : CustomSerializer.Proxy<OpaqueBytesSubSequence, OpaqueBytes>(
OpaqueBytesSubSequence::class.java,
OpaqueBytes::class.java,
factory
) {
override val additionalSerializers: Iterable<CustomSerializer<out Any>> = emptyList()
override fun toProxy(obj: OpaqueBytesSubSequence): OpaqueBytes = OpaqueBytes(obj.copyBytes())
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.serialization.internal.amqp.CustomSerializer
import net.corda.serialization.internal.amqp.SerializerFactory
import java.time.OffsetTime
import java.util.*
/**
* 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 {
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.
*/
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 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.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,
context: SerializationContext

View File

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

View File

@ -11,7 +11,13 @@ import net.corda.serialization.internal.model.LocalTypeInformation
import java.io.NotSerializableException
@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 {
private val logger = contextLogger()

View File

@ -7,7 +7,10 @@ import java.lang.reflect.Type
import java.security.cert.CertificateFactory
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(
type.toString(),
"",

View File

@ -7,7 +7,10 @@ import java.lang.reflect.Type
import java.security.cert.CertificateFactory
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(
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.
*/
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 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.
*/
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 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.
*/
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 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.
*/
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
// so that any change to internals of `ZonedDateTime` is detected early.
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 {
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 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
data class ZonedDateTimeProxy(val dateTime: LocalDateTime, val offset: ZoneOffset, val zone: ZoneId)