mirror of
https://github.com/corda/corda.git
synced 2025-01-15 17:30:02 +00:00
Merge pull request #2251 from corda/kat/feature/testingDisableEvolver
Disable Evolver / Generics fingerprinting bugfix
This commit is contained in:
commit
d846011cc4
1
.gitignore
vendored
1
.gitignore
vendored
@ -88,6 +88,7 @@ crashlytics-build.properties
|
|||||||
|
|
||||||
# docs related
|
# docs related
|
||||||
docs/virtualenv/
|
docs/virtualenv/
|
||||||
|
virtualenv/
|
||||||
|
|
||||||
# bft-smart
|
# bft-smart
|
||||||
**/config/currentView
|
**/config/currentView
|
||||||
|
@ -54,7 +54,6 @@ class DeserializationInput(internal val serializerFactory: SerializerFactory) {
|
|||||||
inline fun <reified T : Any> deserialize(bytes: SerializedBytes<T>): T =
|
inline fun <reified T : Any> deserialize(bytes: SerializedBytes<T>): T =
|
||||||
deserialize(bytes, T::class.java)
|
deserialize(bytes, T::class.java)
|
||||||
|
|
||||||
|
|
||||||
@Throws(NotSerializableException::class)
|
@Throws(NotSerializableException::class)
|
||||||
inline internal fun <reified T : Any> deserializeAndReturnEnvelope(bytes: SerializedBytes<T>): ObjectAndEnvelope<T> =
|
inline internal fun <reified T : Any> deserializeAndReturnEnvelope(bytes: SerializedBytes<T>): ObjectAndEnvelope<T> =
|
||||||
deserializeAndReturnEnvelope(bytes, T::class.java)
|
deserializeAndReturnEnvelope(bytes, T::class.java)
|
||||||
|
@ -106,7 +106,7 @@ class EnumEvolutionSerializer(
|
|||||||
// to the name as it exists. We want to test any new constants have been added to the end
|
// to the name as it exists. We want to test any new constants have been added to the end
|
||||||
// of the enum class
|
// of the enum class
|
||||||
val serialisedOrds = ((schemas.schema.types.find { it.name == old.name } as RestrictedType).choices
|
val serialisedOrds = ((schemas.schema.types.find { it.name == old.name } as RestrictedType).choices
|
||||||
.associateBy ({ it.value.toInt() }, { conversions[it.name] }))
|
.associateBy({ it.value.toInt() }, { conversions[it.name] }))
|
||||||
|
|
||||||
if (ordinals.filterNot { serialisedOrds[it.value] == it.key }.isNotEmpty()) {
|
if (ordinals.filterNot { serialisedOrds[it.value] == it.key }.isNotEmpty()) {
|
||||||
throw NotSerializableException("Constants have been reordered, additions must be appended to the end")
|
throw NotSerializableException("Constants have been reordered, additions must be appended to the end")
|
||||||
|
@ -130,3 +130,34 @@ class EvolutionSerializer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instances of this type are injected into a [SerializerFactory] at creation time to dictate the
|
||||||
|
* behaviour of evolution within that factory. Under normal circumstances this will simply
|
||||||
|
* be an object that returns an [EvolutionSerializer]. Of course, any implementation that
|
||||||
|
* extends this class can be written to invoke whatever behaviour is desired.
|
||||||
|
*/
|
||||||
|
abstract class EvolutionSerializerGetterBase {
|
||||||
|
abstract fun getEvolutionSerializer(
|
||||||
|
factory: SerializerFactory,
|
||||||
|
typeNotation: TypeNotation,
|
||||||
|
newSerializer: AMQPSerializer<Any>,
|
||||||
|
schemas: SerializationSchemas): AMQPSerializer<Any>
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The normal use case for generating an [EvolutionSerializer]'s based on the differences
|
||||||
|
* between the received schema and the class as it exists now on the class path,
|
||||||
|
*/
|
||||||
|
class EvolutionSerializerGetter : EvolutionSerializerGetterBase() {
|
||||||
|
override fun getEvolutionSerializer(factory: SerializerFactory,
|
||||||
|
typeNotation: TypeNotation,
|
||||||
|
newSerializer: AMQPSerializer<Any>,
|
||||||
|
schemas: SerializationSchemas): AMQPSerializer<Any> =
|
||||||
|
factory.getSerializersByDescriptor().computeIfAbsent(typeNotation.descriptor.name!!) {
|
||||||
|
when (typeNotation) {
|
||||||
|
is CompositeType -> EvolutionSerializer.make(typeNotation, newSerializer as ObjectSerializer, factory)
|
||||||
|
is RestrictedType -> EnumEvolutionSerializer.make(typeNotation, newSerializer, factory, schemas)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -346,19 +346,54 @@ private fun Hasher.fingerprintWithCustomSerializerOrElse(factory: SerializerFact
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method concatentates various elements of the types recursively as unencoded strings into the hasher, effectively
|
// This method concatenates various elements of the types recursively as unencoded strings into the hasher, effectively
|
||||||
// creating a unique string for a type which we then hash in the calling function above.
|
// creating a unique string for a type which we then hash in the calling function above.
|
||||||
private fun fingerprintForType(type: Type, contextType: Type?, alreadySeen: MutableSet<Type>, hasher: Hasher, factory: SerializerFactory): Hasher {
|
private fun fingerprintForType(type: Type, contextType: Type?, alreadySeen: MutableSet<Type>,
|
||||||
return if (type in alreadySeen) {
|
hasher: Hasher, factory: SerializerFactory, offset: Int = 4): Hasher {
|
||||||
|
|
||||||
|
// We don't include Example<?> and Example<T> where type is ? or T in this otherwise we
|
||||||
|
// generate different fingerprints for class Outer<T>(val a: Inner<T>) when serialising
|
||||||
|
// and deserializing (assuming deserialization is occurring in a factory that didn't
|
||||||
|
// serialise the object in the first place (and thus the cache lookup fails). This is also
|
||||||
|
// true of Any, where we need Example<A, B> and Example<?, ?> to have the same fingerprint
|
||||||
|
return if (type in alreadySeen && (type !is SerializerFactory.AnyType) && (type !is TypeVariable<*>)) {
|
||||||
hasher.putUnencodedChars(ALREADY_SEEN_HASH)
|
hasher.putUnencodedChars(ALREADY_SEEN_HASH)
|
||||||
} else {
|
} else {
|
||||||
alreadySeen += type
|
alreadySeen += type
|
||||||
try {
|
try {
|
||||||
when (type) {
|
when (type) {
|
||||||
is SerializerFactory.AnyType -> hasher.putUnencodedChars(ANY_TYPE_HASH)
|
is ParameterizedType -> {
|
||||||
|
// Hash the rawType + params
|
||||||
|
val clazz = type.rawType as Class<*>
|
||||||
|
|
||||||
|
val startingHash = if (isCollectionOrMap(clazz)) {
|
||||||
|
hasher.putUnencodedChars(clazz.name)
|
||||||
|
} else {
|
||||||
|
hasher.fingerprintWithCustomSerializerOrElse(factory, clazz, type) {
|
||||||
|
fingerprintForObject(type, type, alreadySeen, hasher, factory, offset+4)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ... and concatenate the type data for each parameter type.
|
||||||
|
type.actualTypeArguments.fold(startingHash) { orig, paramType ->
|
||||||
|
fingerprintForType(paramType, type, alreadySeen, orig, factory, offset+4)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Treat generic types as "any type" to prevent fingerprint mismatch. This case we fall into when
|
||||||
|
// looking at A and B from Example<A, B> (remember we call this function recursively). When
|
||||||
|
// serialising a concrete example of the type we have A and B which are TypeVariables<*>'s but
|
||||||
|
// when deserializing we only have the wildcard placeholder ?, or AnyType
|
||||||
|
//
|
||||||
|
// Note, TypeVariable<*> used to be encoded as TYPE_VARIABLE_HASH but that again produces a
|
||||||
|
// differing fingerprint on serialisation and deserialization
|
||||||
|
is SerializerFactory.AnyType,
|
||||||
|
is TypeVariable<*> -> {
|
||||||
|
hasher.putUnencodedChars("?").putUnencodedChars(ANY_TYPE_HASH)
|
||||||
|
}
|
||||||
is Class<*> -> {
|
is Class<*> -> {
|
||||||
if (type.isArray) {
|
if (type.isArray) {
|
||||||
fingerprintForType(type.componentType, contextType, alreadySeen, hasher, factory).putUnencodedChars(ARRAY_HASH)
|
fingerprintForType(type.componentType, contextType, alreadySeen, hasher, factory, offset+4)
|
||||||
|
.putUnencodedChars(ARRAY_HASH)
|
||||||
} else if (SerializerFactory.isPrimitive(type)) {
|
} else if (SerializerFactory.isPrimitive(type)) {
|
||||||
hasher.putUnencodedChars(type.name)
|
hasher.putUnencodedChars(type.name)
|
||||||
} else if (isCollectionOrMap(type)) {
|
} else if (isCollectionOrMap(type)) {
|
||||||
@ -377,32 +412,18 @@ private fun fingerprintForType(type: Type, contextType: Type?, alreadySeen: Muta
|
|||||||
// to the CorDapp but maybe reference to the JAR in the short term.
|
// to the CorDapp but maybe reference to the JAR in the short term.
|
||||||
hasher.putUnencodedChars(type.name)
|
hasher.putUnencodedChars(type.name)
|
||||||
} else {
|
} else {
|
||||||
fingerprintForObject(type, type, alreadySeen, hasher, factory)
|
fingerprintForObject(type, type, alreadySeen, hasher, factory, offset+4)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is ParameterizedType -> {
|
|
||||||
// Hash the rawType + params
|
|
||||||
val clazz = type.rawType as Class<*>
|
|
||||||
val startingHash = if (isCollectionOrMap(clazz)) {
|
|
||||||
hasher.putUnencodedChars(clazz.name)
|
|
||||||
} else {
|
|
||||||
hasher.fingerprintWithCustomSerializerOrElse(factory, clazz, type) {
|
|
||||||
fingerprintForObject(type, type, alreadySeen, hasher, factory)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// ... and concatentate the type data for each parameter type.
|
|
||||||
type.actualTypeArguments.fold(startingHash) { orig, paramType ->
|
|
||||||
fingerprintForType(paramType, type, alreadySeen, orig, factory)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Hash the element type + some array hash
|
// Hash the element type + some array hash
|
||||||
is GenericArrayType -> fingerprintForType(type.genericComponentType, contextType, alreadySeen,
|
is GenericArrayType -> fingerprintForType(type.genericComponentType, contextType, alreadySeen,
|
||||||
hasher, factory).putUnencodedChars(ARRAY_HASH)
|
hasher, factory, offset+4).putUnencodedChars(ARRAY_HASH)
|
||||||
// TODO: include bounds
|
// TODO: include bounds
|
||||||
is TypeVariable<*> -> hasher.putUnencodedChars(type.name).putUnencodedChars(TYPE_VARIABLE_HASH)
|
is WildcardType -> {
|
||||||
is WildcardType -> hasher.putUnencodedChars(type.typeName).putUnencodedChars(WILDCARD_TYPE_HASH)
|
hasher.putUnencodedChars(type.typeName).putUnencodedChars(WILDCARD_TYPE_HASH)
|
||||||
|
}
|
||||||
else -> throw NotSerializableException("Don't know how to hash")
|
else -> throw NotSerializableException("Don't know how to hash")
|
||||||
}
|
}
|
||||||
} catch (e: NotSerializableException) {
|
} catch (e: NotSerializableException) {
|
||||||
@ -416,15 +437,21 @@ private fun fingerprintForType(type: Type, contextType: Type?, alreadySeen: Muta
|
|||||||
private fun isCollectionOrMap(type: Class<*>) = (Collection::class.java.isAssignableFrom(type) || Map::class.java.isAssignableFrom(type)) &&
|
private fun isCollectionOrMap(type: Class<*>) = (Collection::class.java.isAssignableFrom(type) || Map::class.java.isAssignableFrom(type)) &&
|
||||||
!EnumSet::class.java.isAssignableFrom(type)
|
!EnumSet::class.java.isAssignableFrom(type)
|
||||||
|
|
||||||
private fun fingerprintForObject(type: Type, contextType: Type?, alreadySeen: MutableSet<Type>, hasher: Hasher, factory: SerializerFactory): Hasher {
|
private fun fingerprintForObject(
|
||||||
|
type: Type,
|
||||||
|
contextType: Type?,
|
||||||
|
alreadySeen: MutableSet<Type>,
|
||||||
|
hasher: Hasher,
|
||||||
|
factory: SerializerFactory,
|
||||||
|
offset: Int = 0): Hasher {
|
||||||
// Hash the class + properties + interfaces
|
// Hash the class + properties + interfaces
|
||||||
val name = type.asClass()?.name ?: throw NotSerializableException("Expected only Class or ParameterizedType but found $type")
|
val name = type.asClass()?.name ?: throw NotSerializableException("Expected only Class or ParameterizedType but found $type")
|
||||||
propertiesForSerialization(constructorForDeserialization(type), contextType ?: type, factory).getters
|
propertiesForSerialization(constructorForDeserialization(type), contextType ?: type, factory).getters
|
||||||
.fold(hasher.putUnencodedChars(name)) { orig, prop ->
|
.fold(hasher.putUnencodedChars(name)) { orig, prop ->
|
||||||
fingerprintForType(prop.resolvedType, type, alreadySeen, orig, factory)
|
fingerprintForType(prop.resolvedType, type, alreadySeen, orig, factory, offset+4)
|
||||||
.putUnencodedChars(prop.name)
|
.putUnencodedChars(prop.name)
|
||||||
.putUnencodedChars(if (prop.mandatory) NOT_NULLABLE_HASH else NULLABLE_HASH)
|
.putUnencodedChars(if (prop.mandatory) NOT_NULLABLE_HASH else NULLABLE_HASH)
|
||||||
}
|
}
|
||||||
interfacesForSerialization(type, factory).map { fingerprintForType(it, type, alreadySeen, hasher, factory) }
|
interfacesForSerialization(type, factory).map { fingerprintForType(it, type, alreadySeen, hasher, factory, offset+4) }
|
||||||
return hasher
|
return hasher
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,10 @@ data class FactorySchemaAndDescriptor(val schemas: SerializationSchemas, val typ
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Factory of serializers designed to be shared across threads and invocations.
|
* Factory of serializers designed to be shared across threads and invocations.
|
||||||
|
*
|
||||||
|
* @property evolutionSerializerGetter controls how evolution serializers are generated by the factory. The normal
|
||||||
|
* use case is an [EvolutionSerializer] type is returned. However, in some scenarios, primarily testing, this
|
||||||
|
* can be altered to fit the requirements of the test.
|
||||||
*/
|
*/
|
||||||
// TODO: support for intern-ing of deserialized objects for some core types (e.g. PublicKey) for memory efficiency
|
// TODO: support for intern-ing of deserialized objects for some core types (e.g. PublicKey) for memory efficiency
|
||||||
// TODO: maybe support for caching of serialized form of some core types for performance
|
// TODO: maybe support for caching of serialized form of some core types for performance
|
||||||
@ -33,28 +37,27 @@ data class FactorySchemaAndDescriptor(val schemas: SerializationSchemas, val typ
|
|||||||
// TODO: need to rethink matching of constructor to properties in relation to implementing interfaces and needing those properties etc.
|
// TODO: need to rethink matching of constructor to properties in relation to implementing interfaces and needing those properties etc.
|
||||||
// TODO: need to support super classes as well as interfaces with our current code base... what's involved? If we continue to ban, what is the impact?
|
// TODO: need to support super classes as well as interfaces with our current code base... what's involved? If we continue to ban, what is the impact?
|
||||||
@ThreadSafe
|
@ThreadSafe
|
||||||
open class SerializerFactory(val whitelist: ClassWhitelist, cl: ClassLoader) {
|
open class SerializerFactory(
|
||||||
|
val whitelist: ClassWhitelist,
|
||||||
|
cl: ClassLoader,
|
||||||
|
private val evolutionSerializerGetter: EvolutionSerializerGetterBase = EvolutionSerializerGetter()) {
|
||||||
private val serializersByType = ConcurrentHashMap<Type, AMQPSerializer<Any>>()
|
private val serializersByType = ConcurrentHashMap<Type, AMQPSerializer<Any>>()
|
||||||
private val serializersByDescriptor = ConcurrentHashMap<Any, AMQPSerializer<Any>>()
|
private val serializersByDescriptor = ConcurrentHashMap<Any, AMQPSerializer<Any>>()
|
||||||
private val customSerializers = CopyOnWriteArrayList<SerializerFor>()
|
private val customSerializers = CopyOnWriteArrayList<SerializerFor>()
|
||||||
val transformsCache = ConcurrentHashMap<String, EnumMap<TransformTypes, MutableList<Transform>>>()
|
private val transformsCache = ConcurrentHashMap<String, EnumMap<TransformTypes, MutableList<Transform>>>()
|
||||||
|
|
||||||
open val classCarpenter = ClassCarpenter(cl, whitelist)
|
open val classCarpenter = ClassCarpenter(cl, whitelist)
|
||||||
|
|
||||||
val classloader: ClassLoader
|
val classloader: ClassLoader
|
||||||
get() = classCarpenter.classloader
|
get() = classCarpenter.classloader
|
||||||
|
|
||||||
private fun getEvolutionSerializer(
|
private fun getEvolutionSerializer(typeNotation: TypeNotation, newSerializer: AMQPSerializer<Any>,
|
||||||
typeNotation: TypeNotation,
|
schemas: SerializationSchemas)
|
||||||
newSerializer: AMQPSerializer<Any>,
|
= evolutionSerializerGetter.getEvolutionSerializer(this, typeNotation, newSerializer, schemas)
|
||||||
schemas: SerializationSchemas): AMQPSerializer<Any> {
|
|
||||||
return serializersByDescriptor.computeIfAbsent(typeNotation.descriptor.name!!) {
|
fun getSerializersByDescriptor() = serializersByDescriptor
|
||||||
when (typeNotation) {
|
|
||||||
is CompositeType -> EvolutionSerializer.make(typeNotation, newSerializer as ObjectSerializer, this)
|
fun getTransformsCache() = transformsCache
|
||||||
is RestrictedType -> EnumEvolutionSerializer.make(typeNotation, newSerializer, this, schemas)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Look up, and manufacture if necessary, a serializer for the given type.
|
* Look up, and manufacture if necessary, a serializer for the given type.
|
||||||
@ -93,7 +96,9 @@ open class SerializerFactory(val whitelist: ClassWhitelist, cl: ClassLoader) {
|
|||||||
whitelist.requireWhitelisted(actualType)
|
whitelist.requireWhitelisted(actualType)
|
||||||
EnumSerializer(actualType, actualClass ?: declaredClass, this)
|
EnumSerializer(actualType, actualClass ?: declaredClass, this)
|
||||||
}
|
}
|
||||||
else -> makeClassSerializer(actualClass ?: declaredClass, actualType, declaredType)
|
else -> {
|
||||||
|
makeClassSerializer(actualClass ?: declaredClass, actualType, declaredType)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
serializersByDescriptor.putIfAbsent(serializer.typeDescriptor, serializer)
|
serializersByDescriptor.putIfAbsent(serializer.typeDescriptor, serializer)
|
||||||
@ -102,12 +107,12 @@ open class SerializerFactory(val whitelist: ClassWhitelist, cl: ClassLoader) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Try and infer concrete types for any generics type variables for the actual class encountered, based on the declared
|
* Try and infer concrete types for any generics type variables for the actual class encountered,
|
||||||
* type.
|
* based on the declared type.
|
||||||
*/
|
*/
|
||||||
// TODO: test GenericArrayType
|
// TODO: test GenericArrayType
|
||||||
private fun inferTypeVariables(actualClass: Class<*>?, declaredClass: Class<*>, declaredType: Type): Type? =
|
private fun inferTypeVariables(actualClass: Class<*>?, declaredClass: Class<*>,
|
||||||
when (declaredType) {
|
declaredType: Type) : Type? = when (declaredType) {
|
||||||
is ParameterizedType -> inferTypeVariables(actualClass, declaredClass, declaredType)
|
is ParameterizedType -> inferTypeVariables(actualClass, declaredClass, declaredType)
|
||||||
// Nothing to infer, otherwise we'd have ParameterizedType
|
// Nothing to infer, otherwise we'd have ParameterizedType
|
||||||
is Class<*> -> actualClass
|
is Class<*> -> actualClass
|
||||||
@ -214,9 +219,9 @@ open class SerializerFactory(val whitelist: ClassWhitelist, cl: ClassLoader) {
|
|||||||
try {
|
try {
|
||||||
val serialiser = processSchemaEntry(typeNotation)
|
val serialiser = processSchemaEntry(typeNotation)
|
||||||
|
|
||||||
// if we just successfully built a serialiser for the type but the type fingerprint
|
// if we just successfully built a serializer for the type but the type fingerprint
|
||||||
// doesn't match that of the serialised object then we are dealing with different
|
// doesn't match that of the serialised object then we are dealing with different
|
||||||
// instance of the class, as such we need to build an EvolutionSerialiser
|
// instance of the class, as such we need to build an EvolutionSerializer
|
||||||
if (serialiser.typeDescriptor != typeNotation.descriptor.name) {
|
if (serialiser.typeDescriptor != typeNotation.descriptor.name) {
|
||||||
getEvolutionSerializer(typeNotation, serialiser, schemaAndDescriptor.schemas)
|
getEvolutionSerializer(typeNotation, serialiser, schemaAndDescriptor.schemas)
|
||||||
}
|
}
|
||||||
@ -337,7 +342,9 @@ open class SerializerFactory(val whitelist: ClassWhitelist, cl: ClassLoader) {
|
|||||||
"${nameForType(type.componentType)}${if (type.componentType.isPrimitive) "[p]" else "[]"}"
|
"${nameForType(type.componentType)}${if (type.componentType.isPrimitive) "[p]" else "[]"}"
|
||||||
} else type.name
|
} else type.name
|
||||||
}
|
}
|
||||||
is ParameterizedType -> "${nameForType(type.rawType)}<${type.actualTypeArguments.joinToString { nameForType(it) }}>"
|
is ParameterizedType -> {
|
||||||
|
"${nameForType(type.rawType)}<${type.actualTypeArguments.joinToString { nameForType(it) }}>"
|
||||||
|
}
|
||||||
is GenericArrayType -> "${nameForType(type.genericComponentType)}[]"
|
is GenericArrayType -> "${nameForType(type.genericComponentType)}[]"
|
||||||
is WildcardType -> "?"
|
is WildcardType -> "?"
|
||||||
is TypeVariable<*> -> "?"
|
is TypeVariable<*> -> "?"
|
||||||
|
@ -200,7 +200,7 @@ data class TransformsSchema(val types: Map<String, EnumMap<TransformTypes, Mutab
|
|||||||
* @param sf the [SerializerFactory] building this transform set. Needed as each can define it's own
|
* @param sf the [SerializerFactory] building this transform set. Needed as each can define it's own
|
||||||
* class loader and this dictates which classes we can and cannot see
|
* class loader and this dictates which classes we can and cannot see
|
||||||
*/
|
*/
|
||||||
fun get(name: String, sf: SerializerFactory) = sf.transformsCache.computeIfAbsent(name) {
|
fun get(name: String, sf: SerializerFactory) = sf.getTransformsCache().computeIfAbsent(name) {
|
||||||
val transforms = EnumMap<TransformTypes, MutableList<Transform>>(TransformTypes::class.java)
|
val transforms = EnumMap<TransformTypes, MutableList<Transform>>(TransformTypes::class.java)
|
||||||
try {
|
try {
|
||||||
val clazz = sf.classloader.loadClass(name)
|
val clazz = sf.classloader.loadClass(name)
|
||||||
|
@ -31,7 +31,12 @@ public class ErrorMessageTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testJavaConstructorAnnotations() {
|
public void testJavaConstructorAnnotations() {
|
||||||
SerializerFactory factory1 = new SerializerFactory(AllWhitelist.INSTANCE, ClassLoader.getSystemClassLoader());
|
EvolutionSerializerGetterBase evolutionSerialiserGetter = new EvolutionSerializerGetter();
|
||||||
|
SerializerFactory factory1 = new SerializerFactory(
|
||||||
|
AllWhitelist.INSTANCE,
|
||||||
|
ClassLoader.getSystemClassLoader(),
|
||||||
|
evolutionSerialiserGetter);
|
||||||
|
|
||||||
SerializationOutput ser = new SerializationOutput(factory1);
|
SerializationOutput ser = new SerializationOutput(factory1);
|
||||||
|
|
||||||
Assertions.assertThatThrownBy(() -> ser.serialize(new C(1)))
|
Assertions.assertThatThrownBy(() -> ser.serialize(new C(1)))
|
||||||
|
@ -0,0 +1,93 @@
|
|||||||
|
package net.corda.nodeapi.internal.serialization.amqp;
|
||||||
|
|
||||||
|
import net.corda.core.serialization.SerializedBytes;
|
||||||
|
import net.corda.nodeapi.internal.serialization.AllWhitelist;
|
||||||
|
import org.junit.Test;
|
||||||
|
import java.io.NotSerializableException;
|
||||||
|
|
||||||
|
import static org.jgroups.util.Util.assertEquals;
|
||||||
|
|
||||||
|
public class JavaGenericsTest {
|
||||||
|
private static class Inner {
|
||||||
|
private final Integer v;
|
||||||
|
|
||||||
|
private Inner(Integer v) { this.v = v; }
|
||||||
|
public Integer getV() { return v; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class A<T> {
|
||||||
|
private final T t;
|
||||||
|
|
||||||
|
private A(T t) { this.t = t; }
|
||||||
|
public T getT() { return t; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void basicGeneric() throws NotSerializableException {
|
||||||
|
A a1 = new A(1);
|
||||||
|
|
||||||
|
SerializerFactory factory = new SerializerFactory(
|
||||||
|
AllWhitelist.INSTANCE,
|
||||||
|
ClassLoader.getSystemClassLoader(),
|
||||||
|
new EvolutionSerializerGetter());
|
||||||
|
|
||||||
|
SerializationOutput ser = new SerializationOutput(factory);
|
||||||
|
SerializedBytes<?> bytes = ser.serialize(a1);
|
||||||
|
|
||||||
|
DeserializationInput des = new DeserializationInput(factory);
|
||||||
|
A a2 = des.deserialize(bytes, A.class);
|
||||||
|
|
||||||
|
assertEquals(1, a2.getT());
|
||||||
|
}
|
||||||
|
|
||||||
|
private SerializedBytes<?> forceWildcardSerialize(A<?> a) throws NotSerializableException {
|
||||||
|
SerializerFactory factory = new SerializerFactory(
|
||||||
|
AllWhitelist.INSTANCE,
|
||||||
|
ClassLoader.getSystemClassLoader(),
|
||||||
|
new EvolutionSerializerGetter());
|
||||||
|
|
||||||
|
return (new SerializationOutput(factory)).serialize(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
private SerializedBytes<?> forceWildcardSerializeFactory(
|
||||||
|
A<?> a,
|
||||||
|
SerializerFactory factory) throws NotSerializableException {
|
||||||
|
return (new SerializationOutput(factory)).serialize(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
private A<?> forceWildcardDeserialize(SerializedBytes<?> bytes) throws NotSerializableException {
|
||||||
|
SerializerFactory factory = new SerializerFactory(
|
||||||
|
AllWhitelist.INSTANCE,
|
||||||
|
ClassLoader.getSystemClassLoader(),
|
||||||
|
new EvolutionSerializerGetter());
|
||||||
|
|
||||||
|
DeserializationInput des = new DeserializationInput(factory);
|
||||||
|
return des.deserialize(bytes, A.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
private A<?> forceWildcardDeserializeFactory(
|
||||||
|
SerializedBytes<?> bytes,
|
||||||
|
SerializerFactory factory) throws NotSerializableException {
|
||||||
|
return (new DeserializationInput(factory)).deserialize(bytes, A.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void forceWildcard() throws NotSerializableException {
|
||||||
|
SerializedBytes<?> bytes = forceWildcardSerialize(new A(new Inner(29)));
|
||||||
|
Inner i = (Inner)forceWildcardDeserialize(bytes).getT();
|
||||||
|
assertEquals(29, i.getV());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void forceWildcardSharedFactory() throws NotSerializableException {
|
||||||
|
SerializerFactory factory = new SerializerFactory(
|
||||||
|
AllWhitelist.INSTANCE,
|
||||||
|
ClassLoader.getSystemClassLoader(),
|
||||||
|
new EvolutionSerializerGetter());
|
||||||
|
|
||||||
|
SerializedBytes<?> bytes = forceWildcardSerializeFactory(new A(new Inner(29)), factory);
|
||||||
|
Inner i = (Inner)forceWildcardDeserializeFactory(bytes, factory).getT();
|
||||||
|
|
||||||
|
assertEquals(29, i.getV());
|
||||||
|
}
|
||||||
|
}
|
@ -25,7 +25,9 @@ public class JavaPrivatePropertyTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void singlePrivateWithConstructor() throws NotSerializableException, NoSuchFieldException, IllegalAccessException {
|
public void singlePrivateWithConstructor() throws NotSerializableException, NoSuchFieldException, IllegalAccessException {
|
||||||
SerializerFactory factory = new SerializerFactory(AllWhitelist.INSTANCE, ClassLoader.getSystemClassLoader());
|
EvolutionSerializerGetterBase evolutionSerializerGetter = new EvolutionSerializerGetter();
|
||||||
|
SerializerFactory factory = new SerializerFactory(AllWhitelist.INSTANCE, ClassLoader.getSystemClassLoader(),
|
||||||
|
evolutionSerializerGetter);
|
||||||
SerializationOutput ser = new SerializationOutput(factory);
|
SerializationOutput ser = new SerializationOutput(factory);
|
||||||
DeserializationInput des = new DeserializationInput(factory);
|
DeserializationInput des = new DeserializationInput(factory);
|
||||||
|
|
||||||
@ -53,7 +55,9 @@ public class JavaPrivatePropertyTests {
|
|||||||
@Test
|
@Test
|
||||||
public void singlePrivateWithConstructorAndGetter()
|
public void singlePrivateWithConstructorAndGetter()
|
||||||
throws NotSerializableException, NoSuchFieldException, IllegalAccessException {
|
throws NotSerializableException, NoSuchFieldException, IllegalAccessException {
|
||||||
SerializerFactory factory = new SerializerFactory(AllWhitelist.INSTANCE, ClassLoader.getSystemClassLoader());
|
EvolutionSerializerGetterBase evolutionSerializerGetter = new EvolutionSerializerGetter();
|
||||||
|
SerializerFactory factory = new SerializerFactory(AllWhitelist.INSTANCE,
|
||||||
|
ClassLoader.getSystemClassLoader(), evolutionSerializerGetter);
|
||||||
SerializationOutput ser = new SerializationOutput(factory);
|
SerializationOutput ser = new SerializationOutput(factory);
|
||||||
DeserializationInput des = new DeserializationInput(factory);
|
DeserializationInput des = new DeserializationInput(factory);
|
||||||
|
|
||||||
|
@ -29,7 +29,9 @@ public class JavaSerialiseEnumTests {
|
|||||||
public void testJavaConstructorAnnotations() throws NotSerializableException {
|
public void testJavaConstructorAnnotations() throws NotSerializableException {
|
||||||
Bra bra = new Bra(Bras.UNDERWIRE);
|
Bra bra = new Bra(Bras.UNDERWIRE);
|
||||||
|
|
||||||
SerializerFactory factory1 = new SerializerFactory(AllWhitelist.INSTANCE, ClassLoader.getSystemClassLoader());
|
EvolutionSerializerGetterBase evolutionSerialiserGetter = new EvolutionSerializerGetter();
|
||||||
|
SerializerFactory factory1 = new SerializerFactory(AllWhitelist.INSTANCE, ClassLoader.getSystemClassLoader(),
|
||||||
|
evolutionSerialiserGetter);
|
||||||
SerializationOutput ser = new SerializationOutput(factory1);
|
SerializationOutput ser = new SerializationOutput(factory1);
|
||||||
SerializedBytes<Object> bytes = ser.serialize(bra);
|
SerializedBytes<Object> bytes = ser.serialize(bra);
|
||||||
}
|
}
|
||||||
|
@ -172,8 +172,11 @@ public class JavaSerializationOutputTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Object serdes(Object obj) throws NotSerializableException {
|
private Object serdes(Object obj) throws NotSerializableException {
|
||||||
SerializerFactory factory1 = new SerializerFactory(AllWhitelist.INSTANCE, ClassLoader.getSystemClassLoader());
|
EvolutionSerializerGetterBase evolutionSerialiserGetter = new EvolutionSerializerGetter();
|
||||||
SerializerFactory factory2 = new SerializerFactory(AllWhitelist.INSTANCE, ClassLoader.getSystemClassLoader());
|
SerializerFactory factory1 = new SerializerFactory(AllWhitelist.INSTANCE, ClassLoader.getSystemClassLoader(),
|
||||||
|
evolutionSerialiserGetter);
|
||||||
|
SerializerFactory factory2 = new SerializerFactory(AllWhitelist.INSTANCE, ClassLoader.getSystemClassLoader(),
|
||||||
|
evolutionSerialiserGetter);
|
||||||
SerializationOutput ser = new SerializationOutput(factory1);
|
SerializationOutput ser = new SerializationOutput(factory1);
|
||||||
SerializedBytes<Object> bytes = ser.serialize(obj);
|
SerializedBytes<Object> bytes = ser.serialize(obj);
|
||||||
|
|
||||||
|
@ -125,7 +125,9 @@ public class ListsSerializationJavaTest {
|
|||||||
|
|
||||||
// Have to have own version as Kotlin inline functions cannot be easily called from Java
|
// Have to have own version as Kotlin inline functions cannot be easily called from Java
|
||||||
private static <T> void assertEqualAfterRoundTripSerialization(T container, Class<T> clazz) throws Exception {
|
private static <T> void assertEqualAfterRoundTripSerialization(T container, Class<T> clazz) throws Exception {
|
||||||
SerializerFactory factory1 = new SerializerFactory(AllWhitelist.INSTANCE, ClassLoader.getSystemClassLoader());
|
EvolutionSerializerGetterBase evolutionSerialiserGetter = new EvolutionSerializerGetter();
|
||||||
|
SerializerFactory factory1 = new SerializerFactory(AllWhitelist.INSTANCE, ClassLoader.getSystemClassLoader(),
|
||||||
|
evolutionSerialiserGetter);
|
||||||
SerializationOutput ser = new SerializationOutput(factory1);
|
SerializationOutput ser = new SerializationOutput(factory1);
|
||||||
SerializedBytes<Object> bytes = ser.serialize(container);
|
SerializedBytes<Object> bytes = ser.serialize(container);
|
||||||
DeserializationInput des = new DeserializationInput(factory1);
|
DeserializationInput des = new DeserializationInput(factory1);
|
||||||
|
@ -109,7 +109,12 @@ public class SetterConstructorTests {
|
|||||||
// despite having no constructor we should still be able to serialise an instance of C
|
// despite having no constructor we should still be able to serialise an instance of C
|
||||||
@Test
|
@Test
|
||||||
public void serialiseC() throws NotSerializableException {
|
public void serialiseC() throws NotSerializableException {
|
||||||
SerializerFactory factory1 = new SerializerFactory(AllWhitelist.INSTANCE, ClassLoader.getSystemClassLoader());
|
EvolutionSerializerGetterBase evolutionSerialiserGetter = new EvolutionSerializerGetter();
|
||||||
|
SerializerFactory factory1 = new SerializerFactory(
|
||||||
|
AllWhitelist.INSTANCE,
|
||||||
|
ClassLoader.getSystemClassLoader(),
|
||||||
|
evolutionSerialiserGetter);
|
||||||
|
|
||||||
SerializationOutput ser = new SerializationOutput(factory1);
|
SerializationOutput ser = new SerializationOutput(factory1);
|
||||||
|
|
||||||
C c1 = new C();
|
C c1 = new C();
|
||||||
@ -178,7 +183,11 @@ public class SetterConstructorTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void deserialiseC() throws NotSerializableException {
|
public void deserialiseC() throws NotSerializableException {
|
||||||
SerializerFactory factory1 = new SerializerFactory(AllWhitelist.INSTANCE, ClassLoader.getSystemClassLoader());
|
EvolutionSerializerGetterBase evolutionSerialiserGetter = new EvolutionSerializerGetter();
|
||||||
|
SerializerFactory factory1 = new SerializerFactory(
|
||||||
|
AllWhitelist.INSTANCE,
|
||||||
|
ClassLoader.getSystemClassLoader(),
|
||||||
|
evolutionSerialiserGetter);
|
||||||
|
|
||||||
C cPre1 = new C();
|
C cPre1 = new C();
|
||||||
|
|
||||||
@ -241,7 +250,11 @@ public class SetterConstructorTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void serialiseOuterAndInner() throws NotSerializableException {
|
public void serialiseOuterAndInner() throws NotSerializableException {
|
||||||
SerializerFactory factory1 = new SerializerFactory(AllWhitelist.INSTANCE, ClassLoader.getSystemClassLoader());
|
EvolutionSerializerGetterBase evolutionSerialiserGetter = new EvolutionSerializerGetter();
|
||||||
|
SerializerFactory factory1 = new SerializerFactory(
|
||||||
|
AllWhitelist.INSTANCE,
|
||||||
|
ClassLoader.getSystemClassLoader(),
|
||||||
|
evolutionSerialiserGetter);
|
||||||
|
|
||||||
Inner1 i1 = new Inner1("Hello");
|
Inner1 i1 = new Inner1("Hello");
|
||||||
Inner2 i2 = new Inner2();
|
Inner2 i2 = new Inner2();
|
||||||
@ -263,7 +276,11 @@ public class SetterConstructorTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void typeMistmatch() throws NotSerializableException {
|
public void typeMistmatch() throws NotSerializableException {
|
||||||
SerializerFactory factory1 = new SerializerFactory(AllWhitelist.INSTANCE, ClassLoader.getSystemClassLoader());
|
EvolutionSerializerGetterBase evolutionSerialiserGetter = new EvolutionSerializerGetter();
|
||||||
|
SerializerFactory factory1 = new SerializerFactory(
|
||||||
|
AllWhitelist.INSTANCE,
|
||||||
|
ClassLoader.getSystemClassLoader(),
|
||||||
|
evolutionSerialiserGetter);
|
||||||
|
|
||||||
TypeMismatch tm = new TypeMismatch();
|
TypeMismatch tm = new TypeMismatch();
|
||||||
tm.setA(10);
|
tm.setA(10);
|
||||||
@ -279,7 +296,11 @@ public class SetterConstructorTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void typeMistmatch2() throws NotSerializableException {
|
public void typeMistmatch2() throws NotSerializableException {
|
||||||
SerializerFactory factory1 = new SerializerFactory(AllWhitelist.INSTANCE, ClassLoader.getSystemClassLoader());
|
EvolutionSerializerGetterBase evolutionSerialiserGetter = new EvolutionSerializerGetter();
|
||||||
|
SerializerFactory factory1 = new SerializerFactory(
|
||||||
|
AllWhitelist.INSTANCE,
|
||||||
|
ClassLoader.getSystemClassLoader(),
|
||||||
|
evolutionSerialiserGetter);
|
||||||
|
|
||||||
TypeMismatch2 tm = new TypeMismatch2();
|
TypeMismatch2 tm = new TypeMismatch2();
|
||||||
tm.setA("10");
|
tm.setA("10");
|
||||||
|
@ -5,6 +5,8 @@ import net.corda.nodeapi.internal.serialization.AllWhitelist
|
|||||||
import net.corda.nodeapi.internal.serialization.EmptyWhitelist
|
import net.corda.nodeapi.internal.serialization.EmptyWhitelist
|
||||||
|
|
||||||
fun testDefaultFactory() = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader())
|
fun testDefaultFactory() = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader())
|
||||||
|
fun testDefaultFactoryNoEvolution() = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader(),
|
||||||
|
EvolutionSerializerGetterTesting())
|
||||||
fun testDefaultFactoryWithWhitelist() = SerializerFactory(EmptyWhitelist, ClassLoader.getSystemClassLoader())
|
fun testDefaultFactoryWithWhitelist() = SerializerFactory(EmptyWhitelist, ClassLoader.getSystemClassLoader())
|
||||||
|
|
||||||
class TestSerializationOutput(
|
class TestSerializationOutput(
|
||||||
|
@ -11,13 +11,14 @@ class DeserializeAndReturnEnvelopeTests {
|
|||||||
@Suppress("NOTHING_TO_INLINE")
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
inline private fun classTestName(clazz: String) = "${this.javaClass.name}\$${testName()}\$$clazz"
|
inline private fun classTestName(clazz: String) = "${this.javaClass.name}\$${testName()}\$$clazz"
|
||||||
|
|
||||||
|
val factory = testDefaultFactoryNoEvolution()
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun oneType() {
|
fun oneType() {
|
||||||
data class A(val a: Int, val b: String)
|
data class A(val a: Int, val b: String)
|
||||||
|
|
||||||
val a = A(10, "20")
|
val a = A(10, "20")
|
||||||
|
|
||||||
val factory = testDefaultFactory()
|
|
||||||
fun serialise(clazz: Any) = SerializationOutput(factory).serialize(clazz)
|
fun serialise(clazz: Any) = SerializationOutput(factory).serialize(clazz)
|
||||||
val obj = DeserializationInput(factory).deserializeAndReturnEnvelope(serialise(a))
|
val obj = DeserializationInput(factory).deserializeAndReturnEnvelope(serialise(a))
|
||||||
|
|
||||||
@ -33,7 +34,6 @@ class DeserializeAndReturnEnvelopeTests {
|
|||||||
|
|
||||||
val b = B(A(10, "20"), 30.0F)
|
val b = B(A(10, "20"), 30.0F)
|
||||||
|
|
||||||
val factory = testDefaultFactory()
|
|
||||||
fun serialise(clazz: Any) = SerializationOutput(factory).serialize(clazz)
|
fun serialise(clazz: Any) = SerializationOutput(factory).serialize(clazz)
|
||||||
val obj = DeserializationInput(factory).deserializeAndReturnEnvelope(serialise(b))
|
val obj = DeserializationInput(factory).deserializeAndReturnEnvelope(serialise(b))
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ class DeserializeMapTests {
|
|||||||
private const val VERBOSE = false
|
private const val VERBOSE = false
|
||||||
}
|
}
|
||||||
|
|
||||||
private val sf = testDefaultFactory()
|
private val sf = testDefaultFactoryNoEvolution()
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun mapTest() {
|
fun mapTest() {
|
||||||
|
@ -18,7 +18,7 @@ class DeserializeNeedingCarpentryOfEnumsTest : AmqpCarpenterBase(AllWhitelist) {
|
|||||||
//
|
//
|
||||||
// Setup the test
|
// Setup the test
|
||||||
//
|
//
|
||||||
val setupFactory = testDefaultFactory()
|
val setupFactory = testDefaultFactoryNoEvolution()
|
||||||
|
|
||||||
val enumConstants = listOf("AAA", "BBB", "CCC", "DDD", "EEE", "FFF",
|
val enumConstants = listOf("AAA", "BBB", "CCC", "DDD", "EEE", "FFF",
|
||||||
"GGG", "HHH", "III", "JJJ").associateBy({ it }, { EnumField() })
|
"GGG", "HHH", "III", "JJJ").associateBy({ it }, { EnumField() })
|
||||||
@ -57,7 +57,7 @@ class DeserializeNeedingCarpentryOfEnumsTest : AmqpCarpenterBase(AllWhitelist) {
|
|||||||
//
|
//
|
||||||
// Setup the test
|
// Setup the test
|
||||||
//
|
//
|
||||||
val setupFactory = testDefaultFactory()
|
val setupFactory = testDefaultFactoryNoEvolution()
|
||||||
|
|
||||||
val enumConstants = listOf("AAA", "BBB", "CCC", "DDD", "EEE", "FFF",
|
val enumConstants = listOf("AAA", "BBB", "CCC", "DDD", "EEE", "FFF",
|
||||||
"GGG", "HHH", "III", "JJJ").associateBy({ it }, { EnumField() })
|
"GGG", "HHH", "III", "JJJ").associateBy({ it }, { EnumField() })
|
||||||
|
@ -17,8 +17,8 @@ class DeserializeNeedingCarpentrySimpleTypesTest : AmqpCarpenterBase(AllWhitelis
|
|||||||
private const val VERBOSE = false
|
private const val VERBOSE = false
|
||||||
}
|
}
|
||||||
|
|
||||||
private val sf = testDefaultFactory()
|
private val sf = testDefaultFactoryNoEvolution()
|
||||||
private val sf2 = testDefaultFactory()
|
private val sf2 = testDefaultFactoryNoEvolution()
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun singleInt() {
|
fun singleInt() {
|
||||||
|
@ -27,7 +27,7 @@ class DeserializeNeedingCarpentryTests : AmqpCarpenterBase(AllWhitelist) {
|
|||||||
private const val VERBOSE = false
|
private const val VERBOSE = false
|
||||||
}
|
}
|
||||||
|
|
||||||
private val sf1 = testDefaultFactory()
|
private val sf1 = testDefaultFactoryNoEvolution()
|
||||||
|
|
||||||
// Deserialize with whitelisting on to check that `CordaSerializable` annotation present.
|
// Deserialize with whitelisting on to check that `CordaSerializable` annotation present.
|
||||||
private val sf2 = testDefaultFactoryWithWhitelist()
|
private val sf2 = testDefaultFactoryWithWhitelist()
|
||||||
|
@ -16,8 +16,8 @@ class DeserializeSimpleTypesTests {
|
|||||||
private const val VERBOSE = false
|
private const val VERBOSE = false
|
||||||
}
|
}
|
||||||
|
|
||||||
val sf1 = testDefaultFactory()
|
val sf1 = testDefaultFactoryNoEvolution()
|
||||||
val sf2 = testDefaultFactory()
|
val sf2 = testDefaultFactoryNoEvolution()
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testChar() {
|
fun testChar() {
|
||||||
|
@ -6,6 +6,8 @@ import org.assertj.core.api.Assertions
|
|||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.NotSerializableException
|
import java.io.NotSerializableException
|
||||||
|
import java.util.*
|
||||||
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
import kotlin.test.assertTrue
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
@ -387,21 +389,25 @@ class EnumEvolvabilityTests {
|
|||||||
data class C1(val annotatedEnum: AnnotatedEnumOnce)
|
data class C1(val annotatedEnum: AnnotatedEnumOnce)
|
||||||
|
|
||||||
val sf = testDefaultFactory()
|
val sf = testDefaultFactory()
|
||||||
|
val f = sf.javaClass.getDeclaredField("transformsCache")
|
||||||
|
f.isAccessible = true
|
||||||
|
|
||||||
assertEquals(0, sf.transformsCache.size)
|
val transformsCache = f.get(sf) as ConcurrentHashMap<String, EnumMap<TransformTypes, MutableList<Transform>>>
|
||||||
|
|
||||||
|
assertEquals(0, transformsCache.size)
|
||||||
|
|
||||||
val sb1 = TestSerializationOutput(VERBOSE, sf).serializeAndReturnSchema(C1(AnnotatedEnumOnce.D))
|
val sb1 = TestSerializationOutput(VERBOSE, sf).serializeAndReturnSchema(C1(AnnotatedEnumOnce.D))
|
||||||
|
|
||||||
assertEquals(2, sf.transformsCache.size)
|
assertEquals(2, transformsCache.size)
|
||||||
assertTrue(sf.transformsCache.containsKey(C1::class.java.name))
|
assertTrue(transformsCache.containsKey(C1::class.java.name))
|
||||||
assertTrue(sf.transformsCache.containsKey(AnnotatedEnumOnce::class.java.name))
|
assertTrue(transformsCache.containsKey(AnnotatedEnumOnce::class.java.name))
|
||||||
|
|
||||||
val sb2 = TestSerializationOutput(VERBOSE, sf).serializeAndReturnSchema(C2(AnnotatedEnumOnce.D))
|
val sb2 = TestSerializationOutput(VERBOSE, sf).serializeAndReturnSchema(C2(AnnotatedEnumOnce.D))
|
||||||
|
|
||||||
assertEquals(3, sf.transformsCache.size)
|
assertEquals(3, transformsCache.size)
|
||||||
assertTrue(sf.transformsCache.containsKey(C1::class.java.name))
|
assertTrue(transformsCache.containsKey(C1::class.java.name))
|
||||||
assertTrue(sf.transformsCache.containsKey(C2::class.java.name))
|
assertTrue(transformsCache.containsKey(C2::class.java.name))
|
||||||
assertTrue(sf.transformsCache.containsKey(AnnotatedEnumOnce::class.java.name))
|
assertTrue(transformsCache.containsKey(AnnotatedEnumOnce::class.java.name))
|
||||||
|
|
||||||
assertEquals(sb1.transformsSchema.types[AnnotatedEnumOnce::class.java.name],
|
assertEquals(sb1.transformsSchema.types[AnnotatedEnumOnce::class.java.name],
|
||||||
sb2.transformsSchema.types[AnnotatedEnumOnce::class.java.name])
|
sb2.transformsSchema.types[AnnotatedEnumOnce::class.java.name])
|
||||||
|
@ -65,7 +65,7 @@ class EnumTests {
|
|||||||
@Suppress("NOTHING_TO_INLINE")
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
inline private fun classTestName(clazz: String) = "${this.javaClass.name}\$${testName()}\$$clazz"
|
inline private fun classTestName(clazz: String) = "${this.javaClass.name}\$${testName()}\$$clazz"
|
||||||
|
|
||||||
private val sf1 = testDefaultFactory()
|
private val sf1 = testDefaultFactoryNoEvolution()
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun serialiseSimpleTest() {
|
fun serialiseSimpleTest() {
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
package net.corda.nodeapi.internal.serialization.amqp
|
||||||
|
|
||||||
|
import java.io.NotSerializableException
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An implementation of [EvolutionSerializerGetterBase] that disables all evolution within a
|
||||||
|
* [SerializerFactory]. This is most useful in testing where it is known that evolution should not be
|
||||||
|
* occurring and where bugs may be hidden by transparent invocation of an [EvolutionSerializer]. This
|
||||||
|
* prevents that by simply throwing an exception whenever such a serializer is requested.
|
||||||
|
*/
|
||||||
|
class EvolutionSerializerGetterTesting : EvolutionSerializerGetterBase() {
|
||||||
|
override fun getEvolutionSerializer(factory: SerializerFactory,
|
||||||
|
typeNotation: TypeNotation,
|
||||||
|
newSerializer: AMQPSerializer<Any>,
|
||||||
|
schemas: SerializationSchemas): AMQPSerializer<Any> {
|
||||||
|
throw NotSerializableException("No evolution should be occurring\n" +
|
||||||
|
" ${typeNotation.name}\n" +
|
||||||
|
" ${typeNotation.descriptor.name}\n" +
|
||||||
|
" ${newSerializer.type.typeName}\n" +
|
||||||
|
" ${newSerializer.typeDescriptor}\n\n${schemas.schema}")
|
||||||
|
}
|
||||||
|
}
|
@ -2,26 +2,90 @@ package net.corda.nodeapi.internal.serialization.amqp
|
|||||||
|
|
||||||
import net.corda.core.serialization.SerializedBytes
|
import net.corda.core.serialization.SerializedBytes
|
||||||
import net.corda.nodeapi.internal.serialization.AllWhitelist
|
import net.corda.nodeapi.internal.serialization.AllWhitelist
|
||||||
|
import net.corda.testing.common.internal.ProjectStructure.projectRootDir
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
import java.io.File
|
||||||
|
import java.net.URI
|
||||||
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
class GenericsTests {
|
class GenericsTests {
|
||||||
|
companion object {
|
||||||
|
val VERBOSE = false
|
||||||
|
|
||||||
|
@Suppress("UNUSED")
|
||||||
|
var localPath = projectRootDir.toUri().resolve(
|
||||||
|
"node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun printSeparator() = if (VERBOSE) println("\n\n-------------------------------------------\n\n") else Unit
|
||||||
|
|
||||||
|
private fun <T : Any> BytesAndSchemas<T>.printSchema() = if (VERBOSE) println("${this.schema}\n") else Unit
|
||||||
|
|
||||||
|
private fun ConcurrentHashMap<Any, AMQPSerializer<Any>>.printKeyToType() {
|
||||||
|
if (!VERBOSE) return
|
||||||
|
|
||||||
|
forEach {
|
||||||
|
println("Key = ${it.key} - ${it.value.type.typeName}")
|
||||||
|
}
|
||||||
|
println()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun twoDifferentTypesSameParameterizedOuter() {
|
||||||
|
data class G<A>(val a: A)
|
||||||
|
|
||||||
|
val factory = testDefaultFactoryNoEvolution()
|
||||||
|
|
||||||
|
val bytes1 = SerializationOutput(factory).serializeAndReturnSchema(G("hi")).apply { printSchema() }
|
||||||
|
|
||||||
|
factory.getSerializersByDescriptor().printKeyToType()
|
||||||
|
|
||||||
|
val bytes2 = SerializationOutput(factory).serializeAndReturnSchema(G(121)).apply { printSchema() }
|
||||||
|
|
||||||
|
factory.getSerializersByDescriptor().printKeyToType()
|
||||||
|
|
||||||
|
listOf(factory, testDefaultFactory()).forEach { f ->
|
||||||
|
DeserializationInput(f).deserialize(bytes1.obj).apply { assertEquals("hi", this.a) }
|
||||||
|
DeserializationInput(f).deserialize(bytes2.obj).apply { assertEquals(121, this.a) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun doWeIgnoreMultipleParams() {
|
||||||
|
data class G1<out T>(val a: T)
|
||||||
|
data class G2<out T>(val a: T)
|
||||||
|
data class Wrapper<out T>(val a: Int, val b: G1<T>, val c: G2<T>)
|
||||||
|
|
||||||
|
val factory = testDefaultFactoryNoEvolution()
|
||||||
|
val factory2 = testDefaultFactoryNoEvolution()
|
||||||
|
|
||||||
|
val bytes = SerializationOutput(factory).serializeAndReturnSchema(Wrapper(1, G1("hi"), G2("poop"))).apply { printSchema() }
|
||||||
|
printSeparator()
|
||||||
|
DeserializationInput(factory2).deserialize(bytes.obj)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun nestedSerializationOfGenerics() {
|
fun nestedSerializationOfGenerics() {
|
||||||
data class G<T>(val a: T)
|
data class G<out T>(val a: T)
|
||||||
data class Wrapper<T>(val a: Int, val b: G<T>)
|
data class Wrapper<out T>(val a: Int, val b: G<T>)
|
||||||
|
|
||||||
val factory = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader())
|
val factory = testDefaultFactoryNoEvolution()
|
||||||
val altContextFactory = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader())
|
val altContextFactory = testDefaultFactoryNoEvolution()
|
||||||
val ser = SerializationOutput(factory)
|
val ser = SerializationOutput(factory)
|
||||||
|
|
||||||
val bytes = ser.serializeAndReturnSchema(G("hi"))
|
val bytes = ser.serializeAndReturnSchema(G("hi")).apply { printSchema() }
|
||||||
|
|
||||||
|
factory.getSerializersByDescriptor().printKeyToType()
|
||||||
|
|
||||||
assertEquals("hi", DeserializationInput(factory).deserialize(bytes.obj).a)
|
assertEquals("hi", DeserializationInput(factory).deserialize(bytes.obj).a)
|
||||||
assertEquals("hi", DeserializationInput(altContextFactory).deserialize(bytes.obj).a)
|
assertEquals("hi", DeserializationInput(altContextFactory).deserialize(bytes.obj).a)
|
||||||
|
|
||||||
val bytes2 = ser.serializeAndReturnSchema(Wrapper(1, G("hi")))
|
val bytes2 = ser.serializeAndReturnSchema(Wrapper(1, G("hi"))).apply { printSchema() }
|
||||||
|
|
||||||
|
factory.getSerializersByDescriptor().printKeyToType()
|
||||||
|
|
||||||
|
printSeparator()
|
||||||
|
|
||||||
DeserializationInput(factory).deserialize(bytes2.obj).apply {
|
DeserializationInput(factory).deserialize(bytes2.obj).apply {
|
||||||
assertEquals(1, a)
|
assertEquals(1, a)
|
||||||
@ -36,7 +100,7 @@ class GenericsTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun nestedGenericsReferencesByteArrayViaSerializedBytes() {
|
fun nestedGenericsReferencesByteArrayViaSerializedBytes() {
|
||||||
data class G(val a : Int)
|
data class G(val a: Int)
|
||||||
data class Wrapper<T : Any>(val a: Int, val b: SerializedBytes<T>)
|
data class Wrapper<T : Any>(val a: Int, val b: SerializedBytes<T>)
|
||||||
|
|
||||||
val factory = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader())
|
val factory = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader())
|
||||||
@ -71,27 +135,30 @@ class GenericsTests {
|
|||||||
ser.serialize(Wrapper(Container(InnerA(1)))).apply {
|
ser.serialize(Wrapper(Container(InnerA(1)))).apply {
|
||||||
factories.forEach {
|
factories.forEach {
|
||||||
DeserializationInput(it).deserialize(this).apply { assertEquals(1, c.b.a_a) }
|
DeserializationInput(it).deserialize(this).apply { assertEquals(1, c.b.a_a) }
|
||||||
|
it.getSerializersByDescriptor().printKeyToType(); printSeparator()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ser.serialize(Wrapper(Container(InnerB(1)))).apply {
|
ser.serialize(Wrapper(Container(InnerB(1)))).apply {
|
||||||
factories.forEach {
|
factories.forEach {
|
||||||
DeserializationInput(it).deserialize(this).apply { assertEquals(1, c.b.a_b) }
|
DeserializationInput(it).deserialize(this).apply { assertEquals(1, c.b.a_b) }
|
||||||
|
it.getSerializersByDescriptor().printKeyToType(); printSeparator()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ser.serialize(Wrapper(Container(InnerC("Ho ho ho")))).apply {
|
ser.serialize(Wrapper(Container(InnerC("Ho ho ho")))).apply {
|
||||||
factories.forEach {
|
factories.forEach {
|
||||||
DeserializationInput(it).deserialize(this).apply { assertEquals("Ho ho ho", c.b.a_c) }
|
DeserializationInput(it).deserialize(this).apply { assertEquals("Ho ho ho", c.b.a_c) }
|
||||||
|
it.getSerializersByDescriptor().printKeyToType(); printSeparator()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun nestedSerializationWhereGenericDoesntImpactFingerprint() {
|
fun nestedSerializationWhereGenericDoesntImpactFingerprint() {
|
||||||
data class Inner(val a : Int)
|
data class Inner(val a: Int)
|
||||||
data class Container<T : Any>(val b: Inner)
|
data class Container<T : Any>(val b: Inner)
|
||||||
data class Wrapper<T: Any>(val c: Container<T>)
|
data class Wrapper<T : Any>(val c: Container<T>)
|
||||||
|
|
||||||
val factorys = listOf(
|
val factorys = listOf(
|
||||||
SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader()),
|
SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader()),
|
||||||
@ -111,4 +178,103 @@ class GenericsTests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class ForceWildcard<out T>(val t: T)
|
||||||
|
|
||||||
|
private fun forceWildcardSerialize(
|
||||||
|
a: ForceWildcard<*>,
|
||||||
|
factory: SerializerFactory = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader())): SerializedBytes<*> {
|
||||||
|
val bytes = SerializationOutput(factory).serializeAndReturnSchema(a)
|
||||||
|
factory.getSerializersByDescriptor().printKeyToType()
|
||||||
|
bytes.printSchema()
|
||||||
|
return bytes.obj
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
private fun forceWildcardDeserializeString(
|
||||||
|
bytes: SerializedBytes<*>,
|
||||||
|
factory: SerializerFactory = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader())) {
|
||||||
|
DeserializationInput(factory).deserialize(bytes as SerializedBytes<ForceWildcard<String>>)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
private fun forceWildcardDeserializeDouble(
|
||||||
|
bytes: SerializedBytes<*>,
|
||||||
|
factory: SerializerFactory = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader())) {
|
||||||
|
DeserializationInput(factory).deserialize(bytes as SerializedBytes<ForceWildcard<Double>>)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
private fun forceWildcardDeserialize(
|
||||||
|
bytes: SerializedBytes<*>,
|
||||||
|
factory: SerializerFactory = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader())) {
|
||||||
|
DeserializationInput(factory).deserialize(bytes as SerializedBytes<ForceWildcard<*>>)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun forceWildcard() {
|
||||||
|
forceWildcardDeserializeString(forceWildcardSerialize(ForceWildcard("hello")))
|
||||||
|
forceWildcardDeserializeDouble(forceWildcardSerialize(ForceWildcard(3.0)))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun forceWildcardSharedFactory() {
|
||||||
|
val f = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader())
|
||||||
|
forceWildcardDeserializeString(forceWildcardSerialize(ForceWildcard("hello"), f), f)
|
||||||
|
forceWildcardDeserializeDouble(forceWildcardSerialize(ForceWildcard(3.0), f), f)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun forceWildcardDeserialize() {
|
||||||
|
forceWildcardDeserialize(forceWildcardSerialize(ForceWildcard("hello")))
|
||||||
|
forceWildcardDeserialize(forceWildcardSerialize(ForceWildcard(10)))
|
||||||
|
forceWildcardDeserialize(forceWildcardSerialize(ForceWildcard(20.0)))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun forceWildcardDeserializeSharedFactory() {
|
||||||
|
val f = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader())
|
||||||
|
forceWildcardDeserialize(forceWildcardSerialize(ForceWildcard("hello"), f), f)
|
||||||
|
forceWildcardDeserialize(forceWildcardSerialize(ForceWildcard(10), f), f)
|
||||||
|
forceWildcardDeserialize(forceWildcardSerialize(ForceWildcard(20.0), f), f)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun loadGenericFromFile() {
|
||||||
|
val resource = "${javaClass.simpleName}.${testName()}"
|
||||||
|
val sf = testDefaultFactory()
|
||||||
|
|
||||||
|
// Uncomment to re-generate test files, needs to be done in three stages
|
||||||
|
// File(URI("$localPath/$resource")).writeBytes(forceWildcardSerialize(ForceWildcard("wibble")).bytes)
|
||||||
|
|
||||||
|
assertEquals("wibble",
|
||||||
|
DeserializationInput(sf).deserialize(SerializedBytes<ForceWildcard<*>>(
|
||||||
|
File(GenericsTests::class.java.getResource(resource).toURI()).readBytes())).t)
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DifferentBounds {
|
||||||
|
fun go()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun differentBounds() {
|
||||||
|
data class A (val a: Int): DifferentBounds {
|
||||||
|
override fun go() {
|
||||||
|
println(a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class G<out T : DifferentBounds>(val b: T)
|
||||||
|
|
||||||
|
val factorys = listOf(
|
||||||
|
SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader()),
|
||||||
|
SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader()))
|
||||||
|
|
||||||
|
val ser = SerializationOutput(factorys[0])
|
||||||
|
|
||||||
|
ser.serialize(G(A(10))).apply {
|
||||||
|
factorys.forEach {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -169,9 +169,11 @@ class SerializationOutputTests {
|
|||||||
|
|
||||||
private inline fun <reified T : Any> serdes(obj: T,
|
private inline fun <reified T : Any> serdes(obj: T,
|
||||||
factory: SerializerFactory = SerializerFactory(
|
factory: SerializerFactory = SerializerFactory(
|
||||||
AllWhitelist, ClassLoader.getSystemClassLoader()),
|
AllWhitelist, ClassLoader.getSystemClassLoader(),
|
||||||
|
EvolutionSerializerGetterTesting()),
|
||||||
freshDeserializationFactory: SerializerFactory = SerializerFactory(
|
freshDeserializationFactory: SerializerFactory = SerializerFactory(
|
||||||
AllWhitelist, ClassLoader.getSystemClassLoader()),
|
AllWhitelist, ClassLoader.getSystemClassLoader(),
|
||||||
|
EvolutionSerializerGetterTesting()),
|
||||||
expectedEqual: Boolean = true,
|
expectedEqual: Boolean = true,
|
||||||
expectDeserializedEqual: Boolean = true): T {
|
expectDeserializedEqual: Boolean = true): T {
|
||||||
val ser = SerializationOutput(factory)
|
val ser = SerializationOutput(factory)
|
||||||
|
@ -10,7 +10,7 @@ class SerializeAndReturnSchemaTest {
|
|||||||
@Suppress("NOTHING_TO_INLINE")
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
inline private fun classTestName(clazz: String) = "${this.javaClass.name}\$${testName()}\$$clazz"
|
inline private fun classTestName(clazz: String) = "${this.javaClass.name}\$${testName()}\$$clazz"
|
||||||
|
|
||||||
val factory = testDefaultFactory()
|
val factory = testDefaultFactoryNoEvolution()
|
||||||
|
|
||||||
// just a simple test to verify the internal test extension for serialize does
|
// just a simple test to verify the internal test extension for serialize does
|
||||||
// indeed give us the correct schema back. This is more useful in support of other
|
// indeed give us the correct schema back. This is more useful in support of other
|
||||||
|
@ -45,7 +45,7 @@ class StaticInitialisationOfSerializedObjectTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun KotlinObjectWithCompanionObject() {
|
fun kotlinObjectWithCompanionObject() {
|
||||||
data class D(val c: C)
|
data class D(val c: C)
|
||||||
|
|
||||||
val sf = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader())
|
val sf = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader())
|
||||||
@ -104,7 +104,7 @@ class StaticInitialisationOfSerializedObjectTest {
|
|||||||
override val classCarpenter = ClassCarpenter(ClassLoader.getSystemClassLoader(), wl2)
|
override val classCarpenter = ClassCarpenter(ClassLoader.getSystemClassLoader(), wl2)
|
||||||
}
|
}
|
||||||
|
|
||||||
// This time have the serilization factory and the carpenter use different whitelists
|
// This time have the serialization factory and the carpenter use different whitelists
|
||||||
@Test
|
@Test
|
||||||
fun deserializeTest2() {
|
fun deserializeTest2() {
|
||||||
data class D(val c: C2)
|
data class D(val c: C2)
|
||||||
|
Binary file not shown.
Loading…
Reference in New Issue
Block a user