mirror of
https://github.com/corda/corda.git
synced 2025-03-29 15:16:19 +00:00
CORDA-3174: Implement Corda serialization modules. (#59)
* Create DJVM serialization modules. * Create test cases for Array<T>, List<T> and List<Array<T>>. * Refactor SandboxPrimiveSerializer for all primitive types. * Implement SandboxCollectionSerializer to support Collection types. * Implement SandboxMapSerializer to support Map types. * Attempt to fix infinite loop when computing Collection and Map fingerprints. * Apply special handling when deserialising sandbox.java.lang.Character. * Remap Java primitive types to sandbox Java object types to deter evolution. * Use Class.getPackage().getName() to determine sandbox package name. * Implement SandboxEnumSerializer to support Enum types. * Implement SandboxPublicKeySerializer to support Java security keys. * Add serialization projects to the composite example project. * Implement serializers for BigInteger, BigDecimal, Currency and StringBuffer. * Test that deserialising does not instantiate the untrusted user classes. * Implement serializers for java.time.* types. * Add serialiser for BitSet - currently disabled until BitSet itself is supported. * Add serialisers for EnumSet and Class. * Include support for EnumMap in the SandboxMapSerializer. * Ensure the DJVM Example project's tests preserve @CordaSerializable. * Add support for UUID as a primitive type. * Use common abortReadOnly() method for declaring serialization as unsupported. * Streamline the API for deserialising into the sandbox. * Add preliminary support for deserialising X.509 certificates. * Implement serializer for java.util.Optional. * Refactor configuration of the sandbox serialization scheme. * Add tests for deserialising arrays of basic types. * Include method annotations in annotation stitching. This ensures that `@ConstructorForDeserialization` is not dropped. * Enable test for SandboxBitSetSerializer. * Enable tests for X.509 serializers. * Implement serializers for ProtonJ primitive types. * Serialize java.util.Date as a primitive type. * Add the bintray Gradle plugin to the serialisation modules. * Do not publish serialisation modules - they will become part of Corda itself.
This commit is contained in:
commit
67623f04a3
102
build.gradle
Normal file
102
build.gradle
Normal file
@ -0,0 +1,102 @@
|
||||
plugins {
|
||||
id 'org.jetbrains.kotlin.jvm'
|
||||
id 'java-library'
|
||||
id 'idea'
|
||||
}
|
||||
|
||||
ext {
|
||||
corda_version = '5.0-SNAPSHOT'
|
||||
}
|
||||
|
||||
description 'Serialization support for the DJVM'
|
||||
|
||||
configurations {
|
||||
sandboxTesting
|
||||
jdkRt.resolutionStrategy {
|
||||
// Always check the repository for a newer SNAPSHOT.
|
||||
cacheChangingModulesFor 0, 'seconds'
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
maven {
|
||||
url "$artifactory_contextUrl/corda-dev"
|
||||
}
|
||||
}
|
||||
|
||||
configurations{
|
||||
// This is for the latest deterministic Corda SNAPSHOT artifacts...
|
||||
[ compileClasspath, runtimeClasspath ].forEach { cfg ->
|
||||
cfg.resolutionStrategy {
|
||||
// Always check the repository for a newer SNAPSHOT.
|
||||
cacheChangingModulesFor 0, 'seconds'
|
||||
|
||||
dependencySubstitution {
|
||||
substitute module("net.corda:corda-core:$corda_version") with module("net.corda:corda-core-deterministic:$corda_version")
|
||||
substitute module("net.corda:corda-serialization:$corda_version") with module("net.corda:corda-serialization-deterministic:$corda_version")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Corda serialization requires parameter names
|
||||
* to be available via Java reflection.
|
||||
*/
|
||||
tasks.withType(JavaCompile) {
|
||||
options.compilerArgs += '-parameters'
|
||||
}
|
||||
|
||||
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile) {
|
||||
kotlinOptions {
|
||||
javaParameters = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api project(path: ':djvm', configuration: 'shadow')
|
||||
api "net.corda:corda-core:$corda_version"
|
||||
api "net.corda:corda-serialization:$corda_version"
|
||||
implementation project(':serialization:deserializers')
|
||||
|
||||
testImplementation "org.junit.jupiter:junit-jupiter-api:$junit_jupiter_version"
|
||||
testImplementation "org.junit.jupiter:junit-jupiter-params:$junit_jupiter_version"
|
||||
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junit_jupiter_version"
|
||||
|
||||
// Test utilities
|
||||
testImplementation "org.assertj:assertj-core:$assertj_version"
|
||||
testRuntimeOnly "org.apache.logging.log4j:log4j-slf4j-impl:$log4j_version"
|
||||
jdkRt "net.corda:deterministic-rt:latest.integration"
|
||||
|
||||
// The DJVM will need this classpath to run the unit tests.
|
||||
sandboxTesting files(sourceSets.getByName("test").output)
|
||||
sandboxTesting(project(':serialization:deserializers')) {
|
||||
exclude group: 'net.corda'
|
||||
}
|
||||
sandboxTesting "net.corda:corda-serialization-deterministic:$corda_version"
|
||||
sandboxTesting "org.slf4j:slf4j-nop:$slf4j_version"
|
||||
}
|
||||
|
||||
jar {
|
||||
manifest {
|
||||
attributes('Sealed': true)
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType(Test) {
|
||||
systemProperty 'deterministic-rt.path', configurations.jdkRt.asPath
|
||||
systemProperty 'sandbox-libraries.path', configurations.sandboxTesting.asPath
|
||||
}
|
||||
|
||||
//publish {
|
||||
// name 'corda-djvm-serialization'
|
||||
//}
|
||||
|
||||
idea {
|
||||
module {
|
||||
downloadJavadoc = true
|
||||
downloadSources = true
|
||||
}
|
||||
}
|
29
deserializers/build.gradle
Normal file
29
deserializers/build.gradle
Normal file
@ -0,0 +1,29 @@
|
||||
plugins {
|
||||
id 'org.jetbrains.kotlin.jvm'
|
||||
id 'java-library'
|
||||
id 'idea'
|
||||
}
|
||||
|
||||
description 'Deserializers for the DJVM'
|
||||
|
||||
dependencies {
|
||||
api "net.corda:corda-core:$corda_version"
|
||||
api "net.corda:corda-serialization:$corda_version"
|
||||
}
|
||||
|
||||
jar {
|
||||
manifest {
|
||||
attributes('Sealed': true)
|
||||
}
|
||||
}
|
||||
|
||||
//publish {
|
||||
// name 'corda-djvm-deserializers'
|
||||
//}
|
||||
|
||||
idea {
|
||||
module {
|
||||
downloadJavadoc = true
|
||||
downloadSources = true
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package net.corda.djvm.serialization.deserializers
|
||||
|
||||
import net.corda.serialization.internal.amqp.custom.BitSetSerializer.BitSetProxy
|
||||
import java.util.*
|
||||
import java.util.function.Function
|
||||
|
||||
class BitSetDeserializer : Function<BitSetProxy, BitSet> {
|
||||
override fun apply(proxy: BitSetProxy): BitSet {
|
||||
return BitSet.valueOf(proxy.bytes)
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package net.corda.djvm.serialization.deserializers
|
||||
|
||||
import net.corda.serialization.internal.amqp.custom.CertPathSerializer.CertPathProxy
|
||||
import java.security.cert.CertPath
|
||||
import java.security.cert.CertificateFactory
|
||||
import java.util.function.Function
|
||||
|
||||
class CertPathDeserializer : Function<CertPathProxy, CertPath> {
|
||||
override fun apply(proxy: CertPathProxy): CertPath {
|
||||
val factory = CertificateFactory.getInstance(proxy.type)
|
||||
return factory.generateCertPath(proxy.encoded.inputStream())
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package net.corda.djvm.serialization.deserializers
|
||||
|
||||
import net.corda.serialization.internal.amqp.custom.ClassSerializer.ClassProxy
|
||||
|
||||
import java.util.function.Function
|
||||
|
||||
class ClassDeserializer : Function<ClassProxy, Class<*>> {
|
||||
override fun apply(proxy: ClassProxy): Class<*> {
|
||||
return Class.forName(proxy.className)
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
package net.corda.djvm.serialization.deserializers
|
||||
|
||||
import net.corda.core.utilities.NonEmptySet
|
||||
import java.util.*
|
||||
import java.util.function.Function
|
||||
|
||||
class CreateCollection : Function<Array<Any?>, Collection<Any?>> {
|
||||
private val concreteConstructors: Map<Class<out Collection<*>>, (Array<Any?>) -> Collection<Any?>> = mapOf(
|
||||
List::class.java to ::createList,
|
||||
Set::class.java to ::createSet,
|
||||
SortedSet::class.java to ::createSortedSet,
|
||||
NavigableSet::class.java to ::createNavigableSet,
|
||||
Collection::class.java to ::createCollection,
|
||||
NonEmptySet::class.java to ::createNonEmptySet
|
||||
)
|
||||
|
||||
private fun createList(values: Array<Any?>): List<Any?> {
|
||||
return Collections.unmodifiableList(arrayListOf(*values))
|
||||
}
|
||||
|
||||
private fun createSet(values: Array<Any?>): Set<Any?> {
|
||||
return Collections.unmodifiableSet(linkedSetOf(*values))
|
||||
}
|
||||
|
||||
private fun createSortedSet(values: Array<Any?>): SortedSet<Any?> {
|
||||
return Collections.unmodifiableSortedSet(sortedSetOf(*values))
|
||||
}
|
||||
|
||||
private fun createNavigableSet(values: Array<Any?>): NavigableSet<Any?> {
|
||||
return Collections.unmodifiableNavigableSet(sortedSetOf(*values))
|
||||
}
|
||||
|
||||
private fun createCollection(values: Array<Any?>): Collection<Any?> {
|
||||
return Collections.unmodifiableCollection(arrayListOf(*values))
|
||||
}
|
||||
|
||||
private fun createNonEmptySet(values: Array<Any?>): NonEmptySet<Any?> {
|
||||
return NonEmptySet.copyOf(arrayListOf(*values))
|
||||
}
|
||||
|
||||
@Suppress("unchecked_cast")
|
||||
override fun apply(inputs: Array<Any?>): Collection<Any?> {
|
||||
val collectionClass = inputs[0] as Class<out Collection<Any?>>
|
||||
val args = inputs[1] as Array<Any?>
|
||||
return concreteConstructors[collectionClass]?.invoke(args)!!
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package net.corda.djvm.serialization.deserializers
|
||||
|
||||
import java.util.*
|
||||
import java.util.function.Function
|
||||
|
||||
class CreateCurrency : Function<String, Currency> {
|
||||
override fun apply(currencyCode: String): Currency {
|
||||
return Currency.getInstance(currencyCode)
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package net.corda.djvm.serialization.deserializers
|
||||
|
||||
import java.lang.reflect.Constructor
|
||||
import java.util.function.Function
|
||||
|
||||
class CreateFromString(private val factory: Constructor<Any>) : Function<String, Any> {
|
||||
override fun apply(text: String): Any {
|
||||
return factory.newInstance(text)
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package net.corda.djvm.serialization.deserializers
|
||||
|
||||
import java.util.*
|
||||
import java.util.function.Function
|
||||
|
||||
class CreateMap : Function<Array<Any>, Map<Any?, Any?>> {
|
||||
private val concreteConstructors: Map<Class<out Map<*, *>>, (Array<Array<Any>>) -> Map<Any?, Any?>> = mapOf(
|
||||
Map::class.java to ::createMap,
|
||||
SortedMap::class.java to ::createSortedMap,
|
||||
LinkedHashMap::class.java to ::createLinkedHashMap,
|
||||
NavigableMap::class.java to ::createNavigableMap,
|
||||
TreeMap::class.java to ::createTreeMap,
|
||||
EnumMap::class.java to ::createEnumMap
|
||||
)
|
||||
|
||||
private fun createMap(values: Array<Array<Any>>): Map<Any?, Any?> {
|
||||
return Collections.unmodifiableMap(values.map { it[0] to it[1] }.toMap())
|
||||
}
|
||||
|
||||
private fun createSortedMap(values: Array<Array<Any>>): SortedMap<Any?, out Any?> {
|
||||
return Collections.unmodifiableSortedMap(createTreeMap(values))
|
||||
}
|
||||
|
||||
private fun createNavigableMap(values: Array<Array<Any>>): NavigableMap<Any?, out Any?> {
|
||||
return Collections.unmodifiableNavigableMap(createTreeMap(values))
|
||||
}
|
||||
|
||||
private fun createLinkedHashMap(values: Array<Array<Any>>): LinkedHashMap<Any?, out Any?> {
|
||||
return values.map { it[0] to it[1] }.toMap(LinkedHashMap())
|
||||
}
|
||||
|
||||
private fun createTreeMap(values: Array<Array<Any>>): TreeMap<Any?, out Any?> {
|
||||
return values.map { it[0] to it[1] }.toMap(TreeMap())
|
||||
}
|
||||
|
||||
private fun createEnumMap(values: Array<Array<Any>>): Map<Any?, Any?> {
|
||||
val map = values.map { it[0] to it[1] }.toMap()
|
||||
@Suppress("unchecked_cast")
|
||||
return EnumMap(map as Map<JustForCasting, Any?>) as Map<Any?, Any?>
|
||||
}
|
||||
|
||||
@Suppress("unchecked_cast")
|
||||
override fun apply(inputs: Array<Any>): Map<Any?, Any?> {
|
||||
val mapClass = inputs[0] as Class<out Map<Any?, Any?>>
|
||||
val args = inputs[1] as Array<Array<Any>>
|
||||
return concreteConstructors[mapClass]?.invoke(args)!!
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package net.corda.djvm.serialization.deserializers
|
||||
|
||||
import org.apache.qpid.proton.amqp.Decimal128
|
||||
import java.util.function.Function
|
||||
|
||||
class Decimal128Deserializer : Function<LongArray, Decimal128> {
|
||||
override fun apply(underlying: LongArray): Decimal128 {
|
||||
return Decimal128(underlying[0], underlying[1])
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package net.corda.djvm.serialization.deserializers
|
||||
|
||||
import org.apache.qpid.proton.amqp.Decimal32
|
||||
import java.util.function.Function
|
||||
|
||||
class Decimal32Deserializer : Function<IntArray, Decimal32> {
|
||||
override fun apply(underlying: IntArray): Decimal32 {
|
||||
return Decimal32(underlying[0])
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package net.corda.djvm.serialization.deserializers
|
||||
|
||||
import org.apache.qpid.proton.amqp.Decimal64
|
||||
import java.util.function.Function
|
||||
|
||||
class Decimal64Deserializer : Function<LongArray, Decimal64> {
|
||||
override fun apply(underlying: LongArray): Decimal64 {
|
||||
return Decimal64(underlying[0])
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package net.corda.djvm.serialization.deserializers
|
||||
|
||||
import java.util.function.Function
|
||||
|
||||
class DescribeEnum : Function<Class<*>, Array<out Any>> {
|
||||
override fun apply(enumClass: Class<*>): Array<out Any> {
|
||||
return enumClass.enumConstants
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package net.corda.djvm.serialization.deserializers
|
||||
|
||||
import net.corda.serialization.internal.amqp.custom.DurationSerializer.DurationProxy
|
||||
import java.time.Duration
|
||||
import java.util.function.Function
|
||||
|
||||
class DurationDeserializer : Function<DurationProxy, Duration> {
|
||||
override fun apply(proxy: DurationProxy): Duration {
|
||||
return Duration.ofSeconds(proxy.seconds, proxy.nanos.toLong())
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package net.corda.djvm.serialization.deserializers
|
||||
|
||||
import net.corda.core.internal.uncheckedCast
|
||||
import net.corda.serialization.internal.amqp.custom.EnumSetSerializer.EnumSetProxy
|
||||
import java.util.*
|
||||
import java.util.function.Function
|
||||
|
||||
class EnumSetDeserializer : Function<EnumSetProxy, EnumSet<*>> {
|
||||
override fun apply(proxy: EnumSetProxy): EnumSet<*> {
|
||||
return if (proxy.elements.isEmpty()) {
|
||||
EnumSet.noneOf(uncheckedCast<Class<*>, Class<JustForCasting>>(proxy.clazz))
|
||||
} else {
|
||||
EnumSet.copyOf(uncheckedCast<List<Any>, List<JustForCasting>>(proxy.elements))
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package net.corda.djvm.serialization.deserializers
|
||||
|
||||
import net.corda.serialization.internal.amqp.custom.InstantSerializer.InstantProxy
|
||||
import java.time.Instant
|
||||
import java.util.function.Function
|
||||
|
||||
class InstantDeserializer : Function<InstantProxy, Instant> {
|
||||
override fun apply(proxy: InstantProxy): Instant {
|
||||
return Instant.ofEpochSecond(proxy.epochSeconds, proxy.nanos.toLong())
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package net.corda.djvm.serialization.deserializers
|
||||
|
||||
@Suppress("unused")
|
||||
enum class JustForCasting {
|
||||
UNUSED
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package net.corda.djvm.serialization.deserializers
|
||||
|
||||
import net.corda.serialization.internal.amqp.custom.LocalDateSerializer.LocalDateProxy
|
||||
import java.time.LocalDate
|
||||
import java.util.function.Function
|
||||
|
||||
class LocalDateDeserializer : Function<LocalDateProxy, LocalDate> {
|
||||
override fun apply(proxy: LocalDateProxy): LocalDate {
|
||||
return LocalDate.of(proxy.year, proxy.month.toInt(), proxy.day.toInt())
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package net.corda.djvm.serialization.deserializers
|
||||
|
||||
import net.corda.serialization.internal.amqp.custom.LocalDateTimeSerializer.LocalDateTimeProxy
|
||||
import java.time.LocalDateTime
|
||||
import java.util.function.Function
|
||||
|
||||
class LocalDateTimeDeserializer : Function<LocalDateTimeProxy, LocalDateTime> {
|
||||
override fun apply(proxy: LocalDateTimeProxy): LocalDateTime {
|
||||
return LocalDateTime.of(proxy.date, proxy.time)
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package net.corda.djvm.serialization.deserializers
|
||||
|
||||
import net.corda.serialization.internal.amqp.custom.LocalTimeSerializer.LocalTimeProxy
|
||||
import java.time.LocalTime
|
||||
import java.util.function.Function
|
||||
|
||||
class LocalTimeDeserializer : Function<LocalTimeProxy, LocalTime> {
|
||||
override fun apply(proxy: LocalTimeProxy): LocalTime {
|
||||
return LocalTime.of(proxy.hour.toInt(), proxy.minute.toInt(), proxy.second.toInt(), proxy.nano)
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package net.corda.djvm.serialization.deserializers
|
||||
|
||||
import net.corda.serialization.internal.amqp.custom.MonthDaySerializer.MonthDayProxy
|
||||
import java.time.MonthDay
|
||||
import java.util.function.Function
|
||||
|
||||
class MonthDayDeserializer : Function<MonthDayProxy, MonthDay> {
|
||||
override fun apply(proxy: MonthDayProxy): MonthDay {
|
||||
return MonthDay.of(proxy.month.toInt(), proxy.day.toInt())
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package net.corda.djvm.serialization.deserializers
|
||||
|
||||
import net.corda.serialization.internal.amqp.custom.OffsetDateTimeSerializer.OffsetDateTimeProxy
|
||||
import java.time.OffsetDateTime
|
||||
import java.util.function.Function
|
||||
|
||||
class OffsetDateTimeDeserializer : Function<OffsetDateTimeProxy, OffsetDateTime> {
|
||||
override fun apply(proxy: OffsetDateTimeProxy): OffsetDateTime {
|
||||
return OffsetDateTime.of(proxy.dateTime, proxy.offset)
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package net.corda.djvm.serialization.deserializers
|
||||
|
||||
import net.corda.serialization.internal.amqp.custom.OffsetTimeSerializer.OffsetTimeProxy
|
||||
import java.time.OffsetTime
|
||||
import java.util.function.Function
|
||||
|
||||
class OffsetTimeDeserializer : Function<OffsetTimeProxy, OffsetTime> {
|
||||
override fun apply(proxy: OffsetTimeProxy): OffsetTime {
|
||||
return OffsetTime.of(proxy.time, proxy.offset)
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package net.corda.djvm.serialization.deserializers
|
||||
|
||||
import net.corda.serialization.internal.amqp.custom.OptionalSerializer.OptionalProxy
|
||||
import java.util.*
|
||||
import java.util.function.Function
|
||||
|
||||
class OptionalDeserializer : Function<OptionalProxy, Optional<Any>> {
|
||||
override fun apply(proxy: OptionalProxy): Optional<Any> {
|
||||
return Optional.ofNullable(proxy.item)
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package net.corda.djvm.serialization.deserializers
|
||||
|
||||
import net.corda.serialization.internal.amqp.custom.PeriodSerializer.PeriodProxy
|
||||
import java.time.Period
|
||||
import java.util.function.Function
|
||||
|
||||
class PeriodDeserializer : Function<PeriodProxy, Period> {
|
||||
override fun apply(proxy: PeriodProxy): Period {
|
||||
return Period.of(proxy.years, proxy.months, proxy.days)
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package net.corda.djvm.serialization.deserializers
|
||||
|
||||
import net.corda.core.crypto.Crypto
|
||||
import java.security.PublicKey
|
||||
import java.util.function.Function
|
||||
|
||||
class PublicKeyDecoder : Function<ByteArray, PublicKey> {
|
||||
override fun apply(encoded: ByteArray): PublicKey {
|
||||
return Crypto.decodePublicKey(encoded)
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package net.corda.djvm.serialization.deserializers
|
||||
|
||||
import org.apache.qpid.proton.amqp.Symbol
|
||||
import java.util.function.Function
|
||||
|
||||
class SymbolDeserializer : Function<String, Symbol> {
|
||||
override fun apply(value: String): Symbol {
|
||||
return Symbol.valueOf(value)
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package net.corda.djvm.serialization.deserializers
|
||||
|
||||
import org.apache.qpid.proton.amqp.UnsignedByte
|
||||
import java.util.function.Function
|
||||
|
||||
class UnsignedByteDeserializer : Function<ByteArray, UnsignedByte> {
|
||||
override fun apply(underlying: ByteArray): UnsignedByte {
|
||||
return UnsignedByte(underlying[0])
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package net.corda.djvm.serialization.deserializers
|
||||
|
||||
import org.apache.qpid.proton.amqp.UnsignedInteger
|
||||
import java.util.function.Function
|
||||
|
||||
class UnsignedIntegerDeserializer : Function<IntArray, UnsignedInteger> {
|
||||
override fun apply(underlying: IntArray): UnsignedInteger {
|
||||
return UnsignedInteger(underlying[0])
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package net.corda.djvm.serialization.deserializers
|
||||
|
||||
import org.apache.qpid.proton.amqp.UnsignedLong
|
||||
import java.util.function.Function
|
||||
|
||||
class UnsignedLongDeserializer : Function<LongArray, UnsignedLong> {
|
||||
override fun apply(underlying: LongArray): UnsignedLong {
|
||||
return UnsignedLong(underlying[0])
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package net.corda.djvm.serialization.deserializers
|
||||
|
||||
import org.apache.qpid.proton.amqp.UnsignedShort
|
||||
import java.util.function.Function
|
||||
|
||||
class UnsignedShortDeserializer : Function<ShortArray, UnsignedShort> {
|
||||
override fun apply(underlying: ShortArray): UnsignedShort {
|
||||
return UnsignedShort(underlying[0])
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package net.corda.djvm.serialization.deserializers
|
||||
|
||||
import java.security.cert.CertificateFactory
|
||||
import java.security.cert.X509CRL
|
||||
import java.util.function.Function
|
||||
|
||||
class X509CRLDeserializer : Function<ByteArray, X509CRL> {
|
||||
override fun apply(bytes: ByteArray): X509CRL {
|
||||
val factory = CertificateFactory.getInstance("X.509")
|
||||
return factory.generateCRL(bytes.inputStream()) as X509CRL
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package net.corda.djvm.serialization.deserializers
|
||||
|
||||
import java.security.cert.CertificateFactory
|
||||
import java.security.cert.X509Certificate
|
||||
import java.util.function.Function
|
||||
|
||||
class X509CertificateDeserializer : Function<ByteArray, X509Certificate> {
|
||||
override fun apply(bits: ByteArray): X509Certificate {
|
||||
val factory = CertificateFactory.getInstance("X.509")
|
||||
return factory.generateCertificate(bits.inputStream()) as X509Certificate
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package net.corda.djvm.serialization.deserializers
|
||||
|
||||
import net.corda.serialization.internal.amqp.custom.YearSerializer.YearProxy
|
||||
import java.time.Year
|
||||
import java.util.function.Function
|
||||
|
||||
class YearDeserializer : Function<YearProxy, Year> {
|
||||
override fun apply(proxy: YearProxy): Year {
|
||||
return Year.of(proxy.year)
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package net.corda.djvm.serialization.deserializers
|
||||
|
||||
import net.corda.serialization.internal.amqp.custom.YearMonthSerializer.YearMonthProxy
|
||||
import java.time.YearMonth
|
||||
import java.util.function.Function
|
||||
|
||||
class YearMonthDeserializer : Function<YearMonthProxy, YearMonth> {
|
||||
override fun apply(proxy: YearMonthProxy): YearMonth {
|
||||
return YearMonth.of(proxy.year, proxy.month.toInt())
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package net.corda.djvm.serialization.deserializers
|
||||
|
||||
import net.corda.serialization.internal.amqp.custom.ZoneIdSerializer.ZoneIdProxy
|
||||
import java.time.ZoneId
|
||||
import java.util.function.Function
|
||||
|
||||
class ZoneIdDeserializer : Function<ZoneIdProxy, ZoneId> {
|
||||
override fun apply(proxy: ZoneIdProxy): ZoneId {
|
||||
return ZoneId.of(proxy.id)
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package net.corda.djvm.serialization.deserializers
|
||||
|
||||
import net.corda.serialization.internal.amqp.custom.ZonedDateTimeSerializer.ZonedDateTimeProxy
|
||||
import java.util.function.Function
|
||||
|
||||
class ZonedDateTimeDeserializer : Function<ZonedDateTimeProxy, Array<out Any>?> {
|
||||
override fun apply(proxy: ZonedDateTimeProxy): Array<out Any>? {
|
||||
return arrayOf(proxy.dateTime, proxy.offset, proxy.zone)
|
||||
}
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
package net.corda.djvm.serialization
|
||||
|
||||
import net.corda.core.serialization.SerializationContext
|
||||
import net.corda.core.serialization.SerializationContext.UseCase
|
||||
import net.corda.core.serialization.SerializedBytes
|
||||
import net.corda.core.utilities.ByteSequence
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.djvm.serialization.serializers.*
|
||||
import net.corda.serialization.internal.CordaSerializationMagic
|
||||
import net.corda.serialization.internal.SerializationScheme
|
||||
import net.corda.serialization.internal.amqp.*
|
||||
import java.math.BigDecimal
|
||||
import java.math.BigInteger
|
||||
import java.util.*
|
||||
import java.util.function.BiFunction
|
||||
import java.util.function.Function
|
||||
|
||||
class AMQPSerializationScheme(
|
||||
private val classLoader: SandboxClassLoader,
|
||||
private val sandboxBasicInput: Function<in Any?, out Any?>,
|
||||
private val executor: BiFunction<in Any, in Any?, out Any?>,
|
||||
private val serializerFactoryFactory: SerializerFactoryFactory
|
||||
) : SerializationScheme {
|
||||
|
||||
private fun getSerializerFactory(context: SerializationContext): SerializerFactory {
|
||||
return serializerFactoryFactory.make(context).apply {
|
||||
register(SandboxBitSetSerializer(classLoader, executor, this))
|
||||
register(SandboxCertPathSerializer(classLoader, executor, this))
|
||||
register(SandboxDurationSerializer(classLoader, executor, this))
|
||||
register(SandboxEnumSetSerializer(classLoader, executor, this))
|
||||
register(SandboxInstantSerializer(classLoader, executor, this))
|
||||
register(SandboxLocalDateSerializer(classLoader, executor, this))
|
||||
register(SandboxLocalDateTimeSerializer(classLoader, executor, this))
|
||||
register(SandboxLocalTimeSerializer(classLoader, executor, this))
|
||||
register(SandboxMonthDaySerializer(classLoader, executor, this))
|
||||
register(SandboxOffsetDateTimeSerializer(classLoader, executor, this))
|
||||
register(SandboxOffsetTimeSerializer(classLoader, executor, this))
|
||||
register(SandboxPeriodSerializer(classLoader, executor, this))
|
||||
register(SandboxYearMonthSerializer(classLoader, executor, this))
|
||||
register(SandboxYearSerializer(classLoader, executor, this))
|
||||
register(SandboxZonedDateTimeSerializer(classLoader, executor, this))
|
||||
register(SandboxZoneIdSerializer(classLoader, executor, this))
|
||||
register(SandboxOptionalSerializer(classLoader, executor, this))
|
||||
register(SandboxPrimitiveSerializer(UUID::class.java, classLoader, sandboxBasicInput))
|
||||
register(SandboxPrimitiveSerializer(String::class.java, classLoader, sandboxBasicInput))
|
||||
register(SandboxPrimitiveSerializer(Byte::class.javaObjectType, classLoader, sandboxBasicInput))
|
||||
register(SandboxPrimitiveSerializer(Short::class.javaObjectType, classLoader, sandboxBasicInput))
|
||||
register(SandboxPrimitiveSerializer(Int::class.javaObjectType, classLoader, sandboxBasicInput))
|
||||
register(SandboxPrimitiveSerializer(Long::class.javaObjectType, classLoader, sandboxBasicInput))
|
||||
register(SandboxPrimitiveSerializer(Float::class.javaObjectType, classLoader, sandboxBasicInput))
|
||||
register(SandboxPrimitiveSerializer(Double::class.javaObjectType, classLoader, sandboxBasicInput))
|
||||
register(SandboxPrimitiveSerializer(Boolean::class.javaObjectType, classLoader, sandboxBasicInput))
|
||||
register(SandboxPrimitiveSerializer(Date::class.javaObjectType, classLoader, sandboxBasicInput))
|
||||
register(SandboxCharacterSerializer(classLoader, sandboxBasicInput))
|
||||
register(SandboxCollectionSerializer(classLoader, executor, this))
|
||||
register(SandboxMapSerializer(classLoader, executor, this))
|
||||
register(SandboxEnumSerializer(classLoader, executor, this))
|
||||
register(SandboxPublicKeySerializer(classLoader, executor))
|
||||
register(SandboxToStringSerializer(BigDecimal::class.java, classLoader, executor, sandboxBasicInput))
|
||||
register(SandboxToStringSerializer(BigInteger::class.java, classLoader, executor, sandboxBasicInput))
|
||||
register(SandboxToStringSerializer(StringBuffer::class.java, classLoader, executor, sandboxBasicInput))
|
||||
register(SandboxCurrencySerializer(classLoader, executor, sandboxBasicInput))
|
||||
register(SandboxX509CertificateSerializer(classLoader, executor))
|
||||
register(SandboxX509CRLSerializer(classLoader, executor))
|
||||
register(SandboxUnsignedLongSerializer(classLoader, executor))
|
||||
register(SandboxUnsignedIntegerSerializer(classLoader, executor))
|
||||
register(SandboxUnsignedShortSerializer(classLoader, executor))
|
||||
register(SandboxUnsignedByteSerializer(classLoader, executor))
|
||||
register(SandboxDecimal128Serializer(classLoader, executor))
|
||||
register(SandboxDecimal64Serializer(classLoader, executor))
|
||||
register(SandboxDecimal32Serializer(classLoader, executor))
|
||||
register(SandboxSymbolSerializer(classLoader, executor, sandboxBasicInput))
|
||||
}
|
||||
}
|
||||
|
||||
override fun <T : Any> deserialize(byteSequence: ByteSequence, clazz: Class<T>, context: SerializationContext): T {
|
||||
val serializerFactory = getSerializerFactory(context)
|
||||
return DeserializationInput(serializerFactory).deserialize(byteSequence, clazz, context)
|
||||
}
|
||||
|
||||
override fun <T : Any> serialize(obj: T, context: SerializationContext): SerializedBytes<T> {
|
||||
val serializerFactory = getSerializerFactory(context)
|
||||
return SerializationOutput(serializerFactory).serialize(obj, context)
|
||||
}
|
||||
|
||||
override fun canDeserializeVersion(magic: CordaSerializationMagic, target: UseCase): Boolean {
|
||||
return magic == amqpMagic && target == UseCase.P2P
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package net.corda.djvm.serialization
|
||||
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
|
||||
class DelegatingClassLoader(private val delegate: SandboxClassLoader) : ClassLoader(null) {
|
||||
@Throws(ClassNotFoundException::class)
|
||||
override fun loadClass(name: String, resolve: Boolean): Class<*> {
|
||||
return delegate.loadForSandbox(name).type
|
||||
}
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
@file:Suppress("platform_class_mapped_to_kotlin")
|
||||
package net.corda.djvm.serialization
|
||||
|
||||
import net.corda.core.serialization.SerializationContext
|
||||
import net.corda.serialization.internal.amqp.*
|
||||
import net.corda.serialization.internal.model.*
|
||||
import java.lang.Boolean
|
||||
import java.lang.Byte
|
||||
import java.lang.Double
|
||||
import java.lang.Float
|
||||
import java.lang.Long
|
||||
import java.lang.Short
|
||||
import java.util.Collections.singleton
|
||||
import java.util.Collections.unmodifiableMap
|
||||
import java.util.function.Function
|
||||
|
||||
/**
|
||||
* This has all been lovingly copied from [SerializerFactoryBuilder].
|
||||
*/
|
||||
class SandboxSerializerFactoryFactory(
|
||||
private val primitiveSerializerFactory: Function<Class<*>, AMQPSerializer<Any>>
|
||||
) : SerializerFactoryFactory {
|
||||
|
||||
override fun make(context: SerializationContext): SerializerFactory {
|
||||
val classLoader = context.deserializationClassLoader
|
||||
|
||||
val primitiveTypes = unmodifiableMap(mapOf<Class<*>, Class<*>>(
|
||||
classLoader.loadClass("sandbox.java.lang.Boolean") to Boolean.TYPE,
|
||||
classLoader.loadClass("sandbox.java.lang.Byte") to Byte.TYPE,
|
||||
classLoader.loadClass("sandbox.java.lang.Character") to Character.TYPE,
|
||||
classLoader.loadClass("sandbox.java.lang.Double") to Double.TYPE,
|
||||
classLoader.loadClass("sandbox.java.lang.Float") to Float.TYPE,
|
||||
classLoader.loadClass("sandbox.java.lang.Integer") to Integer.TYPE,
|
||||
classLoader.loadClass("sandbox.java.lang.Long") to Long.TYPE,
|
||||
classLoader.loadClass("sandbox.java.lang.Short") to Short.TYPE
|
||||
))
|
||||
|
||||
val classCarpenter = createClassCarpenter(context)
|
||||
val descriptorBasedSerializerRegistry = DefaultDescriptorBasedSerializerRegistry()
|
||||
val customSerializerRegistry = CachingCustomSerializerRegistry(
|
||||
descriptorBasedSerializerRegistry = descriptorBasedSerializerRegistry,
|
||||
allowedFor = singleton(classLoader.loadClass("sandbox.java.lang.Object"))
|
||||
)
|
||||
|
||||
val localTypeModel = ConfigurableLocalTypeModel(
|
||||
WhitelistBasedTypeModelConfiguration(context.whitelist, customSerializerRegistry)
|
||||
)
|
||||
|
||||
val fingerPrinter = TypeModellingFingerPrinter(customSerializerRegistry)
|
||||
|
||||
val localSerializerFactory = DefaultLocalSerializerFactory(
|
||||
whitelist = context.whitelist,
|
||||
typeModel = localTypeModel,
|
||||
fingerPrinter = fingerPrinter,
|
||||
classloader = classLoader,
|
||||
descriptorBasedSerializerRegistry = descriptorBasedSerializerRegistry,
|
||||
primitiveSerializerFactory = primitiveSerializerFactory,
|
||||
customSerializerRegistry = customSerializerRegistry,
|
||||
onlyCustomSerializers = false
|
||||
)
|
||||
|
||||
val typeLoader: TypeLoader = ClassCarpentingTypeLoader(
|
||||
carpenter = SchemaBuildingRemoteTypeCarpenter(classCarpenter),
|
||||
classLoader = classLoader
|
||||
)
|
||||
|
||||
val evolutionSerializerFactory = DefaultEvolutionSerializerFactory(
|
||||
localSerializerFactory = localSerializerFactory,
|
||||
classLoader = classLoader,
|
||||
mustPreserveDataWhenEvolving = context.preventDataLoss,
|
||||
primitiveTypes = primitiveTypes
|
||||
)
|
||||
|
||||
val remoteSerializerFactory = DefaultRemoteSerializerFactory(
|
||||
evolutionSerializerFactory = evolutionSerializerFactory,
|
||||
descriptorBasedSerializerRegistry = descriptorBasedSerializerRegistry,
|
||||
remoteTypeModel = AMQPRemoteTypeModel(),
|
||||
localTypeModel = localTypeModel,
|
||||
typeLoader = typeLoader,
|
||||
localSerializerFactory = localSerializerFactory
|
||||
)
|
||||
|
||||
return ComposedSerializerFactory(localSerializerFactory, remoteSerializerFactory, customSerializerRegistry)
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package net.corda.djvm.serialization
|
||||
|
||||
import net.corda.core.serialization.ClassWhitelist
|
||||
|
||||
class SandboxWhitelist : ClassWhitelist {
|
||||
companion object {
|
||||
private val packageName = "^sandbox\\.(?:java|kotlin)(?:[.]|$)".toRegex()
|
||||
}
|
||||
|
||||
override fun hasListed(type: Class<*>): Boolean {
|
||||
return packageName.containsMatchIn(type.`package`.name)
|
||||
}
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
@file:JvmName("Serialization")
|
||||
package net.corda.djvm.serialization
|
||||
|
||||
import net.corda.core.serialization.SerializationContext
|
||||
import net.corda.core.serialization.SerializationContext.UseCase
|
||||
import net.corda.core.serialization.SerializationFactory
|
||||
import net.corda.core.serialization.SerializedBytes
|
||||
import net.corda.core.serialization.internal.SerializationEnvironment
|
||||
import net.corda.djvm.execution.SandboxRuntimeException
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.djvm.serialization.serializers.PrimitiveSerializer
|
||||
import net.corda.djvm.source.ClassSource
|
||||
import net.corda.serialization.internal.GlobalTransientClassWhiteList
|
||||
import net.corda.serialization.internal.SerializationContextImpl
|
||||
import net.corda.serialization.internal.SerializationFactoryImpl
|
||||
import net.corda.serialization.internal.amqp.AMQPSerializer
|
||||
import net.corda.serialization.internal.amqp.amqpMagic
|
||||
import java.lang.reflect.InvocationTargetException
|
||||
import java.util.function.BiFunction
|
||||
import java.util.function.Function
|
||||
|
||||
fun SandboxClassLoader.loadClassForSandbox(clazz: Class<*>): Class<Any> {
|
||||
@Suppress("unchecked_cast")
|
||||
return loadClassForSandbox(ClassSource.fromClassName(clazz.name)) as Class<Any>
|
||||
}
|
||||
|
||||
fun createSandboxSerializationEnv(classLoader: SandboxClassLoader): SerializationEnvironment {
|
||||
val p2pContext: SerializationContext = SerializationContextImpl(
|
||||
preferredSerializationVersion = amqpMagic,
|
||||
deserializationClassLoader = DelegatingClassLoader(classLoader),
|
||||
whitelist = GlobalTransientClassWhiteList(SandboxWhitelist()),
|
||||
properties = emptyMap(),
|
||||
objectReferencesEnabled = true,
|
||||
carpenterDisabled = true,
|
||||
useCase = UseCase.P2P,
|
||||
encoding = null
|
||||
)
|
||||
|
||||
val taskClass = classLoader.loadClass("sandbox.RawTask")
|
||||
val taskApply = taskClass.getDeclaredMethod("apply", Any::class.java)
|
||||
val taskConstructor = taskClass.getDeclaredConstructor(classLoader.loadClassForSandbox(Function::class.java))
|
||||
val executor: BiFunction<in Any, in Any?, out Any?> = BiFunction { userTask, arg ->
|
||||
try {
|
||||
taskApply(taskConstructor.newInstance(userTask), arg)
|
||||
} catch (ex: InvocationTargetException) {
|
||||
val target = ex.targetException
|
||||
throw when (target) {
|
||||
is RuntimeException, is Error -> target
|
||||
else -> SandboxRuntimeException(target.message, target)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val sandboxBasicInput = classLoader.createBasicInput()
|
||||
|
||||
val primitiveSerializerFactory: Function<Class<*>, AMQPSerializer<Any>> = Function { clazz ->
|
||||
PrimitiveSerializer(clazz, sandboxBasicInput)
|
||||
}
|
||||
|
||||
val factory = SerializationFactoryImpl(mutableMapOf()).apply {
|
||||
registerScheme(AMQPSerializationScheme(
|
||||
classLoader = classLoader,
|
||||
sandboxBasicInput = sandboxBasicInput,
|
||||
executor = executor,
|
||||
serializerFactoryFactory = SandboxSerializerFactoryFactory(primitiveSerializerFactory)
|
||||
))
|
||||
}
|
||||
return SerializationEnvironment.with(factory, p2pContext = p2pContext)
|
||||
}
|
||||
|
||||
inline fun <reified T : Any> SerializedBytes<T>.deserializeFor(classLoader: SandboxClassLoader): Any {
|
||||
val clazz = classLoader.loadClassForSandbox(T::class.java)
|
||||
return deserializeTo(clazz, classLoader)
|
||||
}
|
||||
|
||||
fun SerializedBytes<*>.deserializeTo(clazz: Class<*>, classLoader: SandboxClassLoader): Any {
|
||||
return deserializeTo(clazz, classLoader, SerializationFactory.defaultFactory)
|
||||
}
|
||||
|
||||
fun SerializedBytes<*>.deserializeTo(clazz: Class<*>, classLoader: SandboxClassLoader, factory: SerializationFactory): Any {
|
||||
val obj = factory.deserialize(this, Any::class.java, factory.defaultContext)
|
||||
return if (clazz.isInstance(obj)) {
|
||||
obj
|
||||
} else {
|
||||
classLoader.createBasicInput().apply(obj)!!
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
@file:JvmName("ExceptionUtils")
|
||||
package net.corda.djvm.serialization.serializers
|
||||
|
||||
import net.corda.serialization.internal.amqp.AMQPNotSerializableException
|
||||
|
||||
/**
|
||||
* Utility function which helps tracking the path in the object graph when exceptions are thrown.
|
||||
* Since there might be a chain of nested calls it is useful to record which part of the graph caused an issue.
|
||||
* Path information is added to the message of the exception being thrown.
|
||||
*/
|
||||
internal inline fun <T> ifThrowsAppend(strToAppendFn: () -> String, block: () -> T): T {
|
||||
try {
|
||||
return block()
|
||||
} catch (th: Throwable) {
|
||||
when (th) {
|
||||
is AMQPNotSerializableException -> th.classHierarchy.add(strToAppendFn())
|
||||
// Do not overwrite the message of these exceptions as it may be used.
|
||||
is ClassNotFoundException -> {}
|
||||
is NoClassDefFoundError -> {}
|
||||
else -> th.resetMessage("${strToAppendFn()} -> ${th.message}")
|
||||
}
|
||||
throw th
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Not a public property so will have to use reflection
|
||||
*/
|
||||
private fun Throwable.resetMessage(newMsg: String) {
|
||||
val detailMessageField = Throwable::class.java.getDeclaredField("detailMessage")
|
||||
detailMessageField.isAccessible = true
|
||||
detailMessageField.set(this, newMsg)
|
||||
}
|
||||
|
||||
/**
|
||||
* We currently only support deserialisation, and so we're going to need this.
|
||||
*/
|
||||
fun abortReadOnly(): Nothing = throw UnsupportedOperationException("Read Only!")
|
@ -0,0 +1,28 @@
|
||||
package net.corda.djvm.serialization.serializers
|
||||
|
||||
import net.corda.core.serialization.SerializationContext
|
||||
import net.corda.serialization.internal.amqp.*
|
||||
import org.apache.qpid.proton.amqp.Binary
|
||||
import org.apache.qpid.proton.amqp.Symbol
|
||||
import org.apache.qpid.proton.codec.Data
|
||||
import java.lang.reflect.Type
|
||||
import java.util.function.Function
|
||||
|
||||
class PrimitiveSerializer(
|
||||
override val type: Class<*>,
|
||||
private val sandboxBasicInput: Function<in Any?, out Any?>
|
||||
) : AMQPSerializer<Any> {
|
||||
override val typeDescriptor: Symbol = typeDescriptorFor(type)
|
||||
|
||||
override fun readObject(obj: Any, schemas: SerializationSchemas, input: DeserializationInput, context: SerializationContext): Any {
|
||||
return (obj as? Binary)?.array ?: sandboxBasicInput.apply(obj)!!
|
||||
}
|
||||
|
||||
override fun writeClassInfo(output: SerializationOutput) {
|
||||
abortReadOnly()
|
||||
}
|
||||
|
||||
override fun writeObject(obj: Any, data: Data, type: Type, output: SerializationOutput, context: SerializationContext, debugIndent: Int) {
|
||||
abortReadOnly()
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package net.corda.djvm.serialization.serializers
|
||||
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.djvm.serialization.deserializers.BitSetDeserializer
|
||||
import net.corda.djvm.serialization.loadClassForSandbox
|
||||
import net.corda.serialization.internal.amqp.CustomSerializer
|
||||
import net.corda.serialization.internal.amqp.SerializerFactory
|
||||
import net.corda.serialization.internal.amqp.custom.BitSetSerializer.BitSetProxy
|
||||
import java.util.*
|
||||
import java.util.Collections.singleton
|
||||
import java.util.function.BiFunction
|
||||
|
||||
class SandboxBitSetSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
private val executor: BiFunction<in Any, in Any?, out Any?>,
|
||||
factory: SerializerFactory
|
||||
) : CustomSerializer.Proxy<Any, Any>(
|
||||
clazz = classLoader.loadClassForSandbox(BitSet::class.java),
|
||||
proxyClass = classLoader.loadClassForSandbox(BitSetProxy::class.java),
|
||||
factory = factory
|
||||
) {
|
||||
private val task = classLoader.loadClassForSandbox(BitSetDeserializer::class.java).newInstance()
|
||||
|
||||
override val deserializationAliases: Set<Class<*>> = singleton(BitSet::class.java)
|
||||
|
||||
override fun toProxy(obj: Any): Any = abortReadOnly()
|
||||
|
||||
override fun fromProxy(proxy: Any): Any {
|
||||
return executor.apply(task, proxy)!!
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package net.corda.djvm.serialization.serializers
|
||||
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.djvm.serialization.deserializers.CertPathDeserializer
|
||||
import net.corda.djvm.serialization.loadClassForSandbox
|
||||
import net.corda.serialization.internal.amqp.CustomSerializer
|
||||
import net.corda.serialization.internal.amqp.SerializerFactory
|
||||
import net.corda.serialization.internal.amqp.custom.CertPathSerializer.CertPathProxy
|
||||
import java.security.cert.CertPath
|
||||
import java.util.Collections.singleton
|
||||
import java.util.function.BiFunction
|
||||
|
||||
class SandboxCertPathSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
private val executor: BiFunction<in Any, in Any?, out Any?>,
|
||||
factory: SerializerFactory
|
||||
) : CustomSerializer.Proxy<Any, Any>(
|
||||
clazz = classLoader.loadClassForSandbox(CertPath::class.java),
|
||||
proxyClass = classLoader.loadClassForSandbox(CertPathProxy::class.java),
|
||||
factory = factory
|
||||
) {
|
||||
private val task = classLoader.loadClassForSandbox(CertPathDeserializer::class.java).newInstance()
|
||||
|
||||
override val deserializationAliases: Set<Class<*>> = singleton(CertPath::class.java)
|
||||
|
||||
override fun toProxy(obj: Any): Any = abortReadOnly()
|
||||
|
||||
override fun fromProxy(proxy: Any): Any {
|
||||
return executor.apply(task, proxy)!!
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package net.corda.djvm.serialization.serializers
|
||||
|
||||
import net.corda.core.serialization.SerializationContext
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.djvm.serialization.loadClassForSandbox
|
||||
import net.corda.serialization.internal.amqp.*
|
||||
import org.apache.qpid.proton.codec.Data
|
||||
import java.lang.reflect.Type
|
||||
import java.util.function.Function
|
||||
|
||||
class SandboxCharacterSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
private val basicInput: Function<in Any?, out Any?>
|
||||
) : CustomSerializer.Is<Any>(classLoader.loadClassForSandbox(Char::class.javaObjectType)) {
|
||||
|
||||
override val schemaForDocumentation: Schema = Schema(emptyList())
|
||||
|
||||
override fun readObject(obj: Any, schemas: SerializationSchemas, input: DeserializationInput, context: SerializationContext): Any {
|
||||
return basicInput.apply(convertToChar(obj))!!
|
||||
}
|
||||
|
||||
private fun convertToChar(obj: Any): Any {
|
||||
return when (obj) {
|
||||
is Short -> obj.toChar()
|
||||
is Int -> obj.toChar()
|
||||
else -> obj
|
||||
}
|
||||
}
|
||||
|
||||
override fun writeDescribedObject(obj: Any, data: Data, type: Type, output: SerializationOutput, context: SerializationContext) {
|
||||
abortReadOnly()
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
package net.corda.djvm.serialization.serializers
|
||||
|
||||
import net.corda.djvm.execution.SandboxRuntimeException
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.djvm.serialization.deserializers.ClassDeserializer
|
||||
import net.corda.djvm.serialization.loadClassForSandbox
|
||||
import net.corda.serialization.internal.amqp.AMQPNotSerializableException
|
||||
import net.corda.serialization.internal.amqp.CustomSerializer
|
||||
import net.corda.serialization.internal.amqp.SerializerFactory
|
||||
import net.corda.serialization.internal.amqp.custom.ClassSerializer.ClassProxy
|
||||
import java.util.function.BiFunction
|
||||
import java.util.function.Function
|
||||
|
||||
@Suppress("unchecked_cast")
|
||||
class SandboxClassSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
private val executor: BiFunction<in Any, in Any?, out Any?>,
|
||||
factory: SerializerFactory
|
||||
) : CustomSerializer.Proxy<Any, Any>(
|
||||
clazz = Class::class.java as Class<Any>,
|
||||
proxyClass = classLoader.loadClassForSandbox(ClassProxy::class.java),
|
||||
factory = factory
|
||||
) {
|
||||
private val task = classLoader.loadClassForSandbox(ClassDeserializer::class.java).newInstance()
|
||||
private val nameOf: Function<Any, String>
|
||||
|
||||
init {
|
||||
val fetch = proxyClass.getMethod("getClassName")
|
||||
nameOf = Function { proxy ->
|
||||
fetch(proxy).toString()
|
||||
}
|
||||
}
|
||||
|
||||
override fun toProxy(obj: Any): Any = abortReadOnly()
|
||||
|
||||
override fun fromProxy(proxy: Any): Any {
|
||||
return try {
|
||||
executor.apply(task, proxy)!!
|
||||
} catch (e: SandboxRuntimeException) {
|
||||
val cause = e.cause ?: throw e
|
||||
if (cause !is ClassNotFoundException) {
|
||||
throw cause
|
||||
}
|
||||
|
||||
val className = nameOf.apply(proxy)
|
||||
throw AMQPNotSerializableException(type,
|
||||
"Could not instantiate $className - not on the classpath",
|
||||
"$className was not found by the node, check the Node containing the CorDapp that " +
|
||||
"implements $className is loaded and on the Classpath",
|
||||
mutableListOf(className)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,120 @@
|
||||
package net.corda.djvm.serialization.serializers
|
||||
|
||||
import net.corda.core.serialization.SerializationContext
|
||||
import net.corda.core.utilities.NonEmptySet
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.djvm.serialization.deserializers.CreateCollection
|
||||
import net.corda.djvm.serialization.loadClassForSandbox
|
||||
import net.corda.serialization.internal.amqp.*
|
||||
import net.corda.serialization.internal.model.LocalTypeInformation
|
||||
import net.corda.serialization.internal.model.TypeIdentifier
|
||||
import org.apache.qpid.proton.amqp.Symbol
|
||||
import org.apache.qpid.proton.codec.Data
|
||||
import java.lang.reflect.ParameterizedType
|
||||
import java.lang.reflect.Type
|
||||
import java.util.*
|
||||
import java.util.function.BiFunction
|
||||
import java.util.function.Function
|
||||
|
||||
class SandboxCollectionSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
executor: BiFunction<in Any, in Any?, out Any?>,
|
||||
private val localFactory: LocalSerializerFactory
|
||||
) : CustomSerializer.Implements<Any>(clazz = classLoader.loadClassForSandbox(Collection::class.java)) {
|
||||
private val creator: Function<Array<Any>, out Any?>
|
||||
|
||||
init {
|
||||
val createTask = classLoader.loadClassForSandbox(CreateCollection::class.java).newInstance()
|
||||
creator = Function { inputs ->
|
||||
executor.apply(createTask, inputs)
|
||||
}
|
||||
}
|
||||
|
||||
private val unsupportedTypes: Set<Class<Any>> = listOf(
|
||||
EnumSet::class.java
|
||||
).map {
|
||||
classLoader.loadClassForSandbox(it)
|
||||
}.toSet()
|
||||
|
||||
// The order matters here - the first match should be the most specific one.
|
||||
// Kotlin preserves the ordering for us by associating into a LinkedHashMap.
|
||||
private val supportedTypes: Map<Class<Any>, Class<out Collection<*>>> = listOf(
|
||||
List::class.java,
|
||||
NonEmptySet::class.java,
|
||||
NavigableSet::class.java,
|
||||
SortedSet::class.java,
|
||||
Set::class.java,
|
||||
Collection::class.java
|
||||
).associateBy {
|
||||
classLoader.loadClassForSandbox(it)
|
||||
}
|
||||
|
||||
private fun getBestMatchFor(type: Class<Any>): Map.Entry<Class<Any>, Class<out Collection<*>>>
|
||||
= supportedTypes.entries.first { it.key.isAssignableFrom(type) }
|
||||
|
||||
override val schemaForDocumentation: Schema = Schema(emptyList())
|
||||
|
||||
override fun isSerializerFor(clazz: Class<*>): Boolean {
|
||||
return super.isSerializerFor(clazz) && unsupportedTypes.none { it.isAssignableFrom(clazz) }
|
||||
}
|
||||
|
||||
override fun specialiseFor(declaredType: Type): AMQPSerializer<Any>? {
|
||||
if (declaredType !is ParameterizedType) {
|
||||
return null
|
||||
}
|
||||
|
||||
@Suppress("unchecked_cast")
|
||||
val rawType = declaredType.rawType as Class<Any>
|
||||
return ConcreteCollectionSerializer(declaredType, getBestMatchFor(rawType), creator, localFactory)
|
||||
}
|
||||
|
||||
override fun readObject(obj: Any, schemas: SerializationSchemas, input: DeserializationInput, context: SerializationContext): Any {
|
||||
throw UnsupportedOperationException("Factory only")
|
||||
}
|
||||
|
||||
override fun writeDescribedObject(obj: Any, data: Data, type: Type, output: SerializationOutput, context: SerializationContext) {
|
||||
throw UnsupportedOperationException("Factory Only")
|
||||
}
|
||||
}
|
||||
|
||||
private class ConcreteCollectionSerializer(
|
||||
declaredType: ParameterizedType,
|
||||
private val matchingType: Map.Entry<Class<Any>, Class<out Collection<*>>>,
|
||||
private val creator: Function<Array<Any>, out Any?>,
|
||||
factory: LocalSerializerFactory
|
||||
) : AMQPSerializer<Any> {
|
||||
override val type: ParameterizedType = declaredType
|
||||
|
||||
override val typeDescriptor: Symbol by lazy {
|
||||
factory.createDescriptor(
|
||||
LocalTypeInformation.ACollection(
|
||||
observedType = declaredType.rawType,
|
||||
typeIdentifier = TypeIdentifier.forGenericType(declaredType),
|
||||
elementType =factory.getTypeInformation(declaredType.actualTypeArguments[0])
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override fun readObject(
|
||||
obj: Any,
|
||||
schemas: SerializationSchemas,
|
||||
input: DeserializationInput,
|
||||
context: SerializationContext
|
||||
): Any {
|
||||
val inboundType = type.actualTypeArguments[0]
|
||||
return ifThrowsAppend({ type.typeName }) {
|
||||
val args = (obj as List<*>).map {
|
||||
input.readObjectOrNull(redescribe(it, inboundType), schemas, inboundType, context)
|
||||
}.toTypedArray()
|
||||
creator.apply(arrayOf(matchingType.key, args))!!
|
||||
}
|
||||
}
|
||||
|
||||
override fun writeClassInfo(output: SerializationOutput) {
|
||||
abortReadOnly()
|
||||
}
|
||||
|
||||
override fun writeObject(obj: Any, data: Data, type: Type, output: SerializationOutput, context: SerializationContext, debugIndent: Int) {
|
||||
abortReadOnly()
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package net.corda.djvm.serialization.serializers
|
||||
|
||||
import net.corda.core.serialization.SerializationContext
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.djvm.serialization.deserializers.CreateCurrency
|
||||
import net.corda.djvm.serialization.loadClassForSandbox
|
||||
import net.corda.serialization.internal.amqp.*
|
||||
import org.apache.qpid.proton.codec.Data
|
||||
import java.lang.reflect.Type
|
||||
import java.util.*
|
||||
import java.util.function.BiFunction
|
||||
import java.util.function.Function
|
||||
|
||||
class SandboxCurrencySerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
executor: BiFunction<in Any, in Any?, out Any?>,
|
||||
basicInput: Function<in Any?, out Any?>
|
||||
) : CustomSerializer.Is<Any>(classLoader.loadClassForSandbox(Currency::class.java)) {
|
||||
private val creator: Function<Any?, Any?>
|
||||
|
||||
init {
|
||||
val createTask = classLoader.loadClassForSandbox(CreateCurrency::class.java).newInstance()
|
||||
creator = basicInput.andThen { input ->
|
||||
executor.apply(createTask, input)
|
||||
}
|
||||
}
|
||||
|
||||
override val deserializationAliases: Set<Class<*>> = Collections.singleton(Currency::class.java)
|
||||
|
||||
override val schemaForDocumentation: Schema = Schema(emptyList())
|
||||
|
||||
override fun readObject(obj: Any, schemas: SerializationSchemas, input: DeserializationInput, context: SerializationContext): Any {
|
||||
return creator.apply(obj)!!
|
||||
}
|
||||
|
||||
override fun writeDescribedObject(obj: Any, data: Data, type: Type, output: SerializationOutput, context: SerializationContext) {
|
||||
abortReadOnly()
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package net.corda.djvm.serialization.serializers
|
||||
|
||||
import net.corda.core.serialization.SerializationContext
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.djvm.serialization.deserializers.Decimal128Deserializer
|
||||
import net.corda.djvm.serialization.loadClassForSandbox
|
||||
import net.corda.serialization.internal.amqp.*
|
||||
import org.apache.qpid.proton.amqp.Decimal128
|
||||
import org.apache.qpid.proton.codec.Data
|
||||
import java.lang.reflect.Type
|
||||
import java.util.function.BiFunction
|
||||
import java.util.function.Function
|
||||
|
||||
class SandboxDecimal128Serializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
executor: BiFunction<in Any, in Any?, out Any?>
|
||||
) : CustomSerializer.Is<Any>(classLoader.loadClassForSandbox(Decimal128::class.java)) {
|
||||
private val transformer: Function<LongArray, out Any?>
|
||||
|
||||
init {
|
||||
val transformTask = classLoader.loadClassForSandbox(Decimal128Deserializer::class.java).newInstance()
|
||||
transformer = Function { inputs ->
|
||||
executor.apply(transformTask, inputs)
|
||||
}
|
||||
}
|
||||
|
||||
override val schemaForDocumentation: Schema = Schema(emptyList())
|
||||
|
||||
override fun readObject(obj: Any, schemas: SerializationSchemas, input: DeserializationInput, context: SerializationContext): Any {
|
||||
val decimal128 = obj as Decimal128
|
||||
return transformer.apply(longArrayOf(decimal128.mostSignificantBits, decimal128.leastSignificantBits))!!
|
||||
}
|
||||
|
||||
override fun writeDescribedObject(obj: Any, data: Data, type: Type, output: SerializationOutput, context: SerializationContext) {
|
||||
abortReadOnly()
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package net.corda.djvm.serialization.serializers
|
||||
|
||||
import net.corda.core.serialization.SerializationContext
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.djvm.serialization.deserializers.Decimal32Deserializer
|
||||
import net.corda.djvm.serialization.loadClassForSandbox
|
||||
import net.corda.serialization.internal.amqp.*
|
||||
import org.apache.qpid.proton.amqp.Decimal32
|
||||
import org.apache.qpid.proton.codec.Data
|
||||
import java.lang.reflect.Type
|
||||
import java.util.function.BiFunction
|
||||
import java.util.function.Function
|
||||
|
||||
class SandboxDecimal32Serializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
executor: BiFunction<in Any, in Any?, out Any?>
|
||||
) : CustomSerializer.Is<Any>(classLoader.loadClassForSandbox(Decimal32::class.java)) {
|
||||
private val transformer: Function<IntArray, out Any?>
|
||||
|
||||
init {
|
||||
val transformTask = classLoader.loadClassForSandbox(Decimal32Deserializer::class.java).newInstance()
|
||||
transformer = Function { inputs ->
|
||||
executor.apply(transformTask, inputs)
|
||||
}
|
||||
}
|
||||
|
||||
override val schemaForDocumentation: Schema = Schema(emptyList())
|
||||
|
||||
override fun readObject(obj: Any, schemas: SerializationSchemas, input: DeserializationInput, context: SerializationContext): Any {
|
||||
return transformer.apply(intArrayOf((obj as Decimal32).bits))!!
|
||||
}
|
||||
|
||||
override fun writeDescribedObject(obj: Any, data: Data, type: Type, output: SerializationOutput, context: SerializationContext) {
|
||||
abortReadOnly()
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package net.corda.djvm.serialization.serializers
|
||||
|
||||
import net.corda.core.serialization.SerializationContext
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.djvm.serialization.deserializers.Decimal64Deserializer
|
||||
import net.corda.djvm.serialization.loadClassForSandbox
|
||||
import net.corda.serialization.internal.amqp.*
|
||||
import org.apache.qpid.proton.amqp.Decimal64
|
||||
import org.apache.qpid.proton.codec.Data
|
||||
import java.lang.reflect.Type
|
||||
import java.util.function.BiFunction
|
||||
import java.util.function.Function
|
||||
|
||||
class SandboxDecimal64Serializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
executor: BiFunction<in Any, in Any?, out Any?>
|
||||
) : CustomSerializer.Is<Any>(classLoader.loadClassForSandbox(Decimal64::class.java)) {
|
||||
private val transformer: Function<LongArray, out Any?>
|
||||
|
||||
init {
|
||||
val transformTask = classLoader.loadClassForSandbox(Decimal64Deserializer::class.java).newInstance()
|
||||
transformer = Function { inputs ->
|
||||
executor.apply(transformTask, inputs)
|
||||
}
|
||||
}
|
||||
|
||||
override val schemaForDocumentation: Schema = Schema(emptyList())
|
||||
|
||||
override fun readObject(obj: Any, schemas: SerializationSchemas, input: DeserializationInput, context: SerializationContext): Any {
|
||||
return transformer.apply(longArrayOf((obj as Decimal64).bits))!!
|
||||
}
|
||||
|
||||
override fun writeDescribedObject(obj: Any, data: Data, type: Type, output: SerializationOutput, context: SerializationContext) {
|
||||
abortReadOnly()
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package net.corda.djvm.serialization.serializers
|
||||
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.djvm.serialization.deserializers.DurationDeserializer
|
||||
import net.corda.djvm.serialization.loadClassForSandbox
|
||||
import net.corda.serialization.internal.amqp.CustomSerializer
|
||||
import net.corda.serialization.internal.amqp.SerializerFactory
|
||||
import net.corda.serialization.internal.amqp.custom.DurationSerializer.DurationProxy
|
||||
import java.time.Duration
|
||||
import java.util.Collections.singleton
|
||||
import java.util.function.BiFunction
|
||||
|
||||
class SandboxDurationSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
private val executor: BiFunction<in Any, in Any?, out Any?>,
|
||||
factory: SerializerFactory
|
||||
) : CustomSerializer.Proxy<Any, Any>(
|
||||
clazz = classLoader.loadClassForSandbox(Duration::class.java),
|
||||
proxyClass = classLoader.loadClassForSandbox(DurationProxy::class.java),
|
||||
factory = factory
|
||||
) {
|
||||
private val task = classLoader.loadClassForSandbox(DurationDeserializer::class.java).newInstance()
|
||||
|
||||
override val deserializationAliases: Set<Class<*>> = singleton(Duration::class.java)
|
||||
|
||||
override fun toProxy(obj: Any): Any = abortReadOnly()
|
||||
|
||||
override fun fromProxy(proxy: Any): Any {
|
||||
return executor.apply(task, proxy)!!
|
||||
}
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
package net.corda.djvm.serialization.serializers
|
||||
|
||||
import net.corda.core.serialization.SerializationContext
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.djvm.serialization.deserializers.DescribeEnum
|
||||
import net.corda.djvm.serialization.loadClassForSandbox
|
||||
import net.corda.serialization.internal.amqp.*
|
||||
import net.corda.serialization.internal.model.EnumTransforms
|
||||
import net.corda.serialization.internal.model.LocalTypeInformation
|
||||
import net.corda.serialization.internal.model.TypeIdentifier
|
||||
import org.apache.qpid.proton.amqp.Symbol
|
||||
import org.apache.qpid.proton.codec.Data
|
||||
import java.lang.reflect.Type
|
||||
import java.util.function.BiFunction
|
||||
import java.util.function.Function
|
||||
|
||||
class SandboxEnumSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
executor: BiFunction<in Any, in Any?, out Any?>,
|
||||
private val localFactory: LocalSerializerFactory
|
||||
) : CustomSerializer.Implements<Any>(clazz = classLoader.loadClassForSandbox(Enum::class.java)) {
|
||||
private val describer: Function<Class<*>, Array<Any>>
|
||||
|
||||
init {
|
||||
val describeTask = classLoader.loadClassForSandbox(DescribeEnum::class.java).newInstance()
|
||||
describer = Function { inputs ->
|
||||
@Suppress("unchecked_cast")
|
||||
executor.apply(describeTask, inputs) as Array<Any>
|
||||
}
|
||||
}
|
||||
|
||||
override val schemaForDocumentation: Schema = Schema(emptyList())
|
||||
|
||||
override fun specialiseFor(declaredType: Type): AMQPSerializer<Any>? {
|
||||
if (declaredType !is Class<*>) {
|
||||
return null
|
||||
}
|
||||
val members = describer.apply(declaredType)
|
||||
return ConcreteEnumSerializer(declaredType, members, localFactory)
|
||||
}
|
||||
|
||||
override fun readObject(obj: Any, schemas: SerializationSchemas, input: DeserializationInput, context: SerializationContext): Any {
|
||||
throw UnsupportedOperationException("Factory only")
|
||||
}
|
||||
|
||||
override fun writeDescribedObject(obj: Any, data: Data, type: Type, output: SerializationOutput, context: SerializationContext) {
|
||||
throw UnsupportedOperationException("Factory Only")
|
||||
}
|
||||
}
|
||||
|
||||
private class ConcreteEnumSerializer(
|
||||
declaredType: Class<*>,
|
||||
private val members: Array<Any>,
|
||||
factory: LocalSerializerFactory
|
||||
) : AMQPSerializer<Any> {
|
||||
override val type: Class<*> = declaredType
|
||||
|
||||
override val typeDescriptor: Symbol by lazy {
|
||||
factory.createDescriptor(
|
||||
/*
|
||||
* Partially populated, providing just the information
|
||||
* required by the fingerprinter.
|
||||
*/
|
||||
LocalTypeInformation.AnEnum(
|
||||
declaredType,
|
||||
TypeIdentifier.forGenericType(declaredType),
|
||||
members.map { it.toString() },
|
||||
emptyList(),
|
||||
EnumTransforms.empty
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override fun readObject(obj: Any, schemas: SerializationSchemas, input: DeserializationInput, context: SerializationContext): Any {
|
||||
val enumName = (obj as List<*>)[0] as String
|
||||
val enumOrd = obj[1] as Int
|
||||
val fromOrd = members[enumOrd]
|
||||
|
||||
if (enumName != fromOrd.toString()) {
|
||||
throw AMQPNotSerializableException(
|
||||
type,
|
||||
"Deserializing obj as enum $type with value $enumName.$enumOrd but ordinality has changed"
|
||||
)
|
||||
}
|
||||
return fromOrd
|
||||
}
|
||||
|
||||
override fun writeClassInfo(output: SerializationOutput) {
|
||||
abortReadOnly()
|
||||
}
|
||||
|
||||
override fun writeObject(obj: Any, data: Data, type: Type, output: SerializationOutput, context: SerializationContext, debugIndent: Int) {
|
||||
abortReadOnly()
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package net.corda.djvm.serialization.serializers
|
||||
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.djvm.serialization.deserializers.EnumSetDeserializer
|
||||
import net.corda.djvm.serialization.loadClassForSandbox
|
||||
import net.corda.serialization.internal.amqp.CustomSerializer
|
||||
import net.corda.serialization.internal.amqp.SerializerFactory
|
||||
import net.corda.serialization.internal.amqp.custom.EnumSetSerializer.EnumSetProxy
|
||||
import java.util.*
|
||||
import java.util.Collections.singleton
|
||||
import java.util.function.BiFunction
|
||||
|
||||
class SandboxEnumSetSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
private val executor: BiFunction<in Any, in Any?, out Any?>,
|
||||
factory: SerializerFactory
|
||||
) : CustomSerializer.Proxy<Any, Any>(
|
||||
clazz = classLoader.loadClassForSandbox(EnumSet::class.java),
|
||||
proxyClass = classLoader.loadClassForSandbox(EnumSetProxy::class.java),
|
||||
factory = factory
|
||||
) {
|
||||
private val task = classLoader.loadClassForSandbox(EnumSetDeserializer::class.java).newInstance()
|
||||
|
||||
override val additionalSerializers: Set<CustomSerializer<out Any>> = singleton(
|
||||
SandboxClassSerializer(classLoader, executor, factory)
|
||||
)
|
||||
|
||||
override val deserializationAliases: Set<Class<*>> = singleton(EnumSet::class.java)
|
||||
|
||||
override fun toProxy(obj: Any): Any = abortReadOnly()
|
||||
|
||||
override fun fromProxy(proxy: Any): Any {
|
||||
return executor.apply(task, proxy)!!
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package net.corda.djvm.serialization.serializers
|
||||
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.djvm.serialization.deserializers.InstantDeserializer
|
||||
import net.corda.djvm.serialization.loadClassForSandbox
|
||||
import net.corda.serialization.internal.amqp.CustomSerializer
|
||||
import net.corda.serialization.internal.amqp.SerializerFactory
|
||||
import net.corda.serialization.internal.amqp.custom.InstantSerializer.InstantProxy
|
||||
import java.time.Instant
|
||||
import java.util.Collections.singleton
|
||||
import java.util.function.BiFunction
|
||||
|
||||
class SandboxInstantSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
private val executor: BiFunction<in Any, in Any?, out Any?>,
|
||||
factory: SerializerFactory
|
||||
) : CustomSerializer.Proxy<Any, Any>(
|
||||
clazz = classLoader.loadClassForSandbox(Instant::class.java),
|
||||
proxyClass = classLoader.loadClassForSandbox(InstantProxy::class.java),
|
||||
factory = factory
|
||||
) {
|
||||
private val task = classLoader.loadClassForSandbox(InstantDeserializer::class.java).newInstance()
|
||||
|
||||
override val deserializationAliases: Set<Class<*>> = singleton(Instant::class.java)
|
||||
|
||||
override fun toProxy(obj: Any): Any = abortReadOnly()
|
||||
|
||||
override fun fromProxy(proxy: Any): Any {
|
||||
return executor.apply(task, proxy)!!
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package net.corda.djvm.serialization.serializers
|
||||
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.djvm.serialization.deserializers.LocalDateDeserializer
|
||||
import net.corda.djvm.serialization.loadClassForSandbox
|
||||
import net.corda.serialization.internal.amqp.CustomSerializer
|
||||
import net.corda.serialization.internal.amqp.SerializerFactory
|
||||
import net.corda.serialization.internal.amqp.custom.LocalDateSerializer.LocalDateProxy
|
||||
import java.time.LocalDate
|
||||
import java.util.Collections.singleton
|
||||
import java.util.function.BiFunction
|
||||
|
||||
class SandboxLocalDateSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
private val executor: BiFunction<in Any, in Any?, out Any?>,
|
||||
factory: SerializerFactory
|
||||
) : CustomSerializer.Proxy<Any, Any>(
|
||||
clazz = classLoader.loadClassForSandbox(LocalDate::class.java),
|
||||
proxyClass = classLoader.loadClassForSandbox(LocalDateProxy::class.java),
|
||||
factory = factory
|
||||
) {
|
||||
private val task = classLoader.loadClassForSandbox(LocalDateDeserializer::class.java).newInstance()
|
||||
|
||||
override val deserializationAliases: Set<Class<*>> = singleton(LocalDate::class.java)
|
||||
|
||||
override fun toProxy(obj: Any): Any = abortReadOnly()
|
||||
|
||||
override fun fromProxy(proxy: Any): Any {
|
||||
return executor.apply(task, proxy)!!
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package net.corda.djvm.serialization.serializers
|
||||
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.djvm.serialization.deserializers.LocalDateTimeDeserializer
|
||||
import net.corda.djvm.serialization.loadClassForSandbox
|
||||
import net.corda.serialization.internal.amqp.CustomSerializer
|
||||
import net.corda.serialization.internal.amqp.SerializerFactory
|
||||
import net.corda.serialization.internal.amqp.custom.LocalDateTimeSerializer.LocalDateTimeProxy
|
||||
import java.time.LocalDateTime
|
||||
import java.util.Collections.singleton
|
||||
import java.util.function.BiFunction
|
||||
|
||||
class SandboxLocalDateTimeSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
private val executor: BiFunction<in Any, in Any?, out Any?>,
|
||||
factory: SerializerFactory
|
||||
) : CustomSerializer.Proxy<Any, Any>(
|
||||
clazz = classLoader.loadClassForSandbox(LocalDateTime::class.java),
|
||||
proxyClass = classLoader.loadClassForSandbox(LocalDateTimeProxy::class.java),
|
||||
factory = factory
|
||||
) {
|
||||
private val task = classLoader.loadClassForSandbox(LocalDateTimeDeserializer::class.java).newInstance()
|
||||
|
||||
override val deserializationAliases: Set<Class<*>> = singleton(LocalDateTime::class.java)
|
||||
|
||||
override fun toProxy(obj: Any): Any = abortReadOnly()
|
||||
|
||||
override fun fromProxy(proxy: Any): Any {
|
||||
return executor.apply(task, proxy)!!
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package net.corda.djvm.serialization.serializers
|
||||
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.djvm.serialization.deserializers.LocalTimeDeserializer
|
||||
import net.corda.djvm.serialization.loadClassForSandbox
|
||||
import net.corda.serialization.internal.amqp.CustomSerializer
|
||||
import net.corda.serialization.internal.amqp.SerializerFactory
|
||||
import net.corda.serialization.internal.amqp.custom.LocalTimeSerializer.LocalTimeProxy
|
||||
import java.time.LocalTime
|
||||
import java.util.Collections.singleton
|
||||
import java.util.function.BiFunction
|
||||
|
||||
class SandboxLocalTimeSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
private val executor: BiFunction<in Any, in Any?, out Any?>,
|
||||
factory: SerializerFactory
|
||||
) : CustomSerializer.Proxy<Any, Any>(
|
||||
clazz = classLoader.loadClassForSandbox(LocalTime::class.java),
|
||||
proxyClass = classLoader.loadClassForSandbox(LocalTimeProxy::class.java),
|
||||
factory = factory
|
||||
) {
|
||||
private val task = classLoader.loadClassForSandbox(LocalTimeDeserializer::class.java).newInstance()
|
||||
|
||||
override val deserializationAliases: Set<Class<*>> = singleton(LocalTime::class.java)
|
||||
|
||||
override fun toProxy(obj: Any): Any = abortReadOnly()
|
||||
|
||||
override fun fromProxy(proxy: Any): Any {
|
||||
return executor.apply(task, proxy)!!
|
||||
}
|
||||
}
|
@ -0,0 +1,114 @@
|
||||
package net.corda.djvm.serialization.serializers
|
||||
|
||||
import net.corda.core.serialization.SerializationContext
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.djvm.serialization.deserializers.CreateMap
|
||||
import net.corda.djvm.serialization.loadClassForSandbox
|
||||
import net.corda.serialization.internal.amqp.*
|
||||
import net.corda.serialization.internal.model.LocalTypeInformation
|
||||
import net.corda.serialization.internal.model.TypeIdentifier
|
||||
import org.apache.qpid.proton.amqp.Symbol
|
||||
import org.apache.qpid.proton.codec.Data
|
||||
import java.lang.reflect.ParameterizedType
|
||||
import java.lang.reflect.Type
|
||||
import java.util.*
|
||||
import java.util.function.BiFunction
|
||||
import java.util.function.Function
|
||||
|
||||
class SandboxMapSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
executor: BiFunction<in Any, in Any?, out Any?>,
|
||||
private val localFactory: LocalSerializerFactory
|
||||
) : CustomSerializer.Implements<Any>(clazz = classLoader.loadClassForSandbox(Map::class.java)) {
|
||||
private val creator: Function<Array<Any>, out Any?>
|
||||
|
||||
init {
|
||||
val createTask = classLoader.loadClassForSandbox(CreateMap::class.java).newInstance()
|
||||
creator = Function { inputs ->
|
||||
executor.apply(createTask, inputs)
|
||||
}
|
||||
}
|
||||
|
||||
// The order matters here - the first match should be the most specific one.
|
||||
// Kotlin preserves the ordering for us by associating into a LinkedHashMap.
|
||||
private val supportedTypes: Map<Class<Any>, Class<out Map<*, *>>> = listOf(
|
||||
TreeMap::class.java,
|
||||
LinkedHashMap::class.java,
|
||||
NavigableMap::class.java,
|
||||
SortedMap::class.java,
|
||||
EnumMap::class.java,
|
||||
Map::class.java
|
||||
).associateBy {
|
||||
classLoader.loadClassForSandbox(it)
|
||||
}
|
||||
|
||||
private fun getBestMatchFor(type: Class<Any>): Map.Entry<Class<Any>, Class<out Map<*, *>>>
|
||||
= supportedTypes.entries.first { it.key.isAssignableFrom(type) }
|
||||
|
||||
override val schemaForDocumentation: Schema = Schema(emptyList())
|
||||
|
||||
override fun specialiseFor(declaredType: Type): AMQPSerializer<Any>? {
|
||||
if (declaredType !is ParameterizedType) {
|
||||
return null
|
||||
}
|
||||
|
||||
@Suppress("unchecked_cast")
|
||||
val rawType = declaredType.rawType as Class<Any>
|
||||
return ConcreteMapSerializer(declaredType, getBestMatchFor(rawType), creator, localFactory)
|
||||
}
|
||||
|
||||
override fun readObject(obj: Any, schemas: SerializationSchemas, input: DeserializationInput, context: SerializationContext): Any {
|
||||
throw UnsupportedOperationException("Factory only")
|
||||
}
|
||||
|
||||
override fun writeDescribedObject(obj: Any, data: Data, type: Type, output: SerializationOutput, context: SerializationContext) {
|
||||
throw UnsupportedOperationException("Factory Only")
|
||||
}
|
||||
}
|
||||
|
||||
private class ConcreteMapSerializer(
|
||||
declaredType: ParameterizedType,
|
||||
private val matchingType: Map.Entry<Class<Any>, Class<out Map<*, *>>>,
|
||||
private val creator: Function<Array<Any>, out Any?>,
|
||||
factory: LocalSerializerFactory
|
||||
) : AMQPSerializer<Any> {
|
||||
override val type: ParameterizedType = declaredType
|
||||
|
||||
override val typeDescriptor: Symbol by lazy {
|
||||
factory.createDescriptor(
|
||||
LocalTypeInformation.AMap(
|
||||
observedType = declaredType.rawType,
|
||||
typeIdentifier = TypeIdentifier.forGenericType(declaredType),
|
||||
keyType =factory.getTypeInformation(declaredType.actualTypeArguments[0]),
|
||||
valueType = factory.getTypeInformation(declaredType.actualTypeArguments[1])
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override fun readObject(
|
||||
obj: Any,
|
||||
schemas: SerializationSchemas,
|
||||
input: DeserializationInput,
|
||||
context: SerializationContext
|
||||
): Any {
|
||||
val inboundKeyType = type.actualTypeArguments[0]
|
||||
val inboundValueType = type.actualTypeArguments[1]
|
||||
return ifThrowsAppend({ type.typeName }) {
|
||||
val entries = (obj as Map<*, *>).map {
|
||||
arrayOf(
|
||||
input.readObjectOrNull(redescribe(it.key, inboundKeyType), schemas, inboundKeyType, context),
|
||||
input.readObjectOrNull(redescribe(it.value, inboundValueType), schemas, inboundValueType, context)
|
||||
)
|
||||
}.toTypedArray()
|
||||
creator.apply(arrayOf(matchingType.key, entries))!!
|
||||
}
|
||||
}
|
||||
|
||||
override fun writeClassInfo(output: SerializationOutput) {
|
||||
abortReadOnly()
|
||||
}
|
||||
|
||||
override fun writeObject(obj: Any, data: Data, type: Type, output: SerializationOutput, context: SerializationContext, debugIndent: Int) {
|
||||
abortReadOnly()
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package net.corda.djvm.serialization.serializers
|
||||
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.djvm.serialization.deserializers.MonthDayDeserializer
|
||||
import net.corda.djvm.serialization.loadClassForSandbox
|
||||
import net.corda.serialization.internal.amqp.CustomSerializer
|
||||
import net.corda.serialization.internal.amqp.SerializerFactory
|
||||
import net.corda.serialization.internal.amqp.custom.MonthDaySerializer.MonthDayProxy
|
||||
import java.time.MonthDay
|
||||
import java.util.Collections.singleton
|
||||
import java.util.function.BiFunction
|
||||
|
||||
class SandboxMonthDaySerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
private val executor: BiFunction<in Any, in Any?, out Any?>,
|
||||
factory: SerializerFactory
|
||||
) : CustomSerializer.Proxy<Any, Any>(
|
||||
clazz = classLoader.loadClassForSandbox(MonthDay::class.java),
|
||||
proxyClass = classLoader.loadClassForSandbox(MonthDayProxy::class.java),
|
||||
factory = factory
|
||||
) {
|
||||
private val task = classLoader.loadClassForSandbox(MonthDayDeserializer::class.java).newInstance()
|
||||
|
||||
override val deserializationAliases: Set<Class<*>> = singleton(MonthDay::class.java)
|
||||
|
||||
override fun toProxy(obj: Any): Any = abortReadOnly()
|
||||
|
||||
override fun fromProxy(proxy: Any): Any {
|
||||
return executor.apply(task, proxy)!!
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package net.corda.djvm.serialization.serializers
|
||||
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.djvm.serialization.deserializers.OffsetDateTimeDeserializer
|
||||
import net.corda.djvm.serialization.loadClassForSandbox
|
||||
import net.corda.serialization.internal.amqp.CustomSerializer
|
||||
import net.corda.serialization.internal.amqp.SerializerFactory
|
||||
import net.corda.serialization.internal.amqp.custom.OffsetDateTimeSerializer.OffsetDateTimeProxy
|
||||
import java.time.OffsetDateTime
|
||||
import java.util.Collections.singleton
|
||||
import java.util.function.BiFunction
|
||||
|
||||
class SandboxOffsetDateTimeSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
private val executor: BiFunction<in Any, in Any?, out Any?>,
|
||||
factory: SerializerFactory
|
||||
) : CustomSerializer.Proxy<Any, Any>(
|
||||
clazz = classLoader.loadClassForSandbox(OffsetDateTime::class.java),
|
||||
proxyClass = classLoader.loadClassForSandbox(OffsetDateTimeProxy::class.java),
|
||||
factory = factory
|
||||
) {
|
||||
private val task = classLoader.loadClassForSandbox(OffsetDateTimeDeserializer::class.java).newInstance()
|
||||
|
||||
override val deserializationAliases: Set<Class<*>> = singleton(OffsetDateTime::class.java)
|
||||
|
||||
override fun toProxy(obj: Any): Any = abortReadOnly()
|
||||
|
||||
override fun fromProxy(proxy: Any): Any {
|
||||
return executor.apply(task, proxy)!!
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package net.corda.djvm.serialization.serializers
|
||||
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.djvm.serialization.deserializers.OffsetTimeDeserializer
|
||||
import net.corda.djvm.serialization.loadClassForSandbox
|
||||
import net.corda.serialization.internal.amqp.CustomSerializer
|
||||
import net.corda.serialization.internal.amqp.SerializerFactory
|
||||
import net.corda.serialization.internal.amqp.custom.OffsetTimeSerializer.OffsetTimeProxy
|
||||
import java.time.OffsetTime
|
||||
import java.util.Collections.singleton
|
||||
import java.util.function.BiFunction
|
||||
|
||||
class SandboxOffsetTimeSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
private val executor: BiFunction<in Any, in Any?, out Any?>,
|
||||
factory: SerializerFactory
|
||||
) : CustomSerializer.Proxy<Any, Any>(
|
||||
clazz = classLoader.loadClassForSandbox(OffsetTime::class.java),
|
||||
proxyClass = classLoader.loadClassForSandbox(OffsetTimeProxy::class.java),
|
||||
factory = factory
|
||||
) {
|
||||
private val task = classLoader.loadClassForSandbox(OffsetTimeDeserializer::class.java).newInstance()
|
||||
|
||||
override val deserializationAliases: Set<Class<*>> = singleton(OffsetTime::class.java)
|
||||
|
||||
override fun toProxy(obj: Any): Any = abortReadOnly()
|
||||
|
||||
override fun fromProxy(proxy: Any): Any {
|
||||
return executor.apply(task, proxy)!!
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package net.corda.djvm.serialization.serializers
|
||||
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.djvm.serialization.deserializers.OptionalDeserializer
|
||||
import net.corda.djvm.serialization.loadClassForSandbox
|
||||
import net.corda.serialization.internal.amqp.CustomSerializer
|
||||
import net.corda.serialization.internal.amqp.SerializerFactory
|
||||
import net.corda.serialization.internal.amqp.custom.OptionalSerializer.OptionalProxy
|
||||
import java.util.*
|
||||
import java.util.Collections.singleton
|
||||
import java.util.function.BiFunction
|
||||
|
||||
class SandboxOptionalSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
private val executor: BiFunction<in Any, in Any?, out Any?>,
|
||||
factory: SerializerFactory
|
||||
) : CustomSerializer.Proxy<Any, Any>(
|
||||
clazz = classLoader.loadClassForSandbox(Optional::class.java),
|
||||
proxyClass = classLoader.loadClassForSandbox(OptionalProxy::class.java),
|
||||
factory = factory
|
||||
) {
|
||||
private val task = classLoader.loadClassForSandbox(OptionalDeserializer::class.java).newInstance()
|
||||
|
||||
override val deserializationAliases: Set<Class<*>> = singleton(Optional::class.java)
|
||||
|
||||
override fun toProxy(obj: Any): Any = abortReadOnly()
|
||||
|
||||
override fun fromProxy(proxy: Any): Any {
|
||||
return executor.apply(task, proxy)!!
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package net.corda.djvm.serialization.serializers
|
||||
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.djvm.serialization.deserializers.PeriodDeserializer
|
||||
import net.corda.djvm.serialization.loadClassForSandbox
|
||||
import net.corda.serialization.internal.amqp.CustomSerializer
|
||||
import net.corda.serialization.internal.amqp.SerializerFactory
|
||||
import net.corda.serialization.internal.amqp.custom.PeriodSerializer.PeriodProxy
|
||||
import java.time.Period
|
||||
import java.util.Collections.singleton
|
||||
import java.util.function.BiFunction
|
||||
|
||||
class SandboxPeriodSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
private val executor: BiFunction<in Any, in Any?, out Any?>,
|
||||
factory: SerializerFactory
|
||||
) : CustomSerializer.Proxy<Any, Any>(
|
||||
clazz = classLoader.loadClassForSandbox(Period::class.java),
|
||||
proxyClass = classLoader.loadClassForSandbox(PeriodProxy::class.java),
|
||||
factory = factory
|
||||
) {
|
||||
private val task = classLoader.loadClassForSandbox(PeriodDeserializer::class.java).newInstance()
|
||||
|
||||
override val deserializationAliases: Set<Class<*>> = singleton(Period::class.java)
|
||||
|
||||
override fun toProxy(obj: Any): Any = abortReadOnly()
|
||||
|
||||
override fun fromProxy(proxy: Any): Any {
|
||||
return executor.apply(task, proxy)!!
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package net.corda.djvm.serialization.serializers
|
||||
|
||||
import net.corda.core.serialization.SerializationContext
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.djvm.serialization.loadClassForSandbox
|
||||
import net.corda.serialization.internal.amqp.*
|
||||
import org.apache.qpid.proton.codec.Data
|
||||
import java.lang.reflect.Type
|
||||
import java.util.function.Function
|
||||
|
||||
class SandboxPrimitiveSerializer(
|
||||
clazz: Class<*>,
|
||||
classLoader: SandboxClassLoader,
|
||||
private val basicInput: Function<in Any?, out Any?>
|
||||
) : CustomSerializer.Is<Any>(classLoader.loadClassForSandbox(clazz)) {
|
||||
|
||||
override val schemaForDocumentation: Schema = Schema(emptyList())
|
||||
|
||||
override fun readObject(obj: Any, schemas: SerializationSchemas, input: DeserializationInput, context: SerializationContext): Any {
|
||||
return basicInput.apply(obj)!!
|
||||
}
|
||||
|
||||
override fun writeDescribedObject(obj: Any, data: Data, type: Type, output: SerializationOutput, context: SerializationContext) {
|
||||
abortReadOnly()
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package net.corda.djvm.serialization.serializers
|
||||
|
||||
import net.corda.core.serialization.SerializationContext
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.djvm.serialization.deserializers.PublicKeyDecoder
|
||||
import net.corda.djvm.serialization.loadClassForSandbox
|
||||
import net.corda.serialization.internal.amqp.*
|
||||
import org.apache.qpid.proton.codec.Data
|
||||
import java.lang.reflect.Type
|
||||
import java.security.PublicKey
|
||||
import java.util.Collections.singleton
|
||||
import java.util.function.BiFunction
|
||||
import java.util.function.Function
|
||||
|
||||
class SandboxPublicKeySerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
executor: BiFunction<in Any, in Any?, out Any?>
|
||||
) : CustomSerializer.Implements<Any>(classLoader.loadClassForSandbox(PublicKey::class.java)) {
|
||||
private val decoder: Function<ByteArray, out Any?>
|
||||
|
||||
init {
|
||||
val decodeTask = classLoader.loadClassForSandbox(PublicKeyDecoder::class.java).newInstance()
|
||||
decoder = Function { inputs ->
|
||||
executor.apply(decodeTask, inputs)
|
||||
}
|
||||
}
|
||||
|
||||
override val schemaForDocumentation: Schema = Schema(emptyList())
|
||||
|
||||
override val deserializationAliases: Set<Class<*>> = singleton(PublicKey::class.java)
|
||||
|
||||
override fun readObject(obj: Any, schemas: SerializationSchemas, input: DeserializationInput, context: SerializationContext): Any {
|
||||
val bits = input.readObject(obj, schemas, ByteArray::class.java, context) as ByteArray
|
||||
return decoder.apply(bits)!!
|
||||
}
|
||||
|
||||
override fun writeDescribedObject(obj: Any, data: Data, type: Type, output: SerializationOutput, context: SerializationContext) {
|
||||
abortReadOnly()
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package net.corda.djvm.serialization.serializers
|
||||
|
||||
import net.corda.core.serialization.SerializationContext
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.djvm.serialization.deserializers.SymbolDeserializer
|
||||
import net.corda.djvm.serialization.loadClassForSandbox
|
||||
import net.corda.serialization.internal.amqp.*
|
||||
import org.apache.qpid.proton.amqp.Symbol
|
||||
import org.apache.qpid.proton.codec.Data
|
||||
import java.lang.reflect.Type
|
||||
import java.util.function.BiFunction
|
||||
import java.util.function.Function
|
||||
|
||||
class SandboxSymbolSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
executor: BiFunction<in Any, in Any?, out Any?>,
|
||||
basicInput: Function<in Any?, out Any?>
|
||||
) : CustomSerializer.Is<Any>(classLoader.loadClassForSandbox(Symbol::class.java)) {
|
||||
private val transformer: Function<String, out Any?>
|
||||
|
||||
init {
|
||||
val transformTask = classLoader.loadClassForSandbox(SymbolDeserializer::class.java).newInstance()
|
||||
@Suppress("unchecked_cast")
|
||||
transformer = basicInput.andThen { input ->
|
||||
executor.apply(transformTask, input)
|
||||
} as Function<String, Any?>
|
||||
}
|
||||
|
||||
override val schemaForDocumentation: Schema = Schema(emptyList())
|
||||
|
||||
override fun readObject(obj: Any, schemas: SerializationSchemas, input: DeserializationInput, context: SerializationContext): Any {
|
||||
return transformer.apply((obj as Symbol).toString())!!
|
||||
}
|
||||
|
||||
override fun writeDescribedObject(obj: Any, data: Data, type: Type, output: SerializationOutput, context: SerializationContext) {
|
||||
abortReadOnly()
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package net.corda.djvm.serialization.serializers
|
||||
|
||||
import net.corda.core.serialization.SerializationContext
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.djvm.serialization.deserializers.CreateFromString
|
||||
import net.corda.djvm.serialization.loadClassForSandbox
|
||||
import net.corda.serialization.internal.amqp.*
|
||||
import org.apache.qpid.proton.codec.Data
|
||||
import java.lang.reflect.Constructor
|
||||
import java.lang.reflect.Type
|
||||
import java.util.Collections.singleton
|
||||
import java.util.function.BiFunction
|
||||
import java.util.function.Function
|
||||
|
||||
class SandboxToStringSerializer(
|
||||
unsafeClass: Class<*>,
|
||||
classLoader: SandboxClassLoader,
|
||||
executor: BiFunction<in Any, in Any?, out Any?>,
|
||||
basicInput: Function<in Any?, out Any?>
|
||||
) : CustomSerializer.Is<Any>(classLoader.loadClassForSandbox(unsafeClass)) {
|
||||
private val creator: Function<Any?, Any?>
|
||||
|
||||
init {
|
||||
val stringClass = classLoader.loadClass("sandbox.java.lang.String")
|
||||
val createTask = classLoader.loadClassForSandbox(CreateFromString::class.java)
|
||||
.getConstructor(Constructor::class.java)
|
||||
.newInstance(clazz.getConstructor(stringClass))
|
||||
creator = basicInput.andThen { input ->
|
||||
executor.apply(createTask, input)
|
||||
}
|
||||
}
|
||||
|
||||
override val deserializationAliases: Set<Class<*>> = singleton(unsafeClass)
|
||||
|
||||
override val schemaForDocumentation: Schema = Schema(emptyList())
|
||||
|
||||
override fun readObject(obj: Any, schemas: SerializationSchemas, input: DeserializationInput, context: SerializationContext): Any {
|
||||
return creator.apply(obj)!!
|
||||
}
|
||||
|
||||
override fun writeDescribedObject(obj: Any, data: Data, type: Type, output: SerializationOutput, context: SerializationContext) {
|
||||
abortReadOnly()
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package net.corda.djvm.serialization.serializers
|
||||
|
||||
import net.corda.core.serialization.SerializationContext
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.djvm.serialization.deserializers.UnsignedByteDeserializer
|
||||
import net.corda.djvm.serialization.loadClassForSandbox
|
||||
import net.corda.serialization.internal.amqp.*
|
||||
import org.apache.qpid.proton.amqp.UnsignedByte
|
||||
import org.apache.qpid.proton.codec.Data
|
||||
import java.lang.reflect.Type
|
||||
import java.util.function.BiFunction
|
||||
import java.util.function.Function
|
||||
|
||||
class SandboxUnsignedByteSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
executor: BiFunction<in Any, in Any?, out Any?>
|
||||
) : CustomSerializer.Is<Any>(classLoader.loadClassForSandbox(UnsignedByte::class.java)) {
|
||||
private val transformer: Function<ByteArray, out Any?>
|
||||
|
||||
init {
|
||||
val transformTask = classLoader.loadClassForSandbox(UnsignedByteDeserializer::class.java).newInstance()
|
||||
transformer = Function { inputs ->
|
||||
executor.apply(transformTask, inputs)
|
||||
}
|
||||
}
|
||||
|
||||
override val schemaForDocumentation: Schema = Schema(emptyList())
|
||||
|
||||
override fun readObject(obj: Any, schemas: SerializationSchemas, input: DeserializationInput, context: SerializationContext): Any {
|
||||
return transformer.apply(byteArrayOf((obj as UnsignedByte).toByte()))!!
|
||||
}
|
||||
|
||||
override fun writeDescribedObject(obj: Any, data: Data, type: Type, output: SerializationOutput, context: SerializationContext) {
|
||||
abortReadOnly()
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package net.corda.djvm.serialization.serializers
|
||||
|
||||
import net.corda.core.serialization.SerializationContext
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.djvm.serialization.deserializers.UnsignedIntegerDeserializer
|
||||
import net.corda.djvm.serialization.loadClassForSandbox
|
||||
import net.corda.serialization.internal.amqp.*
|
||||
import org.apache.qpid.proton.amqp.UnsignedInteger
|
||||
import org.apache.qpid.proton.codec.Data
|
||||
import java.lang.reflect.Type
|
||||
import java.util.function.BiFunction
|
||||
import java.util.function.Function
|
||||
|
||||
class SandboxUnsignedIntegerSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
executor: BiFunction<in Any, in Any?, out Any?>
|
||||
) : CustomSerializer.Is<Any>(classLoader.loadClassForSandbox(UnsignedInteger::class.java)) {
|
||||
private val transformer: Function<IntArray, out Any?>
|
||||
|
||||
init {
|
||||
val transformTask = classLoader.loadClassForSandbox(UnsignedIntegerDeserializer::class.java).newInstance()
|
||||
transformer = Function { inputs ->
|
||||
executor.apply(transformTask, inputs)
|
||||
}
|
||||
}
|
||||
|
||||
override val schemaForDocumentation: Schema = Schema(emptyList())
|
||||
|
||||
override fun readObject(obj: Any, schemas: SerializationSchemas, input: DeserializationInput, context: SerializationContext): Any {
|
||||
return transformer.apply(intArrayOf((obj as UnsignedInteger).toInt()))!!
|
||||
}
|
||||
|
||||
override fun writeDescribedObject(obj: Any, data: Data, type: Type, output: SerializationOutput, context: SerializationContext) {
|
||||
abortReadOnly()
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package net.corda.djvm.serialization.serializers
|
||||
|
||||
import net.corda.core.serialization.SerializationContext
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.djvm.serialization.deserializers.UnsignedLongDeserializer
|
||||
import net.corda.djvm.serialization.loadClassForSandbox
|
||||
import net.corda.serialization.internal.amqp.*
|
||||
import org.apache.qpid.proton.amqp.UnsignedLong
|
||||
import org.apache.qpid.proton.codec.Data
|
||||
import java.lang.reflect.Type
|
||||
import java.util.Collections.singleton
|
||||
import java.util.function.BiFunction
|
||||
import java.util.function.Function
|
||||
|
||||
class SandboxUnsignedLongSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
executor: BiFunction<in Any, in Any?, out Any?>
|
||||
) : CustomSerializer.Is<Any>(classLoader.loadClassForSandbox(UnsignedLong::class.java)) {
|
||||
private val transformer: Function<LongArray, out Any?>
|
||||
|
||||
init {
|
||||
val transformTask = classLoader.loadClassForSandbox(UnsignedLongDeserializer::class.java).newInstance()
|
||||
transformer = Function { inputs ->
|
||||
executor.apply(transformTask, inputs)
|
||||
}
|
||||
}
|
||||
|
||||
override val schemaForDocumentation: Schema = Schema(emptyList())
|
||||
|
||||
override fun readObject(obj: Any, schemas: SerializationSchemas, input: DeserializationInput, context: SerializationContext): Any {
|
||||
return transformer.apply(longArrayOf((obj as UnsignedLong).toLong()))!!
|
||||
}
|
||||
|
||||
override fun writeDescribedObject(obj: Any, data: Data, type: Type, output: SerializationOutput, context: SerializationContext) {
|
||||
abortReadOnly()
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package net.corda.djvm.serialization.serializers
|
||||
|
||||
import net.corda.core.serialization.SerializationContext
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.djvm.serialization.deserializers.UnsignedShortDeserializer
|
||||
import net.corda.djvm.serialization.loadClassForSandbox
|
||||
import net.corda.serialization.internal.amqp.*
|
||||
import org.apache.qpid.proton.amqp.UnsignedShort
|
||||
import org.apache.qpid.proton.codec.Data
|
||||
import java.lang.reflect.Type
|
||||
import java.util.function.BiFunction
|
||||
import java.util.function.Function
|
||||
|
||||
class SandboxUnsignedShortSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
executor: BiFunction<in Any, in Any?, out Any?>
|
||||
) : CustomSerializer.Is<Any>(classLoader.loadClassForSandbox(UnsignedShort::class.java)) {
|
||||
private val transformer: Function<ShortArray, out Any?>
|
||||
|
||||
init {
|
||||
val transformTask = classLoader.loadClassForSandbox(UnsignedShortDeserializer::class.java).newInstance()
|
||||
transformer = Function { inputs ->
|
||||
executor.apply(transformTask, inputs)
|
||||
}
|
||||
}
|
||||
|
||||
override val schemaForDocumentation: Schema = Schema(emptyList())
|
||||
|
||||
override fun readObject(obj: Any, schemas: SerializationSchemas, input: DeserializationInput, context: SerializationContext): Any {
|
||||
return transformer.apply(shortArrayOf((obj as UnsignedShort).toShort()))!!
|
||||
}
|
||||
|
||||
override fun writeDescribedObject(obj: Any, data: Data, type: Type, output: SerializationOutput, context: SerializationContext) {
|
||||
abortReadOnly()
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package net.corda.djvm.serialization.serializers
|
||||
|
||||
import net.corda.core.serialization.SerializationContext
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.djvm.serialization.deserializers.X509CRLDeserializer
|
||||
import net.corda.djvm.serialization.loadClassForSandbox
|
||||
import net.corda.serialization.internal.amqp.*
|
||||
import org.apache.qpid.proton.codec.Data
|
||||
import java.lang.reflect.Type
|
||||
import java.security.cert.X509CRL
|
||||
import java.util.Collections.singleton
|
||||
import java.util.function.BiFunction
|
||||
import java.util.function.Function
|
||||
|
||||
class SandboxX509CRLSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
executor: BiFunction<in Any, in Any?, out Any?>
|
||||
) : CustomSerializer.Implements<Any>(classLoader.loadClassForSandbox(X509CRL::class.java)) {
|
||||
private val generator: Function<ByteArray, out Any?>
|
||||
|
||||
init {
|
||||
val generateTask = classLoader.loadClassForSandbox(X509CRLDeserializer::class.java).newInstance()
|
||||
generator = Function { inputs ->
|
||||
executor.apply(generateTask, inputs)
|
||||
}
|
||||
}
|
||||
|
||||
override val schemaForDocumentation: Schema = Schema(emptyList())
|
||||
|
||||
override val deserializationAliases: Set<Class<*>> = singleton(X509CRL::class.java)
|
||||
|
||||
override fun readObject(obj: Any, schemas: SerializationSchemas, input: DeserializationInput, context: SerializationContext): Any {
|
||||
val bits = input.readObject(obj, schemas, ByteArray::class.java, context) as ByteArray
|
||||
return generator.apply(bits)!!
|
||||
}
|
||||
|
||||
override fun writeDescribedObject(obj: Any, data: Data, type: Type, output: SerializationOutput, context: SerializationContext) {
|
||||
abortReadOnly()
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package net.corda.djvm.serialization.serializers
|
||||
|
||||
import net.corda.core.serialization.SerializationContext
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.djvm.serialization.deserializers.X509CertificateDeserializer
|
||||
import net.corda.djvm.serialization.loadClassForSandbox
|
||||
import net.corda.serialization.internal.amqp.*
|
||||
import org.apache.qpid.proton.codec.Data
|
||||
import java.lang.reflect.Type
|
||||
import java.security.cert.X509Certificate
|
||||
import java.util.Collections.singleton
|
||||
import java.util.function.BiFunction
|
||||
import java.util.function.Function
|
||||
|
||||
class SandboxX509CertificateSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
executor: BiFunction<in Any, in Any?, out Any?>
|
||||
) : CustomSerializer.Implements<Any>(classLoader.loadClassForSandbox(X509Certificate::class.java)) {
|
||||
private val generator: Function<ByteArray, out Any?>
|
||||
|
||||
init {
|
||||
val generateTask = classLoader.loadClassForSandbox(X509CertificateDeserializer::class.java).newInstance()
|
||||
generator = Function { inputs ->
|
||||
executor.apply(generateTask, inputs)
|
||||
}
|
||||
}
|
||||
|
||||
override val schemaForDocumentation: Schema = Schema(emptyList())
|
||||
|
||||
override val deserializationAliases: Set<Class<*>> = singleton(X509Certificate::class.java)
|
||||
|
||||
override fun readObject(obj: Any, schemas: SerializationSchemas, input: DeserializationInput, context: SerializationContext): Any {
|
||||
val bits = input.readObject(obj, schemas, ByteArray::class.java, context) as ByteArray
|
||||
return generator.apply(bits)!!
|
||||
}
|
||||
|
||||
override fun writeDescribedObject(obj: Any, data: Data, type: Type, output: SerializationOutput, context: SerializationContext) {
|
||||
abortReadOnly()
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package net.corda.djvm.serialization.serializers
|
||||
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.djvm.serialization.deserializers.YearMonthDeserializer
|
||||
import net.corda.djvm.serialization.loadClassForSandbox
|
||||
import net.corda.serialization.internal.amqp.CustomSerializer
|
||||
import net.corda.serialization.internal.amqp.SerializerFactory
|
||||
import net.corda.serialization.internal.amqp.custom.YearMonthSerializer.YearMonthProxy
|
||||
import java.time.YearMonth
|
||||
import java.util.Collections.singleton
|
||||
import java.util.function.BiFunction
|
||||
|
||||
class SandboxYearMonthSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
private val executor: BiFunction<in Any, in Any?, out Any?>,
|
||||
factory: SerializerFactory
|
||||
) : CustomSerializer.Proxy<Any, Any>(
|
||||
clazz = classLoader.loadClassForSandbox(YearMonth::class.java),
|
||||
proxyClass = classLoader.loadClassForSandbox(YearMonthProxy::class.java),
|
||||
factory = factory
|
||||
) {
|
||||
private val task = classLoader.loadClassForSandbox(YearMonthDeserializer::class.java).newInstance()
|
||||
|
||||
override val deserializationAliases: Set<Class<*>> = singleton(YearMonth::class.java)
|
||||
|
||||
override fun toProxy(obj: Any): Any = abortReadOnly()
|
||||
|
||||
override fun fromProxy(proxy: Any): Any {
|
||||
return executor.apply(task, proxy)!!
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package net.corda.djvm.serialization.serializers
|
||||
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.djvm.serialization.deserializers.YearDeserializer
|
||||
import net.corda.djvm.serialization.loadClassForSandbox
|
||||
import net.corda.serialization.internal.amqp.CustomSerializer
|
||||
import net.corda.serialization.internal.amqp.SerializerFactory
|
||||
import net.corda.serialization.internal.amqp.custom.YearSerializer.YearProxy
|
||||
import java.time.Year
|
||||
import java.util.Collections.singleton
|
||||
import java.util.function.BiFunction
|
||||
|
||||
class SandboxYearSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
private val executor: BiFunction<in Any, in Any?, out Any?>,
|
||||
factory: SerializerFactory
|
||||
) : CustomSerializer.Proxy<Any, Any>(
|
||||
clazz = classLoader.loadClassForSandbox(Year::class.java),
|
||||
proxyClass = classLoader.loadClassForSandbox(YearProxy::class.java),
|
||||
factory = factory
|
||||
) {
|
||||
private val task = classLoader.loadClassForSandbox(YearDeserializer::class.java).newInstance()
|
||||
|
||||
override val deserializationAliases: Set<Class<*>> = singleton(Year::class.java)
|
||||
|
||||
override fun toProxy(obj: Any): Any = abortReadOnly()
|
||||
|
||||
override fun fromProxy(proxy: Any): Any {
|
||||
return executor.apply(task, proxy)!!
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package net.corda.djvm.serialization.serializers
|
||||
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.djvm.serialization.deserializers.ZoneIdDeserializer
|
||||
import net.corda.djvm.serialization.loadClassForSandbox
|
||||
import net.corda.serialization.internal.amqp.CustomSerializer
|
||||
import net.corda.serialization.internal.amqp.SerializerFactory
|
||||
import net.corda.serialization.internal.amqp.custom.ZoneIdSerializer.ZoneIdProxy
|
||||
import java.time.ZoneId
|
||||
import java.util.Collections.singleton
|
||||
import java.util.function.BiFunction
|
||||
|
||||
class SandboxZoneIdSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
private val executor: BiFunction<in Any, in Any?, out Any?>,
|
||||
factory: SerializerFactory
|
||||
) : CustomSerializer.Proxy<Any, Any>(
|
||||
clazz = classLoader.loadClassForSandbox(ZoneId::class.java),
|
||||
proxyClass = classLoader.loadClassForSandbox(ZoneIdProxy::class.java),
|
||||
factory = factory
|
||||
) {
|
||||
private val task = classLoader.loadClassForSandbox(ZoneIdDeserializer::class.java).newInstance()
|
||||
|
||||
override val revealSubclassesInSchema: Boolean = true
|
||||
|
||||
override val deserializationAliases: Set<Class<*>> = singleton(ZoneId::class.java)
|
||||
|
||||
override fun toProxy(obj: Any): Any = abortReadOnly()
|
||||
|
||||
override fun fromProxy(proxy: Any): Any {
|
||||
return executor.apply(task, proxy)!!
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package net.corda.djvm.serialization.serializers
|
||||
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.djvm.serialization.deserializers.ZonedDateTimeDeserializer
|
||||
import net.corda.djvm.serialization.loadClassForSandbox
|
||||
import net.corda.serialization.internal.amqp.CustomSerializer
|
||||
import net.corda.serialization.internal.amqp.SerializerFactory
|
||||
import net.corda.serialization.internal.amqp.custom.ZonedDateTimeSerializer.ZonedDateTimeProxy
|
||||
import java.time.LocalDateTime
|
||||
import java.time.ZoneId
|
||||
import java.time.ZoneOffset
|
||||
import java.time.ZonedDateTime
|
||||
import java.util.Collections.singleton
|
||||
import java.util.function.BiFunction
|
||||
|
||||
class SandboxZonedDateTimeSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
executor: BiFunction<in Any, in Any?, out Any?>,
|
||||
factory: SerializerFactory
|
||||
) : CustomSerializer.Proxy<Any, Any>(
|
||||
clazz = classLoader.loadClassForSandbox(ZonedDateTime::class.java),
|
||||
proxyClass = classLoader.loadClassForSandbox(ZonedDateTimeProxy::class.java),
|
||||
factory = factory
|
||||
) {
|
||||
private val task = classLoader.loadClassForSandbox(ZonedDateTimeDeserializer::class.java).newInstance()
|
||||
private val creator: BiFunction<in Any?, in Any?, out Any?>
|
||||
|
||||
init {
|
||||
val createTask = clazz.getMethod(
|
||||
"createDJVM",
|
||||
classLoader.loadClassForSandbox(LocalDateTime::class.java),
|
||||
classLoader.loadClassForSandbox(ZoneOffset::class.java),
|
||||
classLoader.loadClassForSandbox(ZoneId::class.java)
|
||||
)
|
||||
creator = executor.andThen { input ->
|
||||
@Suppress("unchecked_cast")
|
||||
createTask(null, *(input as Array<Any>))!!
|
||||
}
|
||||
}
|
||||
|
||||
override val deserializationAliases: Set<Class<*>> = singleton(ZonedDateTime::class.java)
|
||||
|
||||
override fun toProxy(obj: Any): Any = abortReadOnly()
|
||||
|
||||
override fun fromProxy(proxy: Any): Any {
|
||||
return creator.apply(task, proxy)!!
|
||||
}
|
||||
}
|
13
src/test/java/greymalkin/ExternalData.java
Normal file
13
src/test/java/greymalkin/ExternalData.java
Normal file
@ -0,0 +1,13 @@
|
||||
package greymalkin;
|
||||
|
||||
public class ExternalData {
|
||||
private final String data;
|
||||
|
||||
public ExternalData(String data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public String getData() {
|
||||
return data;
|
||||
}
|
||||
}
|
11
src/test/java/greymalkin/ExternalEnum.java
Normal file
11
src/test/java/greymalkin/ExternalEnum.java
Normal file
@ -0,0 +1,11 @@
|
||||
package greymalkin;
|
||||
|
||||
import net.corda.core.serialization.CordaSerializable;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@CordaSerializable
|
||||
public enum ExternalEnum {
|
||||
DOH,
|
||||
RAY,
|
||||
ME
|
||||
}
|
22
src/test/java/net/corda/djvm/serialization/InnocentData.java
Normal file
22
src/test/java/net/corda/djvm/serialization/InnocentData.java
Normal file
@ -0,0 +1,22 @@
|
||||
package net.corda.djvm.serialization;
|
||||
|
||||
import net.corda.core.serialization.CordaSerializable;
|
||||
|
||||
@CordaSerializable
|
||||
public class InnocentData {
|
||||
private final String message;
|
||||
private final Short number;
|
||||
|
||||
public InnocentData(String message, Short number) {
|
||||
this.message = message;
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public Short getNumber() {
|
||||
return number;
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
package net.corda.djvm.serialization;
|
||||
|
||||
import net.corda.core.serialization.ConstructorForDeserialization;
|
||||
import net.corda.core.serialization.CordaSerializable;
|
||||
|
||||
@SuppressWarnings({"unused", "WeakerAccess"})
|
||||
@CordaSerializable
|
||||
public class MultiConstructorData {
|
||||
private final String message;
|
||||
private final long bigNumber;
|
||||
private final Character tag;
|
||||
|
||||
@ConstructorForDeserialization
|
||||
public MultiConstructorData(String message, long bigNumber, Character tag) {
|
||||
this.message = message;
|
||||
this.bigNumber = bigNumber;
|
||||
this.tag = tag;
|
||||
}
|
||||
|
||||
public MultiConstructorData(String message, long bigNumber) {
|
||||
this(message, bigNumber, null);
|
||||
}
|
||||
|
||||
public MultiConstructorData(String message, char tag) {
|
||||
this(message, 0, tag);
|
||||
}
|
||||
|
||||
public MultiConstructorData(String message) {
|
||||
this(message, 0);
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public long getBigNumber() {
|
||||
return bigNumber;
|
||||
}
|
||||
|
||||
public Character getTag() {
|
||||
return tag;
|
||||
}
|
||||
|
||||
@SuppressWarnings("StringBufferReplaceableByString")
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder("MultiConstructor[message='").append(message)
|
||||
.append("', bigNumber=").append(bigNumber)
|
||||
.append(", tag=").append(tag)
|
||||
.append(']')
|
||||
.toString();
|
||||
}
|
||||
}
|
15
src/test/java/net/corda/djvm/serialization/VeryEvilData.java
Normal file
15
src/test/java/net/corda/djvm/serialization/VeryEvilData.java
Normal file
@ -0,0 +1,15 @@
|
||||
package net.corda.djvm.serialization;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class VeryEvilData extends InnocentData {
|
||||
static {
|
||||
if (!VeryEvilData.class.getName().startsWith("sandbox.")) {
|
||||
// Execute our evil payload OUTSIDE the sandbox!
|
||||
throw new IllegalStateException("Victory is mine!");
|
||||
}
|
||||
}
|
||||
|
||||
public VeryEvilData(String message, Short number) {
|
||||
super(message, number);
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
package net.corda.djvm.serialization
|
||||
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import net.corda.core.serialization.internal._contextSerializationEnv
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.djvm.serialization.SandboxType.*
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.junit.jupiter.api.fail
|
||||
import java.math.BigDecimal
|
||||
import java.util.function.Function
|
||||
|
||||
@ExtendWith(LocalSerialization::class)
|
||||
class DeserializeBigDecimalTest : TestBase(KOTLIN) {
|
||||
companion object {
|
||||
const val VERY_BIG_DECIMAL = 994349993939.32737232
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test deserializing big decimal`() {
|
||||
val bigDecimal = BigDecimalData(BigDecimal.valueOf(VERY_BIG_DECIMAL))
|
||||
val data = bigDecimal.serialize()
|
||||
|
||||
sandbox {
|
||||
_contextSerializationEnv.set(createSandboxSerializationEnv(classLoader))
|
||||
|
||||
val sandboxBigInteger = data.deserializeFor(classLoader)
|
||||
|
||||
val executor = createExecutorFor(classLoader)
|
||||
val result = executor.apply(
|
||||
classLoader.loadClassForSandbox(ShowBigDecimal::class.java).newInstance(),
|
||||
sandboxBigInteger
|
||||
) ?: fail("Result cannot be null")
|
||||
|
||||
assertEquals(ShowBigDecimal().apply(bigDecimal), result.toString())
|
||||
assertEquals(SANDBOX_STRING, result::class.java.name)
|
||||
}
|
||||
}
|
||||
|
||||
class ShowBigDecimal : Function<BigDecimalData, String> {
|
||||
override fun apply(data: BigDecimalData): String {
|
||||
return with(data) {
|
||||
"BigDecimal: $number"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@CordaSerializable
|
||||
data class BigDecimalData(val number: BigDecimal)
|
@ -0,0 +1,51 @@
|
||||
package net.corda.djvm.serialization
|
||||
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import net.corda.core.serialization.internal._contextSerializationEnv
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.djvm.serialization.SandboxType.*
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.junit.jupiter.api.fail
|
||||
import java.math.BigInteger
|
||||
import java.util.function.Function
|
||||
|
||||
@ExtendWith(LocalSerialization::class)
|
||||
class DeserializeBigIntegerTest : TestBase(KOTLIN) {
|
||||
companion object {
|
||||
const val VERY_BIG_NUMBER = 1234567890123456789
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test deserializing big integer`() {
|
||||
val bigInteger = BigIntegerData(BigInteger.valueOf(VERY_BIG_NUMBER))
|
||||
val data = bigInteger.serialize()
|
||||
|
||||
sandbox {
|
||||
_contextSerializationEnv.set(createSandboxSerializationEnv(classLoader))
|
||||
|
||||
val sandboxBigInteger = data.deserializeFor(classLoader)
|
||||
|
||||
val executor = createExecutorFor(classLoader)
|
||||
val result = executor.apply(
|
||||
classLoader.loadClassForSandbox(ShowBigInteger::class.java).newInstance(),
|
||||
sandboxBigInteger
|
||||
) ?: fail("Result cannot be null")
|
||||
|
||||
assertEquals(ShowBigInteger().apply(bigInteger), result.toString())
|
||||
assertEquals(SANDBOX_STRING, result::class.java.name)
|
||||
}
|
||||
}
|
||||
|
||||
class ShowBigInteger : Function<BigIntegerData, String> {
|
||||
override fun apply(data: BigIntegerData): String {
|
||||
return with(data) {
|
||||
"BigInteger: $number"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@CordaSerializable
|
||||
data class BigIntegerData(val number: BigInteger)
|
@ -0,0 +1,41 @@
|
||||
package net.corda.djvm.serialization
|
||||
|
||||
import net.corda.core.serialization.internal._contextSerializationEnv
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.djvm.serialization.SandboxType.*
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.junit.jupiter.api.fail
|
||||
import java.util.*
|
||||
import java.util.function.Function
|
||||
|
||||
@ExtendWith(LocalSerialization::class)
|
||||
class DeserializeBitSetTest : TestBase(KOTLIN) {
|
||||
@Test
|
||||
fun `test deserializing bitset`() {
|
||||
val bitSet = BitSet.valueOf(byteArrayOf(0x00, 0x70, 0x55, 0x3A, 0x48, 0x12))
|
||||
val data = bitSet.serialize()
|
||||
|
||||
sandbox {
|
||||
_contextSerializationEnv.set(createSandboxSerializationEnv(classLoader))
|
||||
|
||||
val sandboxBitSet = data.deserializeFor(classLoader)
|
||||
|
||||
val executor = createExecutorFor(classLoader)
|
||||
val result = executor.apply(
|
||||
classLoader.loadClassForSandbox(ShowBitSet::class.java).newInstance(),
|
||||
sandboxBitSet
|
||||
) ?: fail("Result cannot be null")
|
||||
|
||||
assertEquals(bitSet.toString(), result.toString())
|
||||
assertEquals(SANDBOX_STRING, result::class.java.name)
|
||||
}
|
||||
}
|
||||
|
||||
class ShowBitSet : Function<BitSet, String> {
|
||||
override fun apply(bitSet: BitSet): String {
|
||||
return bitSet.toString()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,135 @@
|
||||
package net.corda.djvm.serialization
|
||||
|
||||
import net.corda.core.serialization.internal._contextSerializationEnv
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.djvm.serialization.SandboxType.*
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.bouncycastle.asn1.x509.CRLReason
|
||||
import org.bouncycastle.asn1.x500.X500Name
|
||||
import org.bouncycastle.cert.X509v2CRLBuilder
|
||||
import org.bouncycastle.cert.jcajce.JcaX509CRLConverter
|
||||
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.BeforeAll
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.junit.jupiter.api.fail
|
||||
import java.security.KeyPairGenerator
|
||||
import java.security.cert.CertPath
|
||||
import java.security.cert.CertificateFactory
|
||||
import java.security.cert.X509CRL
|
||||
import java.security.cert.X509Certificate
|
||||
import java.util.Date
|
||||
import java.util.function.Function
|
||||
|
||||
@ExtendWith(LocalSerialization::class)
|
||||
class DeserializeCertificatesTest : TestBase(KOTLIN) {
|
||||
companion object {
|
||||
// The sandbox's localisation may not match that of the host.
|
||||
// E.g. line separator characters and time zone format.
|
||||
fun localise(str: String): String {
|
||||
return str.replace("\n", System.lineSeparator())
|
||||
}
|
||||
|
||||
val factory: CertificateFactory = CertificateFactory.getInstance("X.509")
|
||||
lateinit var certificate: X509Certificate
|
||||
|
||||
@Suppress("unused")
|
||||
@BeforeAll
|
||||
@JvmStatic
|
||||
fun loadCertificate() {
|
||||
certificate = this::class.java.classLoader.getResourceAsStream("testing.cert")?.use { input ->
|
||||
factory.generateCertificate(input) as X509Certificate
|
||||
} ?: fail("Certificate not found")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test deserialize certificate path`() {
|
||||
val certPath = factory.generateCertPath(listOf(certificate))
|
||||
val data = certPath.serialize()
|
||||
|
||||
sandbox {
|
||||
_contextSerializationEnv.set(createSandboxSerializationEnv(classLoader))
|
||||
|
||||
val sandboxCertPath = data.deserializeFor(classLoader)
|
||||
|
||||
val executor = createExecutorFor(classLoader)
|
||||
val result = executor.apply(
|
||||
classLoader.loadClassForSandbox(ShowCertPath::class.java).newInstance(),
|
||||
sandboxCertPath
|
||||
) ?: fail("Result cannot be null")
|
||||
|
||||
assertEquals(ShowCertPath().apply(certPath), localise(result.toString()))
|
||||
assertThat(result::class.java.name).startsWith("sandbox.")
|
||||
}
|
||||
}
|
||||
|
||||
class ShowCertPath : Function<CertPath, String> {
|
||||
override fun apply(certPath: CertPath): String {
|
||||
return "CertPath -> $certPath"
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test deserialize X509 certificate`() {
|
||||
val data = certificate.serialize()
|
||||
|
||||
sandbox {
|
||||
_contextSerializationEnv.set(createSandboxSerializationEnv(classLoader))
|
||||
|
||||
val sandboxCertificate = data.deserializeFor(classLoader)
|
||||
|
||||
val executor = createExecutorFor(classLoader)
|
||||
val result = executor.apply(
|
||||
classLoader.loadClassForSandbox(ShowCertificate::class.java).newInstance(),
|
||||
sandboxCertificate
|
||||
) ?: fail("Result cannot be null")
|
||||
|
||||
assertEquals(ShowCertificate().apply(certificate), localise(result.toString()))
|
||||
assertThat(result::class.java.name).startsWith("sandbox.")
|
||||
}
|
||||
}
|
||||
|
||||
class ShowCertificate : Function<X509Certificate, String> {
|
||||
override fun apply(certificate: X509Certificate): String {
|
||||
return "X.509 Certificate -> $certificate"
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test X509 CRL`() {
|
||||
val caKeyPair = KeyPairGenerator.getInstance("RSA")
|
||||
.generateKeyPair()
|
||||
val signer = JcaContentSignerBuilder("SHA256WithRSAEncryption")
|
||||
.build(caKeyPair.private)
|
||||
|
||||
val now = Date()
|
||||
val crl = with(X509v2CRLBuilder(X500Name("CN=Test CA"), now)) {
|
||||
addCRLEntry(certificate.serialNumber, now, CRLReason.privilegeWithdrawn)
|
||||
JcaX509CRLConverter().getCRL(build(signer))
|
||||
}
|
||||
val data = crl.serialize()
|
||||
|
||||
sandbox {
|
||||
_contextSerializationEnv.set(createSandboxSerializationEnv(classLoader))
|
||||
|
||||
val sandboxCRL = data.deserializeFor(classLoader)
|
||||
|
||||
val executor = createExecutorFor(classLoader)
|
||||
val result = executor.apply(
|
||||
classLoader.loadClassForSandbox(ShowCRL::class.java).newInstance(),
|
||||
sandboxCRL
|
||||
) ?: fail("Result cannot be null")
|
||||
|
||||
assertEquals(ShowCRL().apply(crl), localise(result.toString()))
|
||||
assertThat(result::class.java.name).startsWith("sandbox.")
|
||||
}
|
||||
}
|
||||
|
||||
class ShowCRL : Function<X509CRL, String> {
|
||||
override fun apply(crl: X509CRL): String {
|
||||
return "X.509 CRL -> $crl"
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
package net.corda.djvm.serialization
|
||||
|
||||
import greymalkin.ExternalData
|
||||
import net.corda.core.serialization.internal._contextSerializationEnv
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.djvm.serialization.SandboxType.*
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.jupiter.api.Assertions.*
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.assertThrows
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.junit.jupiter.api.fail
|
||||
import java.io.NotSerializableException
|
||||
import java.util.function.Function
|
||||
|
||||
@ExtendWith(LocalSerialization::class)
|
||||
class DeserializeClassTest : TestBase(KOTLIN) {
|
||||
@Test
|
||||
fun `test deserializing existing class`() {
|
||||
val myClass = ExternalData::class.java
|
||||
val data = myClass.serialize()
|
||||
|
||||
sandbox {
|
||||
_contextSerializationEnv.set(createSandboxSerializationEnv(classLoader))
|
||||
|
||||
val sandboxInstant = data.deserializeFor(classLoader)
|
||||
|
||||
val executor = createExecutorFor(classLoader)
|
||||
val result = executor.apply(
|
||||
classLoader.loadClassForSandbox(ShowClass::class.java).newInstance(),
|
||||
sandboxInstant
|
||||
) ?: fail("Result cannot be null")
|
||||
|
||||
assertEquals("sandbox.${myClass.name}", result.toString())
|
||||
assertEquals(SANDBOX_STRING, result::class.java.name)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test deserializing missing class`() {
|
||||
// The DJVM will refuse to find this class because it belongs to net.corda.djvm.**.
|
||||
val myClass = VeryEvilData::class.java
|
||||
val data = myClass.serialize()
|
||||
|
||||
sandbox {
|
||||
_contextSerializationEnv.set(createSandboxSerializationEnv(classLoader))
|
||||
|
||||
val ex = assertThrows<NotSerializableException>{ data.deserializeFor(classLoader) }
|
||||
assertThat(ex)
|
||||
.isExactlyInstanceOf(NotSerializableException::class.java)
|
||||
.hasMessageContaining("VeryEvilData was not found by the node,")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ShowClass : Function<Class<*>, String> {
|
||||
override fun apply(type: Class<*>): String {
|
||||
return type.name
|
||||
}
|
||||
}
|
@ -0,0 +1,227 @@
|
||||
package net.corda.djvm.serialization
|
||||
|
||||
import greymalkin.ExternalEnum
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import net.corda.core.serialization.internal._contextSerializationEnv
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.core.utilities.NonEmptySet
|
||||
import net.corda.djvm.serialization.SandboxType.*
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.junit.jupiter.api.fail
|
||||
import java.util.*
|
||||
import java.util.function.Function
|
||||
|
||||
@ExtendWith(LocalSerialization::class)
|
||||
class DeserializeCollectionsTest : TestBase(KOTLIN) {
|
||||
@Test
|
||||
fun `test deserializing string list`() {
|
||||
val stringList = StringList(listOf("Hello", "World", "!"))
|
||||
val data = stringList.serialize()
|
||||
|
||||
sandbox {
|
||||
_contextSerializationEnv.set(createSandboxSerializationEnv(classLoader))
|
||||
|
||||
val sandboxList = data.deserializeFor(classLoader)
|
||||
|
||||
val executor = createExecutorFor(classLoader)
|
||||
val result = executor.apply(
|
||||
classLoader.loadClassForSandbox(ShowStringList::class.java).newInstance(),
|
||||
sandboxList
|
||||
) ?: fail("Result cannot be null")
|
||||
|
||||
assertEquals(stringList.lines.joinToString(), result.toString())
|
||||
assertEquals("Hello, World, !", result.toString())
|
||||
}
|
||||
}
|
||||
|
||||
class ShowStringList : Function<StringList, String> {
|
||||
override fun apply(data: StringList): String {
|
||||
return data.lines.joinToString()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test deserializing integer set`() {
|
||||
val integerSet = IntegerSet(linkedSetOf(10, 3, 15, 2, 10))
|
||||
val data = integerSet.serialize()
|
||||
|
||||
sandbox {
|
||||
_contextSerializationEnv.set(createSandboxSerializationEnv(classLoader))
|
||||
|
||||
val sandboxSet = data.deserializeFor(classLoader)
|
||||
|
||||
val executor = createExecutorFor(classLoader)
|
||||
val result = executor.apply(
|
||||
classLoader.loadClassForSandbox(ShowIntegerSet::class.java).newInstance(),
|
||||
sandboxSet
|
||||
) ?: fail("Result cannot be null")
|
||||
|
||||
assertEquals(integerSet.numbers.joinToString(), result.toString())
|
||||
assertEquals("10, 3, 15, 2", result.toString())
|
||||
}
|
||||
}
|
||||
|
||||
class ShowIntegerSet : Function<IntegerSet, String> {
|
||||
override fun apply(data: IntegerSet): String {
|
||||
return data.numbers.joinToString()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test deserializing integer sorted set`() {
|
||||
val integerSortedSet = IntegerSortedSet(sortedSetOf(10, 15, 1000, 3, 2, 10))
|
||||
val data = integerSortedSet.serialize()
|
||||
|
||||
sandbox {
|
||||
_contextSerializationEnv.set(createSandboxSerializationEnv(classLoader))
|
||||
|
||||
val sandboxSet = data.deserializeFor(classLoader)
|
||||
|
||||
val executor = createExecutorFor(classLoader)
|
||||
val result = executor.apply(
|
||||
classLoader.loadClassForSandbox(ShowIntegerSortedSet::class.java).newInstance(),
|
||||
sandboxSet
|
||||
) ?: fail("Result cannot be null")
|
||||
|
||||
assertEquals(integerSortedSet.numbers.joinToString(), result.toString())
|
||||
assertEquals("2, 3, 10, 15, 1000", result.toString())
|
||||
}
|
||||
}
|
||||
|
||||
class ShowIntegerSortedSet : Function<IntegerSortedSet, String> {
|
||||
override fun apply(data: IntegerSortedSet): String {
|
||||
return data.numbers.joinToString()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test deserializing long navigable set`() {
|
||||
val longNavigableSet = LongNavigableSet(sortedSetOf(99955L, 10, 15, 1000, 3, 2, 10))
|
||||
val data = longNavigableSet.serialize()
|
||||
|
||||
sandbox {
|
||||
_contextSerializationEnv.set(createSandboxSerializationEnv(classLoader))
|
||||
|
||||
val sandboxSet = data.deserializeFor(classLoader)
|
||||
|
||||
val executor = createExecutorFor(classLoader)
|
||||
val result = executor.apply(
|
||||
classLoader.loadClassForSandbox(ShowLongNavigableSet::class.java).newInstance(),
|
||||
sandboxSet
|
||||
) ?: fail("Result cannot be null")
|
||||
|
||||
assertEquals(longNavigableSet.numbers.joinToString(), result.toString())
|
||||
assertEquals("2, 3, 10, 15, 1000, 99955", result.toString())
|
||||
}
|
||||
}
|
||||
|
||||
class ShowLongNavigableSet : Function<LongNavigableSet, String> {
|
||||
override fun apply(data: LongNavigableSet): String {
|
||||
return data.numbers.joinToString()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test deserializing short collection`() {
|
||||
val shortCollection = ShortCollection(listOf(10, 200, 3000))
|
||||
val data = shortCollection.serialize()
|
||||
|
||||
sandbox {
|
||||
_contextSerializationEnv.set(createSandboxSerializationEnv(classLoader))
|
||||
|
||||
val sandboxCollection = data.deserializeFor(classLoader)
|
||||
|
||||
val executor = createExecutorFor(classLoader)
|
||||
val result = executor.apply(
|
||||
classLoader.loadClassForSandbox(ShowShortCollection::class.java).newInstance(),
|
||||
sandboxCollection
|
||||
) ?: fail("Result cannot be null")
|
||||
|
||||
assertEquals(shortCollection.numbers.joinToString(), result.toString())
|
||||
assertEquals("10, 200, 3000", result.toString())
|
||||
}
|
||||
}
|
||||
|
||||
class ShowShortCollection : Function<ShortCollection, String> {
|
||||
override fun apply(data: ShortCollection): String {
|
||||
return data.numbers.joinToString()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test deserializing non-empty string set`() {
|
||||
val nonEmptyStrings = NonEmptyStringSet(NonEmptySet.of("Hello", "World", "!"))
|
||||
val data = nonEmptyStrings.serialize()
|
||||
|
||||
sandbox {
|
||||
_contextSerializationEnv.set(createSandboxSerializationEnv(classLoader))
|
||||
|
||||
val sandboxSet = data.deserializeFor(classLoader)
|
||||
|
||||
val executor = createExecutorFor(classLoader)
|
||||
val result = executor.apply(
|
||||
classLoader.loadClassForSandbox(ShowNonEmptyStringSet::class.java).newInstance(),
|
||||
sandboxSet
|
||||
) ?: fail("Result cannot be null")
|
||||
|
||||
assertEquals(nonEmptyStrings.lines.joinToString(), result.toString())
|
||||
assertEquals("Hello, World, !", result.toString())
|
||||
}
|
||||
}
|
||||
|
||||
class ShowNonEmptyStringSet : Function<NonEmptyStringSet, String> {
|
||||
override fun apply(data: NonEmptyStringSet): String {
|
||||
return data.lines.joinToString()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test deserializing enum set`() {
|
||||
val enumSet = HasEnumSet(EnumSet.of(ExternalEnum.DOH))
|
||||
val data = enumSet.serialize()
|
||||
|
||||
sandbox {
|
||||
_contextSerializationEnv.set(createSandboxSerializationEnv(classLoader))
|
||||
|
||||
val sandboxSet = data.deserializeFor(classLoader)
|
||||
|
||||
val executor = createExecutorFor(classLoader)
|
||||
val result = executor.apply(
|
||||
classLoader.loadClassForSandbox(ShowHasEnumSet::class.java).newInstance(),
|
||||
sandboxSet
|
||||
) ?: fail("Result cannot be null")
|
||||
|
||||
assertEquals(enumSet.values.toString(), result.toString())
|
||||
assertEquals("[DOH]", result.toString())
|
||||
}
|
||||
}
|
||||
|
||||
class ShowHasEnumSet : Function<HasEnumSet, String> {
|
||||
override fun apply(data: HasEnumSet): String {
|
||||
return data.values.toString()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@CordaSerializable
|
||||
class StringList(val lines: List<String>)
|
||||
|
||||
@CordaSerializable
|
||||
class IntegerSet(val numbers: Set<Int>)
|
||||
|
||||
@CordaSerializable
|
||||
class IntegerSortedSet(val numbers: SortedSet<Int>)
|
||||
|
||||
@CordaSerializable
|
||||
class LongNavigableSet(val numbers: NavigableSet<Long>)
|
||||
|
||||
@CordaSerializable
|
||||
class ShortCollection(val numbers: Collection<Short>)
|
||||
|
||||
@CordaSerializable
|
||||
class NonEmptyStringSet(val lines: NonEmptySet<String>)
|
||||
|
||||
@CordaSerializable
|
||||
class HasEnumSet(val values: EnumSet<ExternalEnum>)
|
@ -0,0 +1,47 @@
|
||||
package net.corda.djvm.serialization
|
||||
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import net.corda.core.serialization.internal._contextSerializationEnv
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.djvm.serialization.SandboxType.*
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.junit.jupiter.api.fail
|
||||
import java.util.*
|
||||
import java.util.function.Function
|
||||
|
||||
@ExtendWith(LocalSerialization::class)
|
||||
class DeserializeCurrencyTest : TestBase(KOTLIN) {
|
||||
@Test
|
||||
fun `test deserializing currency`() {
|
||||
val currency = CurrencyData(Currency.getInstance("GBP"))
|
||||
val data = currency.serialize()
|
||||
|
||||
sandbox {
|
||||
_contextSerializationEnv.set(createSandboxSerializationEnv(classLoader))
|
||||
|
||||
val sandboxCurrency = data.deserializeFor(classLoader)
|
||||
|
||||
val executor = createExecutorFor(classLoader)
|
||||
val result = executor.apply(
|
||||
classLoader.loadClassForSandbox(ShowCurrency::class.java).newInstance(),
|
||||
sandboxCurrency
|
||||
) ?: fail("Result cannot be null")
|
||||
|
||||
assertEquals(ShowCurrency().apply(currency), result.toString())
|
||||
assertEquals(SANDBOX_STRING, result::class.java.name)
|
||||
}
|
||||
}
|
||||
|
||||
class ShowCurrency : Function<CurrencyData, String> {
|
||||
override fun apply(data: CurrencyData): String {
|
||||
return with(data) {
|
||||
"Currency: $currency"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@CordaSerializable
|
||||
data class CurrencyData(val currency: Currency)
|
@ -0,0 +1,45 @@
|
||||
package net.corda.djvm.serialization
|
||||
|
||||
import greymalkin.ExternalEnum
|
||||
import net.corda.core.serialization.internal._contextSerializationEnv
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.djvm.serialization.SandboxType.KOTLIN
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.junit.jupiter.api.fail
|
||||
import org.junit.jupiter.params.ParameterizedTest
|
||||
import org.junit.jupiter.params.provider.EnumSource
|
||||
import java.util.*
|
||||
import java.util.function.Function
|
||||
|
||||
@ExtendWith(LocalSerialization::class)
|
||||
class DeserializeEnumSetTest : TestBase(KOTLIN) {
|
||||
@ParameterizedTest
|
||||
@EnumSource(ExternalEnum::class)
|
||||
fun `test deserialize enum set`(value: ExternalEnum) {
|
||||
val enumSet = EnumSet.of(value)
|
||||
val data = enumSet.serialize()
|
||||
|
||||
sandbox {
|
||||
_contextSerializationEnv.set(createSandboxSerializationEnv(classLoader))
|
||||
|
||||
val sandboxEnumSet = data.deserializeFor(classLoader)
|
||||
|
||||
val executor = createExecutorFor(classLoader)
|
||||
val result = executor.apply(
|
||||
classLoader.loadClassForSandbox(ShowEnumSet::class.java).newInstance(),
|
||||
sandboxEnumSet
|
||||
) ?: fail("Result cannot be null")
|
||||
|
||||
assertEquals(ShowEnumSet().apply(enumSet), result.toString())
|
||||
assertEquals("EnumSet: [$value]'", result.toString())
|
||||
assertEquals(SANDBOX_STRING, result::class.java.name)
|
||||
}
|
||||
}
|
||||
|
||||
class ShowEnumSet : Function<EnumSet<*>, String> {
|
||||
override fun apply(input: EnumSet<*>): String {
|
||||
return "EnumSet: $input'"
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
package net.corda.djvm.serialization
|
||||
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import net.corda.core.serialization.internal._contextSerializationEnv
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.djvm.serialization.SandboxType.KOTLIN
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.junit.jupiter.api.fail
|
||||
import org.junit.jupiter.params.ParameterizedTest
|
||||
import org.junit.jupiter.params.provider.EnumSource
|
||||
import java.util.function.Function
|
||||
|
||||
@ExtendWith(LocalSerialization::class)
|
||||
class DeserializeEnumTest : TestBase(KOTLIN) {
|
||||
@ParameterizedTest
|
||||
@EnumSource(ExampleEnum::class)
|
||||
fun `test deserialize basic enum`(value: ExampleEnum) {
|
||||
val example = ExampleData(value)
|
||||
val data =example.serialize()
|
||||
|
||||
sandbox {
|
||||
_contextSerializationEnv.set(createSandboxSerializationEnv(classLoader))
|
||||
|
||||
val sandboxExample = data.deserializeFor(classLoader)
|
||||
|
||||
val executor = createExecutorFor(classLoader)
|
||||
val result = executor.apply(
|
||||
classLoader.loadClassForSandbox(ShowExampleData::class.java).newInstance(),
|
||||
sandboxExample
|
||||
) ?: fail("Result cannot be null")
|
||||
|
||||
assertEquals(ShowExampleData().apply(example), result.toString())
|
||||
assertEquals("Example: name='${value.name}', ordinal='${value.ordinal}'", result.toString())
|
||||
assertEquals(SANDBOX_STRING, result::class.java.name)
|
||||
}
|
||||
}
|
||||
|
||||
class ShowExampleData : Function<ExampleData, String> {
|
||||
override fun apply(input: ExampleData): String {
|
||||
return with(input) {
|
||||
"Example: name='${value.name}', ordinal='${value.ordinal}'"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
@CordaSerializable
|
||||
enum class ExampleEnum {
|
||||
ONE,
|
||||
TWO,
|
||||
THREE
|
||||
}
|
||||
|
||||
@CordaSerializable
|
||||
data class ExampleData(val value: ExampleEnum)
|
@ -0,0 +1,81 @@
|
||||
package net.corda.djvm.serialization
|
||||
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import net.corda.core.serialization.internal._contextSerializationEnv
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.djvm.serialization.SandboxType.*
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Disabled
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.junit.jupiter.api.fail
|
||||
import java.util.function.Function
|
||||
|
||||
@ExtendWith(LocalSerialization::class)
|
||||
class DeserializeGenericsTest : TestBase(KOTLIN) {
|
||||
@Disabled
|
||||
@Test
|
||||
fun `test deserializing generic wrapper`() {
|
||||
val wrappedString = GenericWrapper(data = "Hello World!")
|
||||
val data = wrappedString.serialize()
|
||||
|
||||
sandbox {
|
||||
_contextSerializationEnv.set(createSandboxSerializationEnv(classLoader))
|
||||
|
||||
val sandboxWrapper = data.deserializeFor(classLoader)
|
||||
|
||||
val executor = createExecutorFor(classLoader)
|
||||
val result = executor.apply(
|
||||
classLoader.loadClassForSandbox(ShowGenericWrapper::class.java).newInstance(),
|
||||
sandboxWrapper
|
||||
) ?: fail("Result cannot be null")
|
||||
|
||||
assertEquals("Hello World!", result.toString())
|
||||
assertEquals(SANDBOX_STRING, result::class.java.name)
|
||||
}
|
||||
}
|
||||
|
||||
class ShowGenericWrapper : Function<GenericWrapper<String>, String> {
|
||||
override fun apply(input: GenericWrapper<String>): String {
|
||||
return input.data
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test deserializing concrete wrapper`() {
|
||||
val wrapped = ConcreteWrapper(
|
||||
first = GenericWrapper("Hello World"),
|
||||
second = GenericWrapper('!')
|
||||
)
|
||||
val data = wrapped.serialize()
|
||||
|
||||
sandbox {
|
||||
_contextSerializationEnv.set(createSandboxSerializationEnv(classLoader))
|
||||
|
||||
val sandboxWrapped = data.deserializeFor(classLoader)
|
||||
|
||||
val executor = createExecutorFor(classLoader)
|
||||
val result = executor.apply(
|
||||
classLoader.loadClassForSandbox(ShowConcreteWrapper::class.java).newInstance(),
|
||||
sandboxWrapped
|
||||
) ?: fail("Result cannot be null")
|
||||
|
||||
assertEquals("Concrete: first='Hello World', second='!'", result.toString())
|
||||
}
|
||||
}
|
||||
|
||||
class ShowConcreteWrapper : Function<ConcreteWrapper, String> {
|
||||
override fun apply(input: ConcreteWrapper): String {
|
||||
return "Concrete: first='${input.first.data}', second='${input.second.data}'"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@CordaSerializable
|
||||
data class GenericWrapper<T>(val data: T)
|
||||
|
||||
@CordaSerializable
|
||||
data class ConcreteWrapper(
|
||||
val first: GenericWrapper<String>,
|
||||
val second: GenericWrapper<Char>
|
||||
)
|
@ -0,0 +1,41 @@
|
||||
package net.corda.djvm.serialization
|
||||
|
||||
import net.corda.core.serialization.internal._contextSerializationEnv
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.djvm.serialization.SandboxType.*
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.junit.jupiter.api.fail
|
||||
import java.time.Instant
|
||||
import java.util.function.Function
|
||||
|
||||
@ExtendWith(LocalSerialization::class)
|
||||
class DeserializeInstantTest : TestBase(KOTLIN) {
|
||||
@Test
|
||||
fun `test deserializing instant`() {
|
||||
val instant = Instant.now()
|
||||
val data = instant.serialize()
|
||||
|
||||
sandbox {
|
||||
_contextSerializationEnv.set(createSandboxSerializationEnv(classLoader))
|
||||
|
||||
val sandboxInstant = data.deserializeFor(classLoader)
|
||||
|
||||
val executor = createExecutorFor(classLoader)
|
||||
val result = executor.apply(
|
||||
classLoader.loadClassForSandbox(ShowInstant::class.java).newInstance(),
|
||||
sandboxInstant
|
||||
) ?: fail("Result cannot be null")
|
||||
|
||||
assertEquals(instant.toString(), result.toString())
|
||||
assertEquals(SANDBOX_STRING, result::class.java.name)
|
||||
}
|
||||
}
|
||||
|
||||
class ShowInstant : Function<Instant, String> {
|
||||
override fun apply(instant: Instant): String {
|
||||
return instant.toString()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package net.corda.djvm.serialization
|
||||
|
||||
import net.corda.core.serialization.internal._contextSerializationEnv
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.djvm.serialization.SandboxType.*
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.junit.jupiter.api.fail
|
||||
|
||||
import java.util.function.Function
|
||||
|
||||
@ExtendWith(LocalSerialization::class)
|
||||
class DeserializeJavaWithMultipleConstructorsTest : TestBase(KOTLIN) {
|
||||
@Test
|
||||
fun `test deserializing existing class`() {
|
||||
val multiData = MultiConstructorData("Hello World", Long.MAX_VALUE, '!')
|
||||
val data = multiData.serialize()
|
||||
|
||||
sandbox {
|
||||
_contextSerializationEnv.set(createSandboxSerializationEnv(classLoader))
|
||||
|
||||
val sandboxData = data.deserializeFor(classLoader)
|
||||
|
||||
val executor = createExecutorFor(classLoader)
|
||||
val result = executor.apply(
|
||||
classLoader.loadClassForSandbox(ShowMultiData::class.java).newInstance(),
|
||||
sandboxData
|
||||
) ?: fail("Result cannot be null")
|
||||
|
||||
assertThat(result.toString())
|
||||
.isEqualTo("MultiConstructor[message='Hello World', bigNumber=9223372036854775807, tag=!]")
|
||||
}
|
||||
}
|
||||
|
||||
class ShowMultiData : Function<MultiConstructorData, String> {
|
||||
override fun apply(data: MultiConstructorData): String {
|
||||
return data.toString()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package net.corda.djvm.serialization
|
||||
|
||||
import net.corda.core.serialization.internal._contextSerializationEnv
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.djvm.serialization.SandboxType.*
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.junit.jupiter.api.fail
|
||||
import java.time.LocalDate
|
||||
import java.util.function.Function
|
||||
|
||||
@ExtendWith(LocalSerialization::class)
|
||||
class DeserializeLocalDateTest : TestBase(KOTLIN) {
|
||||
@Test
|
||||
fun `test deserializing local date`() {
|
||||
val date = LocalDate.now()
|
||||
val data = date.serialize()
|
||||
|
||||
sandbox {
|
||||
_contextSerializationEnv.set(createSandboxSerializationEnv(classLoader))
|
||||
|
||||
val sandboxDate = data.deserializeFor(classLoader)
|
||||
|
||||
val executor = createExecutorFor(classLoader)
|
||||
val result = executor.apply(
|
||||
classLoader.loadClassForSandbox(ShowLocalDate::class.java).newInstance(),
|
||||
sandboxDate
|
||||
) ?: fail("Result cannot be null")
|
||||
|
||||
assertEquals(date.toString(), result.toString())
|
||||
assertEquals(SANDBOX_STRING, result::class.java.name)
|
||||
}
|
||||
}
|
||||
|
||||
class ShowLocalDate : Function<LocalDate, String> {
|
||||
override fun apply(date: LocalDate): String {
|
||||
return date.toString()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package net.corda.djvm.serialization
|
||||
|
||||
import net.corda.core.serialization.internal._contextSerializationEnv
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.djvm.serialization.SandboxType.*
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.junit.jupiter.api.fail
|
||||
import java.time.LocalDateTime
|
||||
import java.util.function.Function
|
||||
|
||||
@ExtendWith(LocalSerialization::class)
|
||||
class DeserializeLocalDateTimeTest : TestBase(KOTLIN) {
|
||||
@Test
|
||||
fun `test deserializing local date-time`() {
|
||||
val dateTime = LocalDateTime.now()
|
||||
val data = dateTime.serialize()
|
||||
|
||||
sandbox {
|
||||
_contextSerializationEnv.set(createSandboxSerializationEnv(classLoader))
|
||||
|
||||
val sandboxDateTime = data.deserializeFor(classLoader)
|
||||
|
||||
val executor = createExecutorFor(classLoader)
|
||||
val result = executor.apply(
|
||||
classLoader.loadClassForSandbox(ShowLocalDateTime::class.java).newInstance(),
|
||||
sandboxDateTime
|
||||
) ?: fail("Result cannot be null")
|
||||
|
||||
assertEquals(dateTime.toString(), result.toString())
|
||||
assertEquals(SANDBOX_STRING, result::class.java.name)
|
||||
}
|
||||
}
|
||||
|
||||
class ShowLocalDateTime : Function<LocalDateTime, String> {
|
||||
override fun apply(dateTime: LocalDateTime): String {
|
||||
return dateTime.toString()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package net.corda.djvm.serialization
|
||||
|
||||
import net.corda.core.serialization.internal._contextSerializationEnv
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.djvm.serialization.SandboxType.*
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.junit.jupiter.api.fail
|
||||
import java.time.LocalTime
|
||||
import java.util.function.Function
|
||||
|
||||
@ExtendWith(LocalSerialization::class)
|
||||
class DeserializeLocalTimeTest : TestBase(KOTLIN) {
|
||||
@Test
|
||||
fun `test deserializing local time`() {
|
||||
val time = LocalTime.now()
|
||||
val data = time.serialize()
|
||||
|
||||
sandbox {
|
||||
_contextSerializationEnv.set(createSandboxSerializationEnv(classLoader))
|
||||
|
||||
val sandboxTime = data.deserializeFor(classLoader)
|
||||
|
||||
val executor = createExecutorFor(classLoader)
|
||||
val result = executor.apply(
|
||||
classLoader.loadClassForSandbox(ShowLocalTime::class.java).newInstance(),
|
||||
sandboxTime
|
||||
) ?: fail("Result cannot be null")
|
||||
|
||||
assertEquals(time.toString(), result.toString())
|
||||
assertEquals(SANDBOX_STRING, result::class.java.name)
|
||||
}
|
||||
}
|
||||
|
||||
class ShowLocalTime : Function<LocalTime, String> {
|
||||
override fun apply(time: LocalTime): String {
|
||||
return time.toString()
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user