mirror of
https://github.com/corda/corda.git
synced 2025-06-24 02:04:12 +00:00
CORDA-2876: Integrate the DJVM with the Corda Node. (#5633)
* * CORDA-2876: Migrate DJVM serialization modules into Corda. * Pre-generate Corda classes for DJVM sandbox when node boots in production mode. * Ensure that all DJVM test contract CorDapps are signed. * Test examining attachments within DJVM sandbox. * Test Contract.verify() using cryptographic verify function. * Add test cases for more non-determinism in Contract.verify(). * Update node-driver to support testing nodes with DJVM support. * Modify Node to allow alternative DJVM configurations for testing. * Refactor DeterministicVerifierFactoryService for default use-case. * Small whitespace and code-style refactors. * Create and activate a DJVM execution profile for the Node. * Revert making Verifier implement AutoCloseable. * Allow the node to cache sandboxed Corda byte-code for reuse. * Use updated Quasar agent that knows not to touch DJVM classloaders. * Fix Quasar's package exclusions globs for DJVM. * Deserialise LedgerTransaction into the sandbox for Contract.verify(). * Add the DJVM's serialisation modules to the Corda node. * Update the node for the latest DJVM API, and preserve the ConstructorForDeserialization annotation on user contract classes. * Add corda-dev to repositories while DJVM is SNAPSHOT. * Migrate DJVM specialisation into AbstractNode's ServiceHubInternalImpl. * Exclude sandbox.** and shaded djvm.** classes from Quasar agent. * Add the corda-dev repository to :node for the deterministic runtime. * Turn Verifier into an abstract base class that is specialised by BasicVerifier and DeterministicVerifier. * Add the Corda deterministic libraries to the Node, and split the DJVM sandbox across two SandboxClassLoader instances. * Add DJVM to contract verification path inside Corda Node. * Minor lambda simplifications and removing unused import. * CORDA-2871: Remove @CordaSerializable from LedgerTransaction. * CORDA-2871: Add a callback to ServicesForResolution to allow the Node to modify a LedgerTransaction object. * CORDA-2871: Refactor the contract verification code into a separate class, and allow LedgerTransaction to choose different Verifier objects. * Update DJVM to use Corda 4.4-SNAPSHOT. (#95) * CORDA-3330: Allow DJVM to preload / pregenerate classes from selected jars. (#92) * Add support for SourceClassLoader.getResources() to DJVM. * Allow a SandboxConfiguration to preload sandbox byte-code for all classes inside jars containing META-INF/DJVM-preload. * CORDA-3309: Remove explicit try-catch in favour of UncaughtExceptionHandler. (#91) * CORDA-3309: Install UncaughtExceptionHandler for DJVM tasks. (#88) * Fix tests broken by Windows line endings. (#82) * CORDA-3292: Reimplement ExecutionProfile as a data class. (#80) * CORDA-2877: Refactor how we create child SandboxConfiguration objects. (#76) * CORDA-2877: Load bytecode from a persistent cache to prevent repeated rewriting. (#75) * Refactor byte-code cache to SandboxConfiguration instead of AnalysisConfiguration. We cannot "mix and match" byte-code generated by different sets of rules. * CORDA-3137: Enhance annotation handling so that we can allow some annotations to be mapped into the sandbox without also needing to be stitched. (#72) * CORDA-2871: Minor cosmetic fixes. (#69) * CORDA-3218: Align DJVM with internal Corda Serialisation API. (#68) * Ensure we get the latest SNAPSHOT of the serialisation code. * CORDA-2871: Refactor SourceClassLoader to define source classes. (#66) * Rewrite SourceClassLoader to support parent/child relationships. * Revert catching TypNotPresebtException - it was a symptom of a bigger problem. * Remove AutoCloseable from AnalysisConfiguration and SourceClassLoader. * SourceClassLoader.getResource() must delegate to its parent first. * CORDA-2871: Ensure ClassLoader.loadClass() throws ClassNotFoundException for all cases where the class cannot be found. (#64) * CORDA-2871: Modify sandbox tasks to implement both java.Function and sandbox.Function (#62) * Make TaskExecutors implement BiFunction to make them composable. * Create ImportTask to wrap a java.Function inside a sandbox.Function. * Add createExecutor() and createRawExecutor() APIs to SandboxClassLoader. * Update serialization to use SandboxClassLoader.toSandboxClass(). * Remove a layer of lambdas from the serialisation code. * Update SandboxExecutor and SandboxRawExecutor. * Rename Executor to TaskFactory. * Rename dangling executor -> taskFactory. * CORDA-2871: Sanity fixes! (#63) * Improve message for SandboxClassLoadingException. * Fix serialisation API for using sandboxed environment. * CORDA-3174: Extend serialisation to include InputStream and OpaqueBytesSubSequence. (#60) * Update DJVM Example project for serialisation. * Add serializers for InputStream and OpaqueBytesSubSequence. * Support ZIP Inflater and CRC32 inside the sandbox. * Allow the DJVM to wrap java.io.InputStream as sandbox.java.io.InputStream. * Configure tests also to preserve @DeprecatedConstructorForDeserialization. * 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. * CORDA-2876: Only apply DJVM sources to Node Driver when devMode=true. * Resolve DeteKT warnings. * Require Node's JVM to set -Dnet.corda.djvm=true in order to enable DJVM. * Enable DJVM for DemoBench nodes. * Disable Quasar instrumentation verification for DemoBench nodes. * Upgrade to DJVM 1.0-RC01. * Try to modify DriverParameters in a more "ABI friendly" way. * Refactor and simplify sandbox deserialisation of primitive objects. * Review fixes. * Update EvolutionSerializerFactory to handle sandboxed primitive boxed types.
This commit is contained in:
committed by
Matthew Nesbit
parent
f9d8084d44
commit
f226ddc4f2
69
serialization-djvm/build.gradle
Normal file
69
serialization-djvm/build.gradle
Normal file
@ -0,0 +1,69 @@
|
||||
plugins {
|
||||
id 'org.jetbrains.kotlin.jvm'
|
||||
id 'net.corda.plugins.publish-utils'
|
||||
id 'com.jfrog.artifactory'
|
||||
id 'java-library'
|
||||
id 'idea'
|
||||
}
|
||||
|
||||
description 'Serialization support for the DJVM'
|
||||
|
||||
configurations {
|
||||
sandboxTesting
|
||||
jdkRt.resolutionStrategy {
|
||||
// Always check the repository for a newer SNAPSHOT.
|
||||
cacheChangingModulesFor 0, 'seconds'
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api project(':core')
|
||||
api project(':serialization')
|
||||
api "net.corda.djvm:corda-djvm:$djvm_version"
|
||||
implementation(project(':serialization-djvm:deserializers')) {
|
||||
transitive = false
|
||||
}
|
||||
|
||||
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-djvm:deserializers')
|
||||
sandboxTesting project(path: ':serialization-deterministic', configuration: 'deterministicArtifacts')
|
||||
sandboxTesting "org.slf4j:slf4j-nop:$slf4j_version"
|
||||
}
|
||||
|
||||
jar {
|
||||
archiveBaseName = 'corda-serialization-djvm'
|
||||
manifest {
|
||||
attributes('Automatic-Module-Name': 'net.corda.serialization.djvm')
|
||||
attributes('Sealed': true)
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType(Test) {
|
||||
useJUnitPlatform()
|
||||
systemProperty 'deterministic-rt.path', configurations.jdkRt.asPath
|
||||
systemProperty 'sandbox-libraries.path', configurations.sandboxTesting.asPath
|
||||
|
||||
// Configure the host timezone to match the DJVM's.
|
||||
systemProperty 'user.timezone', 'UTC'
|
||||
}
|
||||
|
||||
publish {
|
||||
name jar.archiveBaseName.get()
|
||||
}
|
||||
|
||||
idea {
|
||||
module {
|
||||
downloadJavadoc = true
|
||||
downloadSources = true
|
||||
}
|
||||
}
|
34
serialization-djvm/deserializers/build.gradle
Normal file
34
serialization-djvm/deserializers/build.gradle
Normal file
@ -0,0 +1,34 @@
|
||||
plugins {
|
||||
id 'org.jetbrains.kotlin.jvm'
|
||||
id 'net.corda.plugins.publish-utils'
|
||||
id 'com.jfrog.artifactory'
|
||||
id 'java-library'
|
||||
id 'idea'
|
||||
}
|
||||
apply from: '../../deterministic.gradle'
|
||||
|
||||
description 'Deserializers for the DJVM'
|
||||
|
||||
dependencies {
|
||||
api project(path: ':core-deterministic', configuration: 'deterministicArtifacts')
|
||||
api project(path: ':serialization-deterministic', configuration: 'deterministicArtifacts')
|
||||
}
|
||||
|
||||
jar {
|
||||
archiveBaseName = 'corda-deserializers-djvm'
|
||||
manifest {
|
||||
attributes('Automatic-Module-Name': 'net.corda.serialization.djvm.deserializers')
|
||||
attributes('Sealed': true)
|
||||
}
|
||||
}
|
||||
|
||||
publish {
|
||||
name jar.archiveBaseName.get()
|
||||
}
|
||||
|
||||
idea {
|
||||
module {
|
||||
downloadJavadoc = true
|
||||
downloadSources = true
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package net.corda.serialization.djvm.deserializers
|
||||
|
||||
import net.corda.serialization.internal.amqp.custom.BitSetSerializer.BitSetProxy
|
||||
import java.util.BitSet
|
||||
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.serialization.djvm.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.serialization.djvm.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,50 @@
|
||||
package net.corda.serialization.djvm.deserializers
|
||||
|
||||
import net.corda.core.utilities.NonEmptySet
|
||||
import java.util.Collections
|
||||
import java.util.NavigableSet
|
||||
import java.util.SortedSet
|
||||
import java.util.TreeSet
|
||||
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(values.toCollection(ArrayList()))
|
||||
}
|
||||
|
||||
private fun createSet(values: Array<Any?>): Set<Any?> {
|
||||
return Collections.unmodifiableSet(values.toCollection(LinkedHashSet()))
|
||||
}
|
||||
|
||||
private fun createSortedSet(values: Array<Any?>): SortedSet<Any?> {
|
||||
return Collections.unmodifiableSortedSet(values.toCollection(TreeSet()))
|
||||
}
|
||||
|
||||
private fun createNavigableSet(values: Array<Any?>): NavigableSet<Any?> {
|
||||
return Collections.unmodifiableNavigableSet(values.toCollection(TreeSet()))
|
||||
}
|
||||
|
||||
private fun createCollection(values: Array<Any?>): Collection<Any?> {
|
||||
return Collections.unmodifiableCollection(values.toCollection(ArrayList()))
|
||||
}
|
||||
|
||||
private fun createNonEmptySet(values: Array<Any?>): NonEmptySet<Any?> {
|
||||
return NonEmptySet.copyOf(values.toCollection(ArrayList()))
|
||||
}
|
||||
|
||||
@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.serialization.djvm.deserializers
|
||||
|
||||
import java.util.Currency
|
||||
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.serialization.djvm.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,52 @@
|
||||
package net.corda.serialization.djvm.deserializers
|
||||
|
||||
import java.util.Collections
|
||||
import java.util.EnumMap
|
||||
import java.util.NavigableMap
|
||||
import java.util.SortedMap
|
||||
import java.util.TreeMap
|
||||
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.serialization.djvm.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.serialization.djvm.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.serialization.djvm.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.serialization.djvm.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.serialization.djvm.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.serialization.djvm.deserializers
|
||||
|
||||
import net.corda.core.internal.uncheckedCast
|
||||
import net.corda.serialization.internal.amqp.custom.EnumSetSerializer.EnumSetProxy
|
||||
import java.util.EnumSet
|
||||
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.serialization.djvm.deserializers
|
||||
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.InputStream
|
||||
import java.util.function.Function
|
||||
|
||||
class InputStreamDeserializer : Function<ByteArray, InputStream?> {
|
||||
override fun apply(bytes: ByteArray): InputStream? {
|
||||
return ByteArrayInputStream(bytes)
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package net.corda.serialization.djvm.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.serialization.djvm.deserializers
|
||||
|
||||
@Suppress("unused")
|
||||
enum class JustForCasting {
|
||||
UNUSED
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package net.corda.serialization.djvm.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.serialization.djvm.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.serialization.djvm.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.serialization.djvm.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.serialization.djvm.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.serialization.djvm.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.serialization.djvm.deserializers
|
||||
|
||||
import net.corda.core.utilities.OpaqueBytes
|
||||
import net.corda.core.utilities.OpaqueBytesSubSequence
|
||||
import java.util.function.Function
|
||||
|
||||
class OpaqueBytesSubSequenceDeserializer : Function<OpaqueBytes, OpaqueBytesSubSequence> {
|
||||
override fun apply(proxy: OpaqueBytes): OpaqueBytesSubSequence {
|
||||
return OpaqueBytesSubSequence(proxy.bytes, proxy.offset, proxy.size)
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package net.corda.serialization.djvm.deserializers
|
||||
|
||||
import net.corda.serialization.internal.amqp.custom.OptionalSerializer.OptionalProxy
|
||||
import java.util.Optional
|
||||
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.serialization.djvm.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.serialization.djvm.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.serialization.djvm.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.serialization.djvm.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.serialization.djvm.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.serialization.djvm.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.serialization.djvm.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.serialization.djvm.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.serialization.djvm.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.serialization.djvm.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.serialization.djvm.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.serialization.djvm.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.serialization.djvm.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,131 @@
|
||||
package net.corda.serialization.djvm
|
||||
|
||||
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.serialization.djvm.serializers.SandboxBitSetSerializer
|
||||
import net.corda.serialization.djvm.serializers.SandboxCertPathSerializer
|
||||
import net.corda.serialization.djvm.serializers.SandboxCharacterSerializer
|
||||
import net.corda.serialization.djvm.serializers.SandboxCollectionSerializer
|
||||
import net.corda.serialization.djvm.serializers.SandboxCurrencySerializer
|
||||
import net.corda.serialization.djvm.serializers.SandboxDecimal128Serializer
|
||||
import net.corda.serialization.djvm.serializers.SandboxDecimal32Serializer
|
||||
import net.corda.serialization.djvm.serializers.SandboxDecimal64Serializer
|
||||
import net.corda.serialization.djvm.serializers.SandboxDurationSerializer
|
||||
import net.corda.serialization.djvm.serializers.SandboxEnumSerializer
|
||||
import net.corda.serialization.djvm.serializers.SandboxEnumSetSerializer
|
||||
import net.corda.serialization.djvm.serializers.SandboxInputStreamSerializer
|
||||
import net.corda.serialization.djvm.serializers.SandboxInstantSerializer
|
||||
import net.corda.serialization.djvm.serializers.SandboxLocalDateSerializer
|
||||
import net.corda.serialization.djvm.serializers.SandboxLocalDateTimeSerializer
|
||||
import net.corda.serialization.djvm.serializers.SandboxLocalTimeSerializer
|
||||
import net.corda.serialization.djvm.serializers.SandboxMapSerializer
|
||||
import net.corda.serialization.djvm.serializers.SandboxMonthDaySerializer
|
||||
import net.corda.serialization.djvm.serializers.SandboxOffsetDateTimeSerializer
|
||||
import net.corda.serialization.djvm.serializers.SandboxOffsetTimeSerializer
|
||||
import net.corda.serialization.djvm.serializers.SandboxOpaqueBytesSubSequenceSerializer
|
||||
import net.corda.serialization.djvm.serializers.SandboxOptionalSerializer
|
||||
import net.corda.serialization.djvm.serializers.SandboxPeriodSerializer
|
||||
import net.corda.serialization.djvm.serializers.SandboxPrimitiveSerializer
|
||||
import net.corda.serialization.djvm.serializers.SandboxPublicKeySerializer
|
||||
import net.corda.serialization.djvm.serializers.SandboxSymbolSerializer
|
||||
import net.corda.serialization.djvm.serializers.SandboxToStringSerializer
|
||||
import net.corda.serialization.djvm.serializers.SandboxUnsignedByteSerializer
|
||||
import net.corda.serialization.djvm.serializers.SandboxUnsignedIntegerSerializer
|
||||
import net.corda.serialization.djvm.serializers.SandboxUnsignedLongSerializer
|
||||
import net.corda.serialization.djvm.serializers.SandboxUnsignedShortSerializer
|
||||
import net.corda.serialization.djvm.serializers.SandboxX509CRLSerializer
|
||||
import net.corda.serialization.djvm.serializers.SandboxX509CertificateSerializer
|
||||
import net.corda.serialization.djvm.serializers.SandboxYearMonthSerializer
|
||||
import net.corda.serialization.djvm.serializers.SandboxYearSerializer
|
||||
import net.corda.serialization.djvm.serializers.SandboxZoneIdSerializer
|
||||
import net.corda.serialization.djvm.serializers.SandboxZonedDateTimeSerializer
|
||||
import net.corda.serialization.internal.CordaSerializationMagic
|
||||
import net.corda.serialization.internal.SerializationScheme
|
||||
import net.corda.serialization.internal.amqp.DeserializationInput
|
||||
import net.corda.serialization.internal.amqp.SerializationOutput
|
||||
import net.corda.serialization.internal.amqp.SerializerFactory
|
||||
import net.corda.serialization.internal.amqp.SerializerFactoryFactory
|
||||
import net.corda.serialization.internal.amqp.amqpMagic
|
||||
import java.math.BigDecimal
|
||||
import java.math.BigInteger
|
||||
import java.util.Date
|
||||
import java.util.UUID
|
||||
import java.util.function.Function
|
||||
|
||||
class AMQPSerializationScheme(
|
||||
private val classLoader: SandboxClassLoader,
|
||||
private val sandboxBasicInput: Function<in Any?, out Any?>,
|
||||
private val taskFactory: Function<in Any, out Function<in Any?, out Any?>>,
|
||||
private val serializerFactoryFactory: SerializerFactoryFactory
|
||||
) : SerializationScheme {
|
||||
|
||||
private fun getSerializerFactory(context: SerializationContext): SerializerFactory {
|
||||
return serializerFactoryFactory.make(context).apply {
|
||||
register(SandboxBitSetSerializer(classLoader, taskFactory, this))
|
||||
register(SandboxCertPathSerializer(classLoader, taskFactory, this))
|
||||
register(SandboxDurationSerializer(classLoader, taskFactory, this))
|
||||
register(SandboxEnumSetSerializer(classLoader, taskFactory, this))
|
||||
register(SandboxInputStreamSerializer(classLoader, taskFactory))
|
||||
register(SandboxInstantSerializer(classLoader, taskFactory, this))
|
||||
register(SandboxLocalDateSerializer(classLoader, taskFactory, this))
|
||||
register(SandboxLocalDateTimeSerializer(classLoader, taskFactory, this))
|
||||
register(SandboxLocalTimeSerializer(classLoader, taskFactory, this))
|
||||
register(SandboxMonthDaySerializer(classLoader, taskFactory, this))
|
||||
register(SandboxOffsetDateTimeSerializer(classLoader, taskFactory, this))
|
||||
register(SandboxOffsetTimeSerializer(classLoader, taskFactory, this))
|
||||
register(SandboxPeriodSerializer(classLoader, taskFactory, this))
|
||||
register(SandboxYearMonthSerializer(classLoader, taskFactory, this))
|
||||
register(SandboxYearSerializer(classLoader, taskFactory, this))
|
||||
register(SandboxZonedDateTimeSerializer(classLoader, taskFactory, this))
|
||||
register(SandboxZoneIdSerializer(classLoader, taskFactory, this))
|
||||
register(SandboxOpaqueBytesSubSequenceSerializer(classLoader, taskFactory, this))
|
||||
register(SandboxOptionalSerializer(classLoader, taskFactory, 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, taskFactory, this))
|
||||
register(SandboxMapSerializer(classLoader, taskFactory, this))
|
||||
register(SandboxEnumSerializer(classLoader, taskFactory, this))
|
||||
register(SandboxPublicKeySerializer(classLoader, taskFactory))
|
||||
register(SandboxToStringSerializer(BigDecimal::class.java, classLoader, taskFactory, sandboxBasicInput))
|
||||
register(SandboxToStringSerializer(BigInteger::class.java, classLoader, taskFactory, sandboxBasicInput))
|
||||
register(SandboxToStringSerializer(StringBuffer::class.java, classLoader, taskFactory, sandboxBasicInput))
|
||||
register(SandboxCurrencySerializer(classLoader, taskFactory, sandboxBasicInput))
|
||||
register(SandboxX509CertificateSerializer(classLoader, taskFactory))
|
||||
register(SandboxX509CRLSerializer(classLoader, taskFactory))
|
||||
register(SandboxUnsignedLongSerializer(classLoader, taskFactory))
|
||||
register(SandboxUnsignedIntegerSerializer(classLoader, taskFactory))
|
||||
register(SandboxUnsignedShortSerializer(classLoader, taskFactory))
|
||||
register(SandboxUnsignedByteSerializer(classLoader, taskFactory))
|
||||
register(SandboxDecimal128Serializer(classLoader, taskFactory))
|
||||
register(SandboxDecimal64Serializer(classLoader, taskFactory))
|
||||
register(SandboxDecimal32Serializer(classLoader, taskFactory))
|
||||
register(SandboxSymbolSerializer(classLoader, taskFactory, 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.serialization.djvm
|
||||
|
||||
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,108 @@
|
||||
@file:Suppress("platform_class_mapped_to_kotlin")
|
||||
package net.corda.serialization.djvm
|
||||
|
||||
import net.corda.core.serialization.SerializationContext
|
||||
import net.corda.serialization.internal.amqp.AMQPRemoteTypeModel
|
||||
import net.corda.serialization.internal.amqp.AMQPSerializer
|
||||
import net.corda.serialization.internal.amqp.CachingCustomSerializerRegistry
|
||||
import net.corda.serialization.internal.amqp.ComposedSerializerFactory
|
||||
import net.corda.serialization.internal.amqp.DefaultDescriptorBasedSerializerRegistry
|
||||
import net.corda.serialization.internal.amqp.DefaultEvolutionSerializerFactory
|
||||
import net.corda.serialization.internal.amqp.DefaultLocalSerializerFactory
|
||||
import net.corda.serialization.internal.amqp.DefaultRemoteSerializerFactory
|
||||
import net.corda.serialization.internal.amqp.SerializerFactory
|
||||
import net.corda.serialization.internal.amqp.SerializerFactoryFactory
|
||||
import net.corda.serialization.internal.amqp.WhitelistBasedTypeModelConfiguration
|
||||
import net.corda.serialization.internal.amqp.createClassCarpenter
|
||||
import net.corda.serialization.internal.model.ClassCarpentingTypeLoader
|
||||
import net.corda.serialization.internal.model.ConfigurableLocalTypeModel
|
||||
import net.corda.serialization.internal.model.SchemaBuildingRemoteTypeCarpenter
|
||||
import net.corda.serialization.internal.model.TypeLoader
|
||||
import net.corda.serialization.internal.model.TypeModellingFingerPrinter
|
||||
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.Date
|
||||
import java.util.UUID
|
||||
import java.util.function.Function
|
||||
import java.util.function.Predicate
|
||||
|
||||
/**
|
||||
* 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,
|
||||
classLoader.loadClass("sandbox.java.lang.String") to String::class.java,
|
||||
classLoader.loadClass("sandbox.java.util.Date") to Date::class.java,
|
||||
classLoader.loadClass("sandbox.java.util.UUID") to UUID::class.java,
|
||||
Void::class.java to Void.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,
|
||||
isPrimitiveType = Predicate { clazz -> clazz.isPrimitive || clazz in primitiveTypes.keys },
|
||||
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.serialization.djvm
|
||||
|
||||
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,74 @@
|
||||
@file:JvmName("Serialization")
|
||||
package net.corda.serialization.djvm
|
||||
|
||||
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.core.utilities.ByteSequence
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.serialization.djvm.serializers.PrimitiveSerializer
|
||||
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.util.function.Function
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
inline fun SandboxClassLoader.toSandboxAnyClass(clazz: Class<*>): Class<Any> {
|
||||
@Suppress("unchecked_cast")
|
||||
return toSandboxClass(clazz) 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 taskFactory = classLoader.createRawTaskFactory()
|
||||
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,
|
||||
taskFactory = taskFactory,
|
||||
serializerFactoryFactory = SandboxSerializerFactoryFactory(primitiveSerializerFactory)
|
||||
))
|
||||
}
|
||||
return SerializationEnvironment.with(factory, p2pContext = p2pContext)
|
||||
}
|
||||
|
||||
inline fun <reified T: Any> SerializedBytes<T>.deserializeFor(classLoader: SandboxClassLoader): Any {
|
||||
return deserializeTo(T::class.java, classLoader)
|
||||
}
|
||||
|
||||
inline fun <reified T: Any> ByteSequence.deserializeTypeFor(classLoader: SandboxClassLoader): Any {
|
||||
return deserializeTo(T::class.java, classLoader)
|
||||
}
|
||||
|
||||
fun <T: Any> ByteSequence.deserializeTo(clazz: Class<T>, classLoader: SandboxClassLoader): Any {
|
||||
val sandboxClazz = classLoader.toSandboxClass(clazz)
|
||||
return deserializeTo(sandboxClazz)
|
||||
}
|
||||
|
||||
fun ByteSequence.deserializeTo(clazz: Class<*>): Any {
|
||||
return deserializeTo(clazz, SerializationFactory.defaultFactory)
|
||||
}
|
||||
|
||||
fun ByteSequence.deserializeTo(clazz: Class<*>, factory: SerializationFactory): Any {
|
||||
return factory.deserialize(this, clazz, factory.defaultContext)
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
@file:JvmName("ExceptionUtils")
|
||||
package net.corda.serialization.djvm.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.
|
||||
*/
|
||||
@Suppress("TooGenericExceptionCaught")
|
||||
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,36 @@
|
||||
package net.corda.serialization.djvm.serializers
|
||||
|
||||
import net.corda.core.serialization.SerializationContext
|
||||
import net.corda.serialization.internal.amqp.AMQPSerializer
|
||||
import net.corda.serialization.internal.amqp.DeserializationInput
|
||||
import net.corda.serialization.internal.amqp.SerializationOutput
|
||||
import net.corda.serialization.internal.amqp.SerializationSchemas
|
||||
import net.corda.serialization.internal.amqp.typeDescriptorFor
|
||||
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.serialization.djvm.serializers
|
||||
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.serialization.djvm.deserializers.BitSetDeserializer
|
||||
import net.corda.serialization.djvm.toSandboxAnyClass
|
||||
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.BitSet
|
||||
import java.util.Collections.singleton
|
||||
import java.util.function.Function
|
||||
|
||||
class SandboxBitSetSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
taskFactory: Function<in Any, out Function<in Any?, out Any?>>,
|
||||
factory: SerializerFactory
|
||||
) : CustomSerializer.Proxy<Any, Any>(
|
||||
clazz = classLoader.toSandboxAnyClass(BitSet::class.java),
|
||||
proxyClass = classLoader.toSandboxAnyClass(BitSetProxy::class.java),
|
||||
factory = factory
|
||||
) {
|
||||
private val task = classLoader.createTaskFor(taskFactory, BitSetDeserializer::class.java)
|
||||
|
||||
override val deserializationAliases: Set<Class<*>> = singleton(BitSet::class.java)
|
||||
|
||||
override fun toProxy(obj: Any): Any = abortReadOnly()
|
||||
|
||||
override fun fromProxy(proxy: Any): Any {
|
||||
return task.apply(proxy)!!
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package net.corda.serialization.djvm.serializers
|
||||
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.serialization.djvm.deserializers.CertPathDeserializer
|
||||
import net.corda.serialization.djvm.toSandboxAnyClass
|
||||
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.Function
|
||||
|
||||
class SandboxCertPathSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
taskFactory: Function<in Any, out Function<in Any?, out Any?>>,
|
||||
factory: SerializerFactory
|
||||
) : CustomSerializer.Proxy<Any, Any>(
|
||||
clazz = classLoader.toSandboxAnyClass(CertPath::class.java),
|
||||
proxyClass = classLoader.toSandboxAnyClass(CertPathProxy::class.java),
|
||||
factory = factory
|
||||
) {
|
||||
private val task = classLoader.createTaskFor(taskFactory, CertPathDeserializer::class.java)
|
||||
|
||||
override val deserializationAliases: Set<Class<*>> = singleton(CertPath::class.java)
|
||||
|
||||
override fun toProxy(obj: Any): Any = abortReadOnly()
|
||||
|
||||
override fun fromProxy(proxy: Any): Any {
|
||||
return task.apply(proxy)!!
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package net.corda.serialization.djvm.serializers
|
||||
|
||||
import net.corda.core.serialization.SerializationContext
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.serialization.djvm.toSandboxAnyClass
|
||||
import net.corda.serialization.internal.amqp.CustomSerializer
|
||||
import net.corda.serialization.internal.amqp.DeserializationInput
|
||||
import net.corda.serialization.internal.amqp.Schema
|
||||
import net.corda.serialization.internal.amqp.SerializationOutput
|
||||
import net.corda.serialization.internal.amqp.SerializationSchemas
|
||||
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.toSandboxAnyClass(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,47 @@
|
||||
package net.corda.serialization.djvm.serializers
|
||||
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.serialization.djvm.deserializers.ClassDeserializer
|
||||
import net.corda.serialization.djvm.toSandboxAnyClass
|
||||
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.Function
|
||||
|
||||
@Suppress("unchecked_cast")
|
||||
class SandboxClassSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
taskFactory: Function<in Any, out Function<in Any?, out Any?>>,
|
||||
factory: SerializerFactory
|
||||
) : CustomSerializer.Proxy<Any, Any>(
|
||||
clazz = Class::class.java as Class<Any>,
|
||||
proxyClass = classLoader.toSandboxAnyClass(ClassProxy::class.java),
|
||||
factory = factory
|
||||
) {
|
||||
private val task = classLoader.createTaskFor(taskFactory, ClassDeserializer::class.java)
|
||||
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 {
|
||||
task.apply(proxy)!!
|
||||
} catch (e: ClassNotFoundException) {
|
||||
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,129 @@
|
||||
package net.corda.serialization.djvm.serializers
|
||||
|
||||
import net.corda.core.serialization.SerializationContext
|
||||
import net.corda.core.utilities.NonEmptySet
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.serialization.djvm.deserializers.CreateCollection
|
||||
import net.corda.serialization.djvm.toSandboxAnyClass
|
||||
import net.corda.serialization.internal.amqp.AMQPSerializer
|
||||
import net.corda.serialization.internal.amqp.CustomSerializer
|
||||
import net.corda.serialization.internal.amqp.DeserializationInput
|
||||
import net.corda.serialization.internal.amqp.LocalSerializerFactory
|
||||
import net.corda.serialization.internal.amqp.Schema
|
||||
import net.corda.serialization.internal.amqp.SerializationOutput
|
||||
import net.corda.serialization.internal.amqp.SerializationSchemas
|
||||
import net.corda.serialization.internal.amqp.redescribe
|
||||
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.EnumSet
|
||||
import java.util.NavigableSet
|
||||
import java.util.SortedSet
|
||||
import java.util.function.Function
|
||||
|
||||
class SandboxCollectionSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
taskFactory: Function<in Any, out Function<in Any?, out Any?>>,
|
||||
private val localFactory: LocalSerializerFactory
|
||||
) : CustomSerializer.Implements<Any>(clazz = classLoader.toSandboxAnyClass(Collection::class.java)) {
|
||||
@Suppress("unchecked_cast")
|
||||
private val creator: Function<Array<Any>, out Any?>
|
||||
= classLoader.createTaskFor(taskFactory, CreateCollection::class.java) as Function<Array<Any>, out Any?>
|
||||
|
||||
private val unsupportedTypes: Set<Class<Any>> = listOf(
|
||||
EnumSet::class.java
|
||||
).map {
|
||||
classLoader.toSandboxAnyClass(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.toSandboxAnyClass(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,41 @@
|
||||
package net.corda.serialization.djvm.serializers
|
||||
|
||||
import net.corda.core.serialization.SerializationContext
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.serialization.djvm.deserializers.CreateCurrency
|
||||
import net.corda.serialization.djvm.toSandboxAnyClass
|
||||
import net.corda.serialization.internal.amqp.CustomSerializer
|
||||
import net.corda.serialization.internal.amqp.DeserializationInput
|
||||
import net.corda.serialization.internal.amqp.Schema
|
||||
import net.corda.serialization.internal.amqp.SerializationOutput
|
||||
import net.corda.serialization.internal.amqp.SerializationSchemas
|
||||
import org.apache.qpid.proton.codec.Data
|
||||
import java.lang.reflect.Type
|
||||
import java.util.Collections.singleton
|
||||
import java.util.Currency
|
||||
import java.util.function.Function
|
||||
|
||||
class SandboxCurrencySerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
taskFactory: Function<in Any, out Function<in Any?, out Any?>>,
|
||||
basicInput: Function<in Any?, out Any?>
|
||||
) : CustomSerializer.Is<Any>(classLoader.toSandboxAnyClass(Currency::class.java)) {
|
||||
private val creator: Function<Any?, Any?>
|
||||
|
||||
init {
|
||||
val createTask = classLoader.createTaskFor(taskFactory, CreateCurrency::class.java)
|
||||
creator = basicInput.andThen(createTask)
|
||||
}
|
||||
|
||||
override val deserializationAliases: Set<Class<*>> = 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,35 @@
|
||||
package net.corda.serialization.djvm.serializers
|
||||
|
||||
import net.corda.core.serialization.SerializationContext
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.serialization.djvm.deserializers.Decimal128Deserializer
|
||||
import net.corda.serialization.djvm.toSandboxAnyClass
|
||||
import net.corda.serialization.internal.amqp.CustomSerializer
|
||||
import net.corda.serialization.internal.amqp.DeserializationInput
|
||||
import net.corda.serialization.internal.amqp.Schema
|
||||
import net.corda.serialization.internal.amqp.SerializationOutput
|
||||
import net.corda.serialization.internal.amqp.SerializationSchemas
|
||||
import org.apache.qpid.proton.amqp.Decimal128
|
||||
import org.apache.qpid.proton.codec.Data
|
||||
import java.lang.reflect.Type
|
||||
import java.util.function.Function
|
||||
|
||||
class SandboxDecimal128Serializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
taskFactory: Function<in Any, out Function<in Any?, out Any?>>
|
||||
) : CustomSerializer.Is<Any>(classLoader.toSandboxAnyClass(Decimal128::class.java)) {
|
||||
@Suppress("unchecked_cast")
|
||||
private val transformer: Function<LongArray, out Any?>
|
||||
= classLoader.createTaskFor(taskFactory, Decimal128Deserializer::class.java) as Function<LongArray, out Any?>
|
||||
|
||||
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,34 @@
|
||||
package net.corda.serialization.djvm.serializers
|
||||
|
||||
import net.corda.core.serialization.SerializationContext
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.serialization.djvm.deserializers.Decimal32Deserializer
|
||||
import net.corda.serialization.djvm.toSandboxAnyClass
|
||||
import net.corda.serialization.internal.amqp.CustomSerializer
|
||||
import net.corda.serialization.internal.amqp.DeserializationInput
|
||||
import net.corda.serialization.internal.amqp.Schema
|
||||
import net.corda.serialization.internal.amqp.SerializationOutput
|
||||
import net.corda.serialization.internal.amqp.SerializationSchemas
|
||||
import org.apache.qpid.proton.amqp.Decimal32
|
||||
import org.apache.qpid.proton.codec.Data
|
||||
import java.lang.reflect.Type
|
||||
import java.util.function.Function
|
||||
|
||||
class SandboxDecimal32Serializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
taskFactory: Function<in Any, out Function<in Any?, out Any?>>
|
||||
) : CustomSerializer.Is<Any>(classLoader.toSandboxAnyClass(Decimal32::class.java)) {
|
||||
@Suppress("unchecked_cast")
|
||||
private val transformer: Function<IntArray, out Any?>
|
||||
= classLoader.createTaskFor(taskFactory, Decimal32Deserializer::class.java) as Function<IntArray, out Any?>
|
||||
|
||||
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,34 @@
|
||||
package net.corda.serialization.djvm.serializers
|
||||
|
||||
import net.corda.core.serialization.SerializationContext
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.serialization.djvm.deserializers.Decimal64Deserializer
|
||||
import net.corda.serialization.djvm.toSandboxAnyClass
|
||||
import net.corda.serialization.internal.amqp.CustomSerializer
|
||||
import net.corda.serialization.internal.amqp.DeserializationInput
|
||||
import net.corda.serialization.internal.amqp.Schema
|
||||
import net.corda.serialization.internal.amqp.SerializationOutput
|
||||
import net.corda.serialization.internal.amqp.SerializationSchemas
|
||||
import org.apache.qpid.proton.amqp.Decimal64
|
||||
import org.apache.qpid.proton.codec.Data
|
||||
import java.lang.reflect.Type
|
||||
import java.util.function.Function
|
||||
|
||||
class SandboxDecimal64Serializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
taskFactory: Function<in Any, out Function<in Any?, out Any?>>
|
||||
) : CustomSerializer.Is<Any>(classLoader.toSandboxAnyClass(Decimal64::class.java)) {
|
||||
@Suppress("unchecked_cast")
|
||||
private val transformer: Function<LongArray, out Any?>
|
||||
= classLoader.createTaskFor(taskFactory, Decimal64Deserializer::class.java) as Function<LongArray, out Any?>
|
||||
|
||||
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.serialization.djvm.serializers
|
||||
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.serialization.djvm.deserializers.DurationDeserializer
|
||||
import net.corda.serialization.djvm.toSandboxAnyClass
|
||||
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.Function
|
||||
|
||||
class SandboxDurationSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
taskFactory: Function<in Any, out Function<in Any?, out Any?>>,
|
||||
factory: SerializerFactory
|
||||
) : CustomSerializer.Proxy<Any, Any>(
|
||||
clazz = classLoader.toSandboxAnyClass(Duration::class.java),
|
||||
proxyClass = classLoader.toSandboxAnyClass(DurationProxy::class.java),
|
||||
factory = factory
|
||||
) {
|
||||
private val task = classLoader.createTaskFor(taskFactory, DurationDeserializer::class.java)
|
||||
|
||||
override val deserializationAliases: Set<Class<*>> = singleton(Duration::class.java)
|
||||
|
||||
override fun toProxy(obj: Any): Any = abortReadOnly()
|
||||
|
||||
override fun fromProxy(proxy: Any): Any {
|
||||
return task.apply(proxy)!!
|
||||
}
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
package net.corda.serialization.djvm.serializers
|
||||
|
||||
import net.corda.core.serialization.SerializationContext
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.serialization.djvm.deserializers.DescribeEnum
|
||||
import net.corda.serialization.djvm.toSandboxAnyClass
|
||||
import net.corda.serialization.internal.amqp.AMQPNotSerializableException
|
||||
import net.corda.serialization.internal.amqp.AMQPSerializer
|
||||
import net.corda.serialization.internal.amqp.CustomSerializer
|
||||
import net.corda.serialization.internal.amqp.DeserializationInput
|
||||
import net.corda.serialization.internal.amqp.LocalSerializerFactory
|
||||
import net.corda.serialization.internal.amqp.Schema
|
||||
import net.corda.serialization.internal.amqp.SerializationOutput
|
||||
import net.corda.serialization.internal.amqp.SerializationSchemas
|
||||
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.Function
|
||||
|
||||
class SandboxEnumSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
taskFactory: Function<in Any, out Function<in Any?, out Any?>>,
|
||||
private val localFactory: LocalSerializerFactory
|
||||
) : CustomSerializer.Implements<Any>(clazz = classLoader.toSandboxAnyClass(Enum::class.java)) {
|
||||
@Suppress("unchecked_cast")
|
||||
private val describer: Function<Class<*>, Array<Any>>
|
||||
= classLoader.createTaskFor(taskFactory, DescribeEnum::class.java) as Function<Class<*>, 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.serialization.djvm.serializers
|
||||
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.serialization.djvm.deserializers.EnumSetDeserializer
|
||||
import net.corda.serialization.djvm.toSandboxAnyClass
|
||||
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.Collections.singleton
|
||||
import java.util.EnumSet
|
||||
import java.util.function.Function
|
||||
|
||||
class SandboxEnumSetSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
taskFactory: Function<in Any, out Function<in Any?, out Any?>>,
|
||||
factory: SerializerFactory
|
||||
) : CustomSerializer.Proxy<Any, Any>(
|
||||
clazz = classLoader.toSandboxAnyClass(EnumSet::class.java),
|
||||
proxyClass = classLoader.toSandboxAnyClass(EnumSetProxy::class.java),
|
||||
factory = factory
|
||||
) {
|
||||
private val task = classLoader.createTaskFor(taskFactory, EnumSetDeserializer::class.java)
|
||||
|
||||
override val additionalSerializers: Set<CustomSerializer<out Any>> = singleton(
|
||||
SandboxClassSerializer(classLoader, taskFactory, factory)
|
||||
)
|
||||
|
||||
override val deserializationAliases: Set<Class<*>> = singleton(EnumSet::class.java)
|
||||
|
||||
override fun toProxy(obj: Any): Any = abortReadOnly()
|
||||
|
||||
override fun fromProxy(proxy: Any): Any {
|
||||
return task.apply(proxy)!!
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package net.corda.serialization.djvm.serializers
|
||||
|
||||
import net.corda.core.serialization.SerializationContext
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.serialization.djvm.deserializers.InputStreamDeserializer
|
||||
import net.corda.serialization.djvm.toSandboxAnyClass
|
||||
import net.corda.serialization.internal.amqp.CustomSerializer
|
||||
import net.corda.serialization.internal.amqp.DeserializationInput
|
||||
import net.corda.serialization.internal.amqp.Schema
|
||||
import net.corda.serialization.internal.amqp.SerializationOutput
|
||||
import net.corda.serialization.internal.amqp.SerializationSchemas
|
||||
import org.apache.qpid.proton.codec.Data
|
||||
import java.io.InputStream
|
||||
import java.lang.reflect.Type
|
||||
import java.util.Collections.singleton
|
||||
import java.util.function.Function
|
||||
|
||||
class SandboxInputStreamSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
taskFactory: Function<in Any, out Function<in Any?, out Any?>>
|
||||
) : CustomSerializer.Implements<Any>(classLoader.toSandboxAnyClass(InputStream::class.java)) {
|
||||
@Suppress("unchecked_cast")
|
||||
private val decoder: Function<ByteArray, out Any?>
|
||||
= classLoader.createTaskFor(taskFactory, InputStreamDeserializer::class.java) as Function<ByteArray, out Any?>
|
||||
|
||||
override val schemaForDocumentation: Schema = Schema(emptyList())
|
||||
|
||||
override val deserializationAliases: Set<Class<*>> = singleton(InputStream::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,31 @@
|
||||
package net.corda.serialization.djvm.serializers
|
||||
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.serialization.djvm.deserializers.InstantDeserializer
|
||||
import net.corda.serialization.djvm.toSandboxAnyClass
|
||||
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.Function
|
||||
|
||||
class SandboxInstantSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
taskFactory: Function<in Any, out Function<in Any?, out Any?>>,
|
||||
factory: SerializerFactory
|
||||
) : CustomSerializer.Proxy<Any, Any>(
|
||||
clazz = classLoader.toSandboxAnyClass(Instant::class.java),
|
||||
proxyClass = classLoader.toSandboxAnyClass(InstantProxy::class.java),
|
||||
factory = factory
|
||||
) {
|
||||
private val task = classLoader.createTaskFor(taskFactory, InstantDeserializer::class.java)
|
||||
|
||||
override val deserializationAliases: Set<Class<*>> = singleton(Instant::class.java)
|
||||
|
||||
override fun toProxy(obj: Any): Any = abortReadOnly()
|
||||
|
||||
override fun fromProxy(proxy: Any): Any {
|
||||
return task.apply(proxy)!!
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package net.corda.serialization.djvm.serializers
|
||||
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.serialization.djvm.deserializers.LocalDateDeserializer
|
||||
import net.corda.serialization.djvm.toSandboxAnyClass
|
||||
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.Function
|
||||
|
||||
class SandboxLocalDateSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
taskFactory: Function<in Any, out Function<in Any?, out Any?>>,
|
||||
factory: SerializerFactory
|
||||
) : CustomSerializer.Proxy<Any, Any>(
|
||||
clazz = classLoader.toSandboxAnyClass(LocalDate::class.java),
|
||||
proxyClass = classLoader.toSandboxAnyClass(LocalDateProxy::class.java),
|
||||
factory = factory
|
||||
) {
|
||||
private val task = classLoader.createTaskFor(taskFactory, LocalDateDeserializer::class.java)
|
||||
|
||||
override val deserializationAliases: Set<Class<*>> = singleton(LocalDate::class.java)
|
||||
|
||||
override fun toProxy(obj: Any): Any = abortReadOnly()
|
||||
|
||||
override fun fromProxy(proxy: Any): Any {
|
||||
return task.apply(proxy)!!
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package net.corda.serialization.djvm.serializers
|
||||
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.serialization.djvm.deserializers.LocalDateTimeDeserializer
|
||||
import net.corda.serialization.djvm.toSandboxAnyClass
|
||||
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.Function
|
||||
|
||||
class SandboxLocalDateTimeSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
taskFactory: Function<in Any, out Function<in Any?, out Any?>>,
|
||||
factory: SerializerFactory
|
||||
) : CustomSerializer.Proxy<Any, Any>(
|
||||
clazz = classLoader.toSandboxAnyClass(LocalDateTime::class.java),
|
||||
proxyClass = classLoader.toSandboxAnyClass(LocalDateTimeProxy::class.java),
|
||||
factory = factory
|
||||
) {
|
||||
private val task = classLoader.createTaskFor(taskFactory, LocalDateTimeDeserializer::class.java)
|
||||
|
||||
override val deserializationAliases: Set<Class<*>> = singleton(LocalDateTime::class.java)
|
||||
|
||||
override fun toProxy(obj: Any): Any = abortReadOnly()
|
||||
|
||||
override fun fromProxy(proxy: Any): Any {
|
||||
return task.apply(proxy)!!
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package net.corda.serialization.djvm.serializers
|
||||
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.serialization.djvm.deserializers.LocalTimeDeserializer
|
||||
import net.corda.serialization.djvm.toSandboxAnyClass
|
||||
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.Function
|
||||
|
||||
class SandboxLocalTimeSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
taskFactory: Function<in Any, out Function<in Any?, out Any?>>,
|
||||
factory: SerializerFactory
|
||||
) : CustomSerializer.Proxy<Any, Any>(
|
||||
clazz = classLoader.toSandboxAnyClass(LocalTime::class.java),
|
||||
proxyClass = classLoader.toSandboxAnyClass(LocalTimeProxy::class.java),
|
||||
factory = factory
|
||||
) {
|
||||
private val task = classLoader.createTaskFor(taskFactory, LocalTimeDeserializer::class.java)
|
||||
|
||||
override val deserializationAliases: Set<Class<*>> = singleton(LocalTime::class.java)
|
||||
|
||||
override fun toProxy(obj: Any): Any = abortReadOnly()
|
||||
|
||||
override fun fromProxy(proxy: Any): Any {
|
||||
return task.apply(proxy)!!
|
||||
}
|
||||
}
|
@ -0,0 +1,124 @@
|
||||
package net.corda.serialization.djvm.serializers
|
||||
|
||||
import net.corda.core.serialization.SerializationContext
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.serialization.djvm.deserializers.CreateMap
|
||||
import net.corda.serialization.djvm.toSandboxAnyClass
|
||||
import net.corda.serialization.internal.amqp.AMQPSerializer
|
||||
import net.corda.serialization.internal.amqp.CustomSerializer
|
||||
import net.corda.serialization.internal.amqp.DeserializationInput
|
||||
import net.corda.serialization.internal.amqp.LocalSerializerFactory
|
||||
import net.corda.serialization.internal.amqp.Schema
|
||||
import net.corda.serialization.internal.amqp.SerializationOutput
|
||||
import net.corda.serialization.internal.amqp.SerializationSchemas
|
||||
import net.corda.serialization.internal.amqp.redescribe
|
||||
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.EnumMap
|
||||
import java.util.NavigableMap
|
||||
import java.util.SortedMap
|
||||
import java.util.TreeMap
|
||||
import java.util.function.Function
|
||||
|
||||
class SandboxMapSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
taskFactory: Function<in Any, out Function<in Any?, out Any?>>,
|
||||
private val localFactory: LocalSerializerFactory
|
||||
) : CustomSerializer.Implements<Any>(clazz = classLoader.toSandboxAnyClass(Map::class.java)) {
|
||||
@Suppress("unchecked_cast")
|
||||
private val creator: Function<Array<Any>, out Any?>
|
||||
= classLoader.createTaskFor(taskFactory, CreateMap::class.java) as Function<Array<Any>, out Any?>
|
||||
|
||||
// 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.toSandboxAnyClass(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.serialization.djvm.serializers
|
||||
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.serialization.djvm.deserializers.MonthDayDeserializer
|
||||
import net.corda.serialization.djvm.toSandboxAnyClass
|
||||
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.Function
|
||||
|
||||
class SandboxMonthDaySerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
taskFactory: Function<in Any, out Function<in Any?, out Any?>>,
|
||||
factory: SerializerFactory
|
||||
) : CustomSerializer.Proxy<Any, Any>(
|
||||
clazz = classLoader.toSandboxAnyClass(MonthDay::class.java),
|
||||
proxyClass = classLoader.toSandboxAnyClass(MonthDayProxy::class.java),
|
||||
factory = factory
|
||||
) {
|
||||
private val task = classLoader.createTaskFor(taskFactory, MonthDayDeserializer::class.java)
|
||||
|
||||
override val deserializationAliases: Set<Class<*>> = singleton(MonthDay::class.java)
|
||||
|
||||
override fun toProxy(obj: Any): Any = abortReadOnly()
|
||||
|
||||
override fun fromProxy(proxy: Any): Any {
|
||||
return task.apply(proxy)!!
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package net.corda.serialization.djvm.serializers
|
||||
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.serialization.djvm.deserializers.OffsetDateTimeDeserializer
|
||||
import net.corda.serialization.djvm.toSandboxAnyClass
|
||||
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.Function
|
||||
|
||||
class SandboxOffsetDateTimeSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
taskFactory: Function<in Any, out Function<in Any?, out Any?>>,
|
||||
factory: SerializerFactory
|
||||
) : CustomSerializer.Proxy<Any, Any>(
|
||||
clazz = classLoader.toSandboxAnyClass(OffsetDateTime::class.java),
|
||||
proxyClass = classLoader.toSandboxAnyClass(OffsetDateTimeProxy::class.java),
|
||||
factory = factory
|
||||
) {
|
||||
private val task = classLoader.createTaskFor(taskFactory, OffsetDateTimeDeserializer::class.java)
|
||||
|
||||
override val deserializationAliases: Set<Class<*>> = singleton(OffsetDateTime::class.java)
|
||||
|
||||
override fun toProxy(obj: Any): Any = abortReadOnly()
|
||||
|
||||
override fun fromProxy(proxy: Any): Any {
|
||||
return task.apply(proxy)!!
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package net.corda.serialization.djvm.serializers
|
||||
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.serialization.djvm.deserializers.OffsetTimeDeserializer
|
||||
import net.corda.serialization.djvm.toSandboxAnyClass
|
||||
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.Function
|
||||
|
||||
class SandboxOffsetTimeSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
taskFactory: Function<in Any, out Function<in Any?, out Any?>>,
|
||||
factory: SerializerFactory
|
||||
) : CustomSerializer.Proxy<Any, Any>(
|
||||
clazz = classLoader.toSandboxAnyClass(OffsetTime::class.java),
|
||||
proxyClass = classLoader.toSandboxAnyClass(OffsetTimeProxy::class.java),
|
||||
factory = factory
|
||||
) {
|
||||
private val task = classLoader.createTaskFor(taskFactory, OffsetTimeDeserializer::class.java)
|
||||
|
||||
override val deserializationAliases: Set<Class<*>> = singleton(OffsetTime::class.java)
|
||||
|
||||
override fun toProxy(obj: Any): Any = abortReadOnly()
|
||||
|
||||
override fun fromProxy(proxy: Any): Any {
|
||||
return task.apply(proxy)!!
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package net.corda.serialization.djvm.serializers
|
||||
|
||||
import net.corda.core.utilities.OpaqueBytes
|
||||
import net.corda.core.utilities.OpaqueBytesSubSequence
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.serialization.djvm.deserializers.OpaqueBytesSubSequenceDeserializer
|
||||
import net.corda.serialization.djvm.toSandboxAnyClass
|
||||
import net.corda.serialization.internal.amqp.CustomSerializer
|
||||
import net.corda.serialization.internal.amqp.SerializerFactory
|
||||
import java.util.Collections.singleton
|
||||
import java.util.function.Function
|
||||
|
||||
class SandboxOpaqueBytesSubSequenceSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
taskFactory: Function<in Any, out Function<in Any?, out Any?>>,
|
||||
factory: SerializerFactory
|
||||
) : CustomSerializer.Proxy<Any, Any>(
|
||||
clazz = classLoader.toSandboxAnyClass(OpaqueBytesSubSequence::class.java),
|
||||
proxyClass = classLoader.toSandboxAnyClass(OpaqueBytes::class.java),
|
||||
factory = factory
|
||||
) {
|
||||
private val task = classLoader.createTaskFor(taskFactory, OpaqueBytesSubSequenceDeserializer::class.java)
|
||||
|
||||
override val deserializationAliases: Set<Class<*>> = singleton(OpaqueBytesSubSequence::class.java)
|
||||
|
||||
override fun toProxy(obj: Any): Any = abortReadOnly()
|
||||
|
||||
override fun fromProxy(proxy: Any): Any {
|
||||
return task.apply(proxy)!!
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package net.corda.serialization.djvm.serializers
|
||||
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.serialization.djvm.deserializers.OptionalDeserializer
|
||||
import net.corda.serialization.djvm.toSandboxAnyClass
|
||||
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.Collections.singleton
|
||||
import java.util.Optional
|
||||
import java.util.function.Function
|
||||
|
||||
class SandboxOptionalSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
taskFactory: Function<in Any, out Function<in Any?, out Any?>>,
|
||||
factory: SerializerFactory
|
||||
) : CustomSerializer.Proxy<Any, Any>(
|
||||
clazz = classLoader.toSandboxAnyClass(Optional::class.java),
|
||||
proxyClass = classLoader.toSandboxAnyClass(OptionalProxy::class.java),
|
||||
factory = factory
|
||||
) {
|
||||
private val task = classLoader.createTaskFor(taskFactory, OptionalDeserializer::class.java)
|
||||
|
||||
override val deserializationAliases: Set<Class<*>> = singleton(Optional::class.java)
|
||||
|
||||
override fun toProxy(obj: Any): Any = abortReadOnly()
|
||||
|
||||
override fun fromProxy(proxy: Any): Any {
|
||||
return task.apply(proxy)!!
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package net.corda.serialization.djvm.serializers
|
||||
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.serialization.djvm.deserializers.PeriodDeserializer
|
||||
import net.corda.serialization.djvm.toSandboxAnyClass
|
||||
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.Function
|
||||
|
||||
class SandboxPeriodSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
taskFactory: Function<in Any, out Function<in Any?, out Any?>>,
|
||||
factory: SerializerFactory
|
||||
) : CustomSerializer.Proxy<Any, Any>(
|
||||
clazz = classLoader.toSandboxAnyClass(Period::class.java),
|
||||
proxyClass = classLoader.toSandboxAnyClass(PeriodProxy::class.java),
|
||||
factory = factory
|
||||
) {
|
||||
private val task = classLoader.createTaskFor(taskFactory, PeriodDeserializer::class.java)
|
||||
|
||||
override val deserializationAliases: Set<Class<*>> = singleton(Period::class.java)
|
||||
|
||||
override fun toProxy(obj: Any): Any = abortReadOnly()
|
||||
|
||||
override fun fromProxy(proxy: Any): Any {
|
||||
return task.apply(proxy)!!
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package net.corda.serialization.djvm.serializers
|
||||
|
||||
import net.corda.core.serialization.SerializationContext
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.serialization.djvm.toSandboxAnyClass
|
||||
import net.corda.serialization.internal.amqp.CustomSerializer
|
||||
import net.corda.serialization.internal.amqp.DeserializationInput
|
||||
import net.corda.serialization.internal.amqp.Schema
|
||||
import net.corda.serialization.internal.amqp.SerializationOutput
|
||||
import net.corda.serialization.internal.amqp.SerializationSchemas
|
||||
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.toSandboxAnyClass(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,38 @@
|
||||
package net.corda.serialization.djvm.serializers
|
||||
|
||||
import net.corda.core.serialization.SerializationContext
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.serialization.djvm.deserializers.PublicKeyDecoder
|
||||
import net.corda.serialization.djvm.toSandboxAnyClass
|
||||
import net.corda.serialization.internal.amqp.CustomSerializer
|
||||
import net.corda.serialization.internal.amqp.DeserializationInput
|
||||
import net.corda.serialization.internal.amqp.Schema
|
||||
import net.corda.serialization.internal.amqp.SerializationOutput
|
||||
import net.corda.serialization.internal.amqp.SerializationSchemas
|
||||
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.Function
|
||||
|
||||
class SandboxPublicKeySerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
taskFactory: Function<in Any, out Function<in Any?, out Any?>>
|
||||
) : CustomSerializer.Implements<Any>(classLoader.toSandboxAnyClass(PublicKey::class.java)) {
|
||||
@Suppress("unchecked_cast")
|
||||
private val decoder: Function<ByteArray, out Any?>
|
||||
= classLoader.createTaskFor(taskFactory, PublicKeyDecoder::class.java) as Function<ByteArray, out Any?>
|
||||
|
||||
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,39 @@
|
||||
package net.corda.serialization.djvm.serializers
|
||||
|
||||
import net.corda.core.serialization.SerializationContext
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.serialization.djvm.deserializers.SymbolDeserializer
|
||||
import net.corda.serialization.djvm.toSandboxAnyClass
|
||||
import net.corda.serialization.internal.amqp.CustomSerializer
|
||||
import net.corda.serialization.internal.amqp.DeserializationInput
|
||||
import net.corda.serialization.internal.amqp.Schema
|
||||
import net.corda.serialization.internal.amqp.SerializationOutput
|
||||
import net.corda.serialization.internal.amqp.SerializationSchemas
|
||||
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 SandboxSymbolSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
taskFactory: Function<in Any, out Function<in Any?, out Any?>>,
|
||||
basicInput: Function<in Any?, out Any?>
|
||||
) : CustomSerializer.Is<Any>(classLoader.toSandboxAnyClass(Symbol::class.java)) {
|
||||
private val transformer: Function<String, out Any?>
|
||||
|
||||
init {
|
||||
val transformTask = classLoader.createTaskFor(taskFactory, SymbolDeserializer::class.java)
|
||||
@Suppress("unchecked_cast")
|
||||
transformer = basicInput.andThen(transformTask) 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,45 @@
|
||||
package net.corda.serialization.djvm.serializers
|
||||
|
||||
import net.corda.core.serialization.SerializationContext
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.serialization.djvm.deserializers.CreateFromString
|
||||
import net.corda.serialization.djvm.toSandboxAnyClass
|
||||
import net.corda.serialization.internal.amqp.CustomSerializer
|
||||
import net.corda.serialization.internal.amqp.DeserializationInput
|
||||
import net.corda.serialization.internal.amqp.Schema
|
||||
import net.corda.serialization.internal.amqp.SerializationOutput
|
||||
import net.corda.serialization.internal.amqp.SerializationSchemas
|
||||
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.Function
|
||||
|
||||
class SandboxToStringSerializer(
|
||||
unsafeClass: Class<*>,
|
||||
classLoader: SandboxClassLoader,
|
||||
taskFactory: Function<in Any, out Function<in Any?, out Any?>>,
|
||||
basicInput: Function<in Any?, out Any?>
|
||||
) : CustomSerializer.Is<Any>(classLoader.toSandboxAnyClass(unsafeClass)) {
|
||||
private val creator: Function<Any?, Any?>
|
||||
|
||||
init {
|
||||
val stringClass = classLoader.loadClass("sandbox.java.lang.String")
|
||||
val createTask = classLoader.toSandboxClass(CreateFromString::class.java)
|
||||
.getConstructor(Constructor::class.java)
|
||||
.newInstance(clazz.getConstructor(stringClass))
|
||||
creator = basicInput.andThen(taskFactory.apply(createTask))
|
||||
}
|
||||
|
||||
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,34 @@
|
||||
package net.corda.serialization.djvm.serializers
|
||||
|
||||
import net.corda.core.serialization.SerializationContext
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.serialization.djvm.deserializers.UnsignedByteDeserializer
|
||||
import net.corda.serialization.djvm.toSandboxAnyClass
|
||||
import net.corda.serialization.internal.amqp.CustomSerializer
|
||||
import net.corda.serialization.internal.amqp.DeserializationInput
|
||||
import net.corda.serialization.internal.amqp.Schema
|
||||
import net.corda.serialization.internal.amqp.SerializationOutput
|
||||
import net.corda.serialization.internal.amqp.SerializationSchemas
|
||||
import org.apache.qpid.proton.amqp.UnsignedByte
|
||||
import org.apache.qpid.proton.codec.Data
|
||||
import java.lang.reflect.Type
|
||||
import java.util.function.Function
|
||||
|
||||
class SandboxUnsignedByteSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
taskFactory: Function<in Any, out Function<in Any?, out Any?>>
|
||||
) : CustomSerializer.Is<Any>(classLoader.toSandboxAnyClass(UnsignedByte::class.java)) {
|
||||
@Suppress("unchecked_cast")
|
||||
private val transformer: Function<ByteArray, out Any?>
|
||||
= classLoader.createTaskFor(taskFactory, UnsignedByteDeserializer::class.java) as Function<ByteArray, out Any?>
|
||||
|
||||
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,34 @@
|
||||
package net.corda.serialization.djvm.serializers
|
||||
|
||||
import net.corda.core.serialization.SerializationContext
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.serialization.djvm.deserializers.UnsignedIntegerDeserializer
|
||||
import net.corda.serialization.djvm.toSandboxAnyClass
|
||||
import net.corda.serialization.internal.amqp.CustomSerializer
|
||||
import net.corda.serialization.internal.amqp.DeserializationInput
|
||||
import net.corda.serialization.internal.amqp.Schema
|
||||
import net.corda.serialization.internal.amqp.SerializationOutput
|
||||
import net.corda.serialization.internal.amqp.SerializationSchemas
|
||||
import org.apache.qpid.proton.amqp.UnsignedInteger
|
||||
import org.apache.qpid.proton.codec.Data
|
||||
import java.lang.reflect.Type
|
||||
import java.util.function.Function
|
||||
|
||||
class SandboxUnsignedIntegerSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
taskFactory: Function<in Any, out Function<in Any?, out Any?>>
|
||||
) : CustomSerializer.Is<Any>(classLoader.toSandboxAnyClass(UnsignedInteger::class.java)) {
|
||||
@Suppress("unchecked_cast")
|
||||
private val transformer: Function<IntArray, out Any?>
|
||||
= classLoader.createTaskFor(taskFactory, UnsignedIntegerDeserializer::class.java) as Function<IntArray, out Any?>
|
||||
|
||||
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,34 @@
|
||||
package net.corda.serialization.djvm.serializers
|
||||
|
||||
import net.corda.core.serialization.SerializationContext
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.serialization.djvm.deserializers.UnsignedLongDeserializer
|
||||
import net.corda.serialization.djvm.toSandboxAnyClass
|
||||
import net.corda.serialization.internal.amqp.CustomSerializer
|
||||
import net.corda.serialization.internal.amqp.DeserializationInput
|
||||
import net.corda.serialization.internal.amqp.Schema
|
||||
import net.corda.serialization.internal.amqp.SerializationOutput
|
||||
import net.corda.serialization.internal.amqp.SerializationSchemas
|
||||
import org.apache.qpid.proton.amqp.UnsignedLong
|
||||
import org.apache.qpid.proton.codec.Data
|
||||
import java.lang.reflect.Type
|
||||
import java.util.function.Function
|
||||
|
||||
class SandboxUnsignedLongSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
taskFactory: Function<in Any, out Function<in Any?, out Any?>>
|
||||
) : CustomSerializer.Is<Any>(classLoader.toSandboxAnyClass(UnsignedLong::class.java)) {
|
||||
@Suppress("unchecked_cast")
|
||||
private val transformer: Function<LongArray, out Any?>
|
||||
= classLoader.createTaskFor(taskFactory, UnsignedLongDeserializer::class.java) as Function<LongArray, out Any?>
|
||||
|
||||
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,34 @@
|
||||
package net.corda.serialization.djvm.serializers
|
||||
|
||||
import net.corda.core.serialization.SerializationContext
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.serialization.djvm.deserializers.UnsignedShortDeserializer
|
||||
import net.corda.serialization.djvm.toSandboxAnyClass
|
||||
import net.corda.serialization.internal.amqp.CustomSerializer
|
||||
import net.corda.serialization.internal.amqp.DeserializationInput
|
||||
import net.corda.serialization.internal.amqp.Schema
|
||||
import net.corda.serialization.internal.amqp.SerializationOutput
|
||||
import net.corda.serialization.internal.amqp.SerializationSchemas
|
||||
import org.apache.qpid.proton.amqp.UnsignedShort
|
||||
import org.apache.qpid.proton.codec.Data
|
||||
import java.lang.reflect.Type
|
||||
import java.util.function.Function
|
||||
|
||||
class SandboxUnsignedShortSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
taskFactory: Function<in Any, out Function<in Any?, out Any?>>
|
||||
) : CustomSerializer.Is<Any>(classLoader.toSandboxAnyClass(UnsignedShort::class.java)) {
|
||||
@Suppress("unchecked_cast")
|
||||
private val transformer: Function<ShortArray, out Any?>
|
||||
= classLoader.createTaskFor(taskFactory, UnsignedShortDeserializer::class.java) as Function<ShortArray, out Any?>
|
||||
|
||||
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,38 @@
|
||||
package net.corda.serialization.djvm.serializers
|
||||
|
||||
import net.corda.core.serialization.SerializationContext
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.serialization.djvm.deserializers.X509CRLDeserializer
|
||||
import net.corda.serialization.djvm.toSandboxAnyClass
|
||||
import net.corda.serialization.internal.amqp.CustomSerializer
|
||||
import net.corda.serialization.internal.amqp.DeserializationInput
|
||||
import net.corda.serialization.internal.amqp.Schema
|
||||
import net.corda.serialization.internal.amqp.SerializationOutput
|
||||
import net.corda.serialization.internal.amqp.SerializationSchemas
|
||||
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.Function
|
||||
|
||||
class SandboxX509CRLSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
taskFactory: Function<in Any, out Function<in Any?, out Any?>>
|
||||
) : CustomSerializer.Implements<Any>(classLoader.toSandboxAnyClass(X509CRL::class.java)) {
|
||||
@Suppress("unchecked_cast")
|
||||
private val generator: Function<ByteArray, out Any?>
|
||||
= classLoader.createTaskFor(taskFactory, X509CRLDeserializer::class.java) as Function<ByteArray, out Any?>
|
||||
|
||||
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,38 @@
|
||||
package net.corda.serialization.djvm.serializers
|
||||
|
||||
import net.corda.core.serialization.SerializationContext
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.serialization.djvm.deserializers.X509CertificateDeserializer
|
||||
import net.corda.serialization.djvm.toSandboxAnyClass
|
||||
import net.corda.serialization.internal.amqp.CustomSerializer
|
||||
import net.corda.serialization.internal.amqp.DeserializationInput
|
||||
import net.corda.serialization.internal.amqp.Schema
|
||||
import net.corda.serialization.internal.amqp.SerializationOutput
|
||||
import net.corda.serialization.internal.amqp.SerializationSchemas
|
||||
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.Function
|
||||
|
||||
class SandboxX509CertificateSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
taskFactory: Function<in Any, out Function<in Any?, out Any?>>
|
||||
) : CustomSerializer.Implements<Any>(classLoader.toSandboxAnyClass(X509Certificate::class.java)) {
|
||||
@Suppress("unchecked_cast")
|
||||
private val generator: Function<ByteArray, out Any?>
|
||||
= classLoader.createTaskFor(taskFactory, X509CertificateDeserializer::class.java) as Function<ByteArray, out Any?>
|
||||
|
||||
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.serialization.djvm.serializers
|
||||
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.serialization.djvm.deserializers.YearMonthDeserializer
|
||||
import net.corda.serialization.djvm.toSandboxAnyClass
|
||||
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.Function
|
||||
|
||||
class SandboxYearMonthSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
taskFactory: Function<in Any, out Function<in Any?, out Any?>>,
|
||||
factory: SerializerFactory
|
||||
) : CustomSerializer.Proxy<Any, Any>(
|
||||
clazz = classLoader.toSandboxAnyClass(YearMonth::class.java),
|
||||
proxyClass = classLoader.toSandboxAnyClass(YearMonthProxy::class.java),
|
||||
factory = factory
|
||||
) {
|
||||
private val task = classLoader.createTaskFor(taskFactory, YearMonthDeserializer::class.java)
|
||||
|
||||
override val deserializationAliases: Set<Class<*>> = singleton(YearMonth::class.java)
|
||||
|
||||
override fun toProxy(obj: Any): Any = abortReadOnly()
|
||||
|
||||
override fun fromProxy(proxy: Any): Any {
|
||||
return task.apply(proxy)!!
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package net.corda.serialization.djvm.serializers
|
||||
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.serialization.djvm.deserializers.YearDeserializer
|
||||
import net.corda.serialization.djvm.toSandboxAnyClass
|
||||
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.Function
|
||||
|
||||
class SandboxYearSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
taskFactory: Function<in Any, out Function<in Any?, out Any?>>,
|
||||
factory: SerializerFactory
|
||||
) : CustomSerializer.Proxy<Any, Any>(
|
||||
clazz = classLoader.toSandboxAnyClass(Year::class.java),
|
||||
proxyClass = classLoader.toSandboxAnyClass(YearProxy::class.java),
|
||||
factory = factory
|
||||
) {
|
||||
private val task = classLoader.createTaskFor(taskFactory, YearDeserializer::class.java)
|
||||
|
||||
override val deserializationAliases: Set<Class<*>> = singleton(Year::class.java)
|
||||
|
||||
override fun toProxy(obj: Any): Any = abortReadOnly()
|
||||
|
||||
override fun fromProxy(proxy: Any): Any {
|
||||
return task.apply(proxy)!!
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package net.corda.serialization.djvm.serializers
|
||||
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.serialization.djvm.deserializers.ZoneIdDeserializer
|
||||
import net.corda.serialization.djvm.toSandboxAnyClass
|
||||
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.Function
|
||||
|
||||
class SandboxZoneIdSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
taskFactory: Function<in Any, out Function<in Any?, out Any?>>,
|
||||
factory: SerializerFactory
|
||||
) : CustomSerializer.Proxy<Any, Any>(
|
||||
clazz = classLoader.toSandboxAnyClass(ZoneId::class.java),
|
||||
proxyClass = classLoader.toSandboxAnyClass(ZoneIdProxy::class.java),
|
||||
factory = factory
|
||||
) {
|
||||
private val task = classLoader.createTaskFor(taskFactory, ZoneIdDeserializer::class.java)
|
||||
|
||||
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 task.apply(proxy)!!
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package net.corda.serialization.djvm.serializers
|
||||
|
||||
import net.corda.djvm.rewiring.SandboxClassLoader
|
||||
import net.corda.serialization.djvm.deserializers.ZonedDateTimeDeserializer
|
||||
import net.corda.serialization.djvm.toSandboxAnyClass
|
||||
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.Function
|
||||
|
||||
class SandboxZonedDateTimeSerializer(
|
||||
classLoader: SandboxClassLoader,
|
||||
taskFactory: Function<in Any, out Function<in Any?, out Any?>>,
|
||||
factory: SerializerFactory
|
||||
) : CustomSerializer.Proxy<Any, Any>(
|
||||
clazz = classLoader.toSandboxAnyClass(ZonedDateTime::class.java),
|
||||
proxyClass = classLoader.toSandboxAnyClass(ZonedDateTimeProxy::class.java),
|
||||
factory = factory
|
||||
) {
|
||||
private val task = classLoader.createTaskFor(taskFactory, ZonedDateTimeDeserializer::class.java)
|
||||
private val creator: Function<in Any?, out Any?>
|
||||
|
||||
init {
|
||||
val createTask = clazz.getMethod(
|
||||
"createDJVM",
|
||||
classLoader.toSandboxClass(LocalDateTime::class.java),
|
||||
classLoader.toSandboxClass(ZoneOffset::class.java),
|
||||
classLoader.toSandboxClass(ZoneId::class.java)
|
||||
)
|
||||
creator = task.andThen { input ->
|
||||
@Suppress("unchecked_cast", "SpreadOperator")
|
||||
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(proxy)!!
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package greymalkin;
|
||||
|
||||
import net.corda.core.serialization.CordaSerializable;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@CordaSerializable
|
||||
public enum ExternalEnum {
|
||||
DOH,
|
||||
RAY,
|
||||
ME
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package net.corda.serialization.djvm;
|
||||
|
||||
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.serialization.djvm;
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package net.corda.serialization.djvm;
|
||||
|
||||
@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,49 @@
|
||||
package net.corda.serialization.djvm
|
||||
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import net.corda.core.serialization.internal._contextSerializationEnv
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.serialization.djvm.SandboxType.KOTLIN
|
||||
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 taskFactory = classLoader.createRawTaskFactory()
|
||||
val showBigDecimal = classLoader.createTaskFor(taskFactory, ShowBigDecimal::class.java)
|
||||
val result = showBigDecimal.apply(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,49 @@
|
||||
package net.corda.serialization.djvm
|
||||
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import net.corda.core.serialization.internal._contextSerializationEnv
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.serialization.djvm.SandboxType.KOTLIN
|
||||
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 taskFactory = classLoader.createRawTaskFactory()
|
||||
val showBigInteger = classLoader.createTaskFor(taskFactory, ShowBigInteger::class.java)
|
||||
val result = showBigInteger.apply(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,39 @@
|
||||
package net.corda.serialization.djvm
|
||||
|
||||
import net.corda.core.serialization.internal._contextSerializationEnv
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.serialization.djvm.SandboxType.KOTLIN
|
||||
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.BitSet
|
||||
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 taskFactory = classLoader.createRawTaskFactory()
|
||||
val showBitSet = classLoader.createTaskFor(taskFactory, ShowBitSet::class.java)
|
||||
val result = showBitSet.apply(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,129 @@
|
||||
package net.corda.serialization.djvm
|
||||
|
||||
import net.corda.core.serialization.internal._contextSerializationEnv
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.serialization.djvm.SandboxType.KOTLIN
|
||||
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.
|
||||
fun String.toUNIX(): String {
|
||||
return replace(System.lineSeparator(), "\n")
|
||||
}
|
||||
|
||||
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 taskFactory = classLoader.createRawTaskFactory()
|
||||
val showCertPath = classLoader.createTaskFor(taskFactory, ShowCertPath::class.java)
|
||||
val result = showCertPath.apply(sandboxCertPath) ?: fail("Result cannot be null")
|
||||
|
||||
assertEquals(ShowCertPath().apply(certPath).toUNIX(), 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 taskFactory = classLoader.createRawTaskFactory()
|
||||
val showCertificate = classLoader.createTaskFor(taskFactory, ShowCertificate::class.java)
|
||||
val result = showCertificate.apply(sandboxCertificate) ?: fail("Result cannot be null")
|
||||
|
||||
assertEquals(ShowCertificate().apply(certificate).toUNIX(), 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 taskFactory = classLoader.createRawTaskFactory()
|
||||
val showCRL = classLoader.createTaskFor(taskFactory, ShowCRL::class.java)
|
||||
val result = showCRL.apply(sandboxCRL) ?: fail("Result cannot be null")
|
||||
|
||||
assertEquals(ShowCRL().apply(crl).toUNIX(), 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,59 @@
|
||||
package net.corda.serialization.djvm
|
||||
|
||||
import greymalkin.ExternalData
|
||||
import net.corda.core.serialization.internal._contextSerializationEnv
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.djvm.messages.Severity
|
||||
import net.corda.serialization.djvm.SandboxType.KOTLIN
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
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 taskFactory = classLoader.createRawTaskFactory()
|
||||
val showClass = classLoader.createTaskFor(taskFactory, ShowClass::class.java)
|
||||
val result = showClass.apply(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 = Severity::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("Severity was not found by the node,")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ShowClass : Function<Class<*>, String> {
|
||||
override fun apply(type: Class<*>): String {
|
||||
return type.name
|
||||
}
|
||||
}
|
@ -0,0 +1,215 @@
|
||||
package net.corda.serialization.djvm
|
||||
|
||||
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.serialization.djvm.SandboxType.KOTLIN
|
||||
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.EnumSet
|
||||
import java.util.NavigableSet
|
||||
import java.util.SortedSet
|
||||
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 taskFactory = classLoader.createRawTaskFactory()
|
||||
val showStringList = classLoader.createTaskFor(taskFactory, ShowStringList::class.java)
|
||||
val result = showStringList.apply(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 taskFactory = classLoader.createRawTaskFactory()
|
||||
val showIntegerSet = classLoader.createTaskFor(taskFactory, ShowIntegerSet::class.java)
|
||||
val result = showIntegerSet.apply(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 taskFactory = classLoader.createRawTaskFactory()
|
||||
val showIntegerSortedSet = classLoader.createTaskFor(taskFactory, ShowIntegerSortedSet::class.java)
|
||||
val result = showIntegerSortedSet.apply(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 taskFactory = classLoader.createRawTaskFactory()
|
||||
val showLongNavigableSet = classLoader.createTaskFor(taskFactory, ShowLongNavigableSet::class.java)
|
||||
val result = showLongNavigableSet.apply(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 taskFactory = classLoader.createRawTaskFactory()
|
||||
val showShortCollection = classLoader.createTaskFor(taskFactory, ShowShortCollection::class.java)
|
||||
val result = showShortCollection.apply(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 taskFactory = classLoader.createRawTaskFactory()
|
||||
val showNonEmptyStringSet = classLoader.createTaskFor(taskFactory, ShowNonEmptyStringSet::class.java)
|
||||
val result = showNonEmptyStringSet.apply(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 taskFactory = classLoader.createRawTaskFactory()
|
||||
val showHasEnumSet = classLoader.createTaskFor(taskFactory, ShowHasEnumSet::class.java)
|
||||
val result = showHasEnumSet.apply(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,45 @@
|
||||
package net.corda.serialization.djvm
|
||||
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import net.corda.core.serialization.internal._contextSerializationEnv
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.serialization.djvm.SandboxType.KOTLIN
|
||||
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.Currency
|
||||
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 taskFactory = classLoader.createRawTaskFactory()
|
||||
val showCurrency = classLoader.createTaskFor(taskFactory, ShowCurrency::class.java)
|
||||
val result = showCurrency.apply(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,43 @@
|
||||
package net.corda.serialization.djvm
|
||||
|
||||
import greymalkin.ExternalEnum
|
||||
import net.corda.core.serialization.internal._contextSerializationEnv
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.serialization.djvm.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.EnumSet
|
||||
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 taskFactory = classLoader.createRawTaskFactory()
|
||||
val showEnumSet = classLoader.createTaskFor(taskFactory, ShowEnumSet::class.java)
|
||||
val result = showEnumSet.apply(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,55 @@
|
||||
package net.corda.serialization.djvm
|
||||
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import net.corda.core.serialization.internal._contextSerializationEnv
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.serialization.djvm.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 taskFactory = classLoader.createRawTaskFactory()
|
||||
val showExampleData = classLoader.createTaskFor(taskFactory, ShowExampleData::class.java)
|
||||
val result = showExampleData.apply(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,170 @@
|
||||
package net.corda.serialization.djvm
|
||||
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import net.corda.core.serialization.internal._contextSerializationEnv
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.serialization.djvm.SandboxType.KOTLIN
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
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.function.Function
|
||||
|
||||
@ExtendWith(LocalSerialization::class)
|
||||
class DeserializeGenericsTest : TestBase(KOTLIN) {
|
||||
@Test
|
||||
fun `test deserializing generic wrapper with String`() {
|
||||
val wrappedString = GenericWrapper(data = "Hello World!")
|
||||
val data = wrappedString.serialize()
|
||||
|
||||
sandbox {
|
||||
_contextSerializationEnv.set(createSandboxSerializationEnv(classLoader))
|
||||
|
||||
val sandboxWrapper = data.deserializeFor(classLoader)
|
||||
|
||||
val taskFactory = classLoader.createRawTaskFactory()
|
||||
val getGenericData = classLoader.createTaskFor(taskFactory, GetGenericData::class.java)
|
||||
val result = getGenericData.apply(sandboxWrapper) ?: fail("Result cannot be null")
|
||||
|
||||
assertEquals("Hello World!", result.toString())
|
||||
assertEquals(SANDBOX_STRING, result::class.java.name)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test deserializing generic wrapper with Integer`() {
|
||||
val wrappedInteger = GenericWrapper(data = 1000)
|
||||
val data = wrappedInteger.serialize()
|
||||
|
||||
sandbox {
|
||||
_contextSerializationEnv.set(createSandboxSerializationEnv(classLoader))
|
||||
|
||||
val sandboxWrapper = data.deserializeFor(classLoader)
|
||||
|
||||
val taskFactory = classLoader.createRawTaskFactory()
|
||||
val getGenericData = classLoader.createTaskFor(taskFactory, GetGenericData::class.java)
|
||||
val result = getGenericData.apply(sandboxWrapper) ?: fail("Result cannot be null")
|
||||
|
||||
assertEquals("sandbox.java.lang.Integer", result::class.java.name)
|
||||
assertEquals(1000, classLoader.createBasicOutput().apply(result))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test deserializing generic wrapper with array of Integer`() {
|
||||
val wrappedArrayOfInteger = GenericWrapper(arrayOf(1000, 2000, 3000))
|
||||
val data = wrappedArrayOfInteger.serialize()
|
||||
|
||||
sandbox {
|
||||
_contextSerializationEnv.set(createSandboxSerializationEnv(classLoader))
|
||||
|
||||
val sandboxWrapper = data.deserializeFor(classLoader)
|
||||
|
||||
val taskFactory = classLoader.createRawTaskFactory()
|
||||
val getGenericData = classLoader.createTaskFor(taskFactory, GetGenericData::class.java)
|
||||
val result = getGenericData.apply(sandboxWrapper) ?: fail("Result cannot be null")
|
||||
|
||||
assertEquals("[Lsandbox.java.lang.Integer;", result::class.java.name)
|
||||
assertThat(classLoader.createBasicOutput().apply(result))
|
||||
.isEqualTo(arrayOf(1000, 2000, 3000))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test deserializing generic wrapper with primitive int array`() {
|
||||
val wrappedArrayOfInteger = GenericWrapper(intArrayOf(1000, 2000, 3000))
|
||||
val data = wrappedArrayOfInteger.serialize()
|
||||
|
||||
sandbox {
|
||||
_contextSerializationEnv.set(createSandboxSerializationEnv(classLoader))
|
||||
|
||||
val sandboxWrapper = data.deserializeFor(classLoader)
|
||||
|
||||
val taskFactory = classLoader.createRawTaskFactory()
|
||||
val getGenericData = classLoader.createTaskFor(taskFactory, GetGenericData::class.java)
|
||||
val result = getGenericData.apply(sandboxWrapper) ?: fail("Result cannot be null")
|
||||
|
||||
assertEquals("[I", result::class.java.name)
|
||||
assertThat(classLoader.createBasicOutput().apply(result))
|
||||
.isEqualTo(intArrayOf(1000, 2000, 3000))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test deserializing generic list`() {
|
||||
val wrappedList = GenericWrapper(data = listOf("Hello World!"))
|
||||
val data = wrappedList.serialize()
|
||||
|
||||
sandbox {
|
||||
_contextSerializationEnv.set(createSandboxSerializationEnv(classLoader))
|
||||
|
||||
val sandboxWrapper = data.deserializeFor(classLoader)
|
||||
|
||||
val taskFactory = classLoader.createRawTaskFactory()
|
||||
val getGenericData = classLoader.createTaskFor(taskFactory, GetGenericData::class.java)
|
||||
val dataResult = getGenericData.apply(sandboxWrapper) ?: fail("Result cannot be null")
|
||||
|
||||
assertEquals("[Hello World!]", dataResult.toString())
|
||||
assertEquals("sandbox.java.util.Collections\$UnmodifiableRandomAccessList", dataResult::class.java.name)
|
||||
|
||||
val getGenericIterableData = classLoader.createTaskFor(taskFactory, GetGenericIterableData::class.java)
|
||||
val dataItemResult = getGenericIterableData.apply(sandboxWrapper) ?: fail("Result cannot be null")
|
||||
assertEquals(SANDBOX_STRING, dataItemResult::class.java.name)
|
||||
}
|
||||
}
|
||||
|
||||
class GetGenericData : Function<GenericWrapper<out Any>, Any?> {
|
||||
override fun apply(input: GenericWrapper<out Any>): Any? {
|
||||
return input.data
|
||||
}
|
||||
}
|
||||
|
||||
class GetGenericIterableData : Function<GenericWrapper<out Iterable<*>>, Any?> {
|
||||
override fun apply(input: GenericWrapper<out Iterable<*>>): Any? {
|
||||
return input.data.iterator().let {
|
||||
if (it.hasNext()) {
|
||||
it.next()
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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 taskFactory = classLoader.createRawTaskFactory()
|
||||
val showConcreteWrapper = classLoader.createTaskFor(taskFactory, ShowConcreteWrapper::class.java)
|
||||
val result = showConcreteWrapper.apply(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>
|
||||
)
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user