CORDA-1603: Class carpenter able to synthesis Cash.State objects (#3400)

This requires the class carpenter to be able to run in a "lenient" mode where it permits synthesised classes to implement interfaces with unimplemented methods.
This commit is contained in:
Shams Asari 2018-06-25 11:33:37 +01:00 committed by GitHub
parent 68d4ed0cd9
commit b97af477b2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 307 additions and 303 deletions

View File

@ -50,7 +50,7 @@ class AMQPClientSerializationScheme(
target == SerializationContext.UseCase.RPCClient || target == SerializationContext.UseCase.P2P)
override fun rpcClientSerializerFactory(context: SerializationContext): SerializerFactory {
return SerializerFactory(context.whitelist, ClassLoader.getSystemClassLoader()).apply {
return SerializerFactory(context.whitelist, ClassLoader.getSystemClassLoader(), context.lenientCarpenterEnabled).apply {
register(RpcClientObservableSerializer)
register(RpcClientCordaFutureSerializer(this))
register(RxNotificationSerializer(this))

View File

@ -142,6 +142,14 @@ interface SerializationContext {
* otherwise they appear as new copies of the object.
*/
val objectReferencesEnabled: Boolean
/**
* If true the carpenter will happily synthesis classes that implement interfaces containing methods that are not
* getters for any AMQP fields. Invoking these methods will throw an [AbstractMethodError]. If false then an exception
* will be thrown during deserialization instead.
*
* The default is false.
*/
val lenientCarpenterEnabled: Boolean
/**
* The use case we are serializing or deserializing for. See [UseCase].
*/
@ -157,6 +165,12 @@ interface SerializationContext {
*/
fun withoutReferences(): SerializationContext
/**
* Return a new context based on this one but with a lenient carpenter.
* @see lenientCarpenterEnabled
*/
fun withLenientCarpenter(): SerializationContext
/**
* Helper method to return a new context based on this context with the deserialization class loader changed.
*/

View File

@ -7,6 +7,10 @@ release, see :doc:`upgrade-notes`.
Unreleased
----------
* The class carpenter has a "lenient" mode where it will, during deserialisation, happily synthesis classes that implement
interfaces that will have unimplemented methods. This is useful, for example, for object viewers. This can be turned on
with ``SerializationContext.withLenientCarpenter``.
* Introduced a grace period before the initial node registration fails if the node cannot connect to the Doorman.
It retries 10 times with a 1 minute interval in between each try. At the moment this is not configurable.

View File

@ -557,6 +557,11 @@ without the supporting classes being present on the classpath. This can be usef
be able to use reflection over the deserialized data, for scripting languages that run on the JVM, and also for
ensuring classes not on the classpath can be deserialized without loading potentially malicious code.
If the original class implements some interfaces then the carpenter will make sure that all of the interface methods are
backed by feilds. If that's not the case then an exception will be thrown during deserialization. This check can
be turned off with ``SerializationContext.withLenientCarpenter``. This can be useful if only the field getters are needed,
say in an object viewer.
Possible future enhancements include:
#. Java singleton support. We will add support for identifying classes which are singletons and identifying the

View File

@ -26,15 +26,13 @@ class AMQPServerSerializationScheme(
throw UnsupportedOperationException()
}
override fun rpcServerSerializerFactory(context: SerializationContext) =
SerializerFactory(
context.whitelist,
context.deserializationClassLoader
).apply {
override fun rpcServerSerializerFactory(context: SerializationContext): SerializerFactory {
return SerializerFactory(context.whitelist, context.deserializationClassLoader, context.lenientCarpenterEnabled).apply {
register(RpcServerObservableSerializer())
register(RpcServerCordaFutureSerializer(this))
register(RxNotificationSerializer(this))
}
}
override fun canDeserializeVersion(magic: CordaSerializationMagic, target: SerializationContext.UseCase): Boolean {
return canDeserializeVersion(magic) &&

View File

@ -30,7 +30,8 @@ data class SerializationContextImpl @JvmOverloads constructor(override val prefe
override val objectReferencesEnabled: Boolean,
override val useCase: SerializationContext.UseCase,
override val encoding: SerializationEncoding?,
override val encodingWhitelist: EncodingWhitelist = NullEncodingWhitelist) : SerializationContext {
override val encodingWhitelist: EncodingWhitelist = NullEncodingWhitelist,
override val lenientCarpenterEnabled: Boolean = false) : SerializationContext {
private val builder = AttachmentsClassLoaderBuilder(properties, deserializationClassLoader)
/**
@ -52,6 +53,8 @@ data class SerializationContextImpl @JvmOverloads constructor(override val prefe
return copy(objectReferencesEnabled = false)
}
override fun withLenientCarpenter(): SerializationContext = copy(lenientCarpenterEnabled = true)
override fun withClassLoader(classLoader: ClassLoader): SerializationContext {
return copy(deserializationClassLoader = classLoader)
}

View File

@ -7,6 +7,7 @@ import net.corda.core.serialization.SerializationContext
fun createSerializerFactoryFactory(): SerializerFactoryFactory = SerializerFactoryFactoryImpl()
open class SerializerFactoryFactoryImpl : SerializerFactoryFactory {
override fun make(context: SerializationContext) =
SerializerFactory(context.whitelist, context.deserializationClassLoader)
override fun make(context: SerializationContext): SerializerFactory {
return SerializerFactory(context.whitelist, context.deserializationClassLoader, context.lenientCarpenterEnabled)
}
}

View File

@ -7,6 +7,8 @@ import net.corda.serialization.internal.amqp.SerializerFactory.Companion.nameFor
import org.apache.qpid.proton.amqp.Symbol
import org.apache.qpid.proton.codec.Data
import java.io.NotSerializableException
import java.lang.reflect.Constructor
import java.lang.reflect.InvocationTargetException
import java.lang.reflect.Type
import kotlin.reflect.jvm.javaConstructor
@ -29,8 +31,7 @@ open class ObjectSerializer(val clazz: Type, factory: SerializerFactory) : AMQPS
private val typeName = nameForType(clazz)
override val typeDescriptor = Symbol.valueOf(
"$DESCRIPTOR_DOMAIN:${factory.fingerPrinter.fingerprint(type)}")!!
override val typeDescriptor: Symbol = Symbol.valueOf("$DESCRIPTOR_DOMAIN:${factory.fingerPrinter.fingerprint(type)}")
// We restrict to only those annotated or whitelisted
private val interfaces = interfacesForSerialization(clazz, factory)
@ -119,7 +120,7 @@ open class ObjectSerializer(val clazz: Type, factory: SerializerFactory) : AMQPS
context: SerializationContext): Any = ifThrowsAppend({ clazz.typeName }) {
logger.trace { "Calling setter based construction for ${clazz.typeName}" }
val instance: Any = javaConstructor?.newInstance() ?: throw NotSerializableException(
val instance: Any = javaConstructor?.newInstanceUnwrapped() ?: throw NotSerializableException(
"Failed to instantiate instance of object $clazz")
// read the properties out of the serialised form, since we're invoking the setters the order we
@ -153,7 +154,15 @@ open class ObjectSerializer(val clazz: Type, factory: SerializerFactory) : AMQPS
+ "serialized properties.")
}
return javaConstructor?.newInstance(*properties.toTypedArray())
return javaConstructor?.newInstanceUnwrapped(*properties.toTypedArray())
?: throw NotSerializableException("Attempt to deserialize an interface: $clazz. Serialized form is invalid.")
}
private fun <T> Constructor<T>.newInstanceUnwrapped(vararg args: Any?): T {
try {
return newInstance(*args)
} catch (e: InvocationTargetException) {
throw e.cause!!
}
}
}

View File

@ -8,6 +8,7 @@ import net.corda.core.StubOutForDJVM
import net.corda.core.internal.kotlinObjectInstance
import net.corda.core.internal.uncheckedCast
import net.corda.core.serialization.ClassWhitelist
import net.corda.core.utilities.contextLogger
import net.corda.core.utilities.debug
import net.corda.core.utilities.loggerFor
import net.corda.core.utilities.trace
@ -53,40 +54,43 @@ open class SerializerFactory(
private val serializersByType: MutableMap<Type, AMQPSerializer<Any>>,
val serializersByDescriptor: MutableMap<Any, AMQPSerializer<Any>>,
private val customSerializers: MutableList<SerializerFor>,
val transformsCache: MutableMap<String, EnumMap<TransformTypes, MutableList<Transform>>>) {
val transformsCache: MutableMap<String, EnumMap<TransformTypes, MutableList<Transform>>>
) {
@DeleteForDJVM
constructor(whitelist: ClassWhitelist,
classCarpenter: ClassCarpenter,
evolutionSerializerGetter: EvolutionSerializerGetterBase = EvolutionSerializerGetter(),
fingerPrinter: FingerPrinter = SerializerFingerPrinter()
) : this(whitelist, classCarpenter, evolutionSerializerGetter, fingerPrinter,
serializersByType = ConcurrentHashMap(),
serializersByDescriptor = ConcurrentHashMap(),
customSerializers = CopyOnWriteArrayList(),
transformsCache = ConcurrentHashMap())
) : this(
whitelist,
classCarpenter,
evolutionSerializerGetter,
fingerPrinter,
ConcurrentHashMap(),
ConcurrentHashMap(),
CopyOnWriteArrayList(),
ConcurrentHashMap()
)
@DeleteForDJVM
constructor(whitelist: ClassWhitelist,
classLoader: ClassLoader,
lenientCarpenter: Boolean = false,
evolutionSerializerGetter: EvolutionSerializerGetterBase = EvolutionSerializerGetter(),
fingerPrinter: FingerPrinter = SerializerFingerPrinter()
) : this(whitelist, ClassCarpenterImpl(classLoader, whitelist), evolutionSerializerGetter, fingerPrinter,
serializersByType = ConcurrentHashMap(),
serializersByDescriptor = ConcurrentHashMap(),
customSerializers = CopyOnWriteArrayList(),
transformsCache = ConcurrentHashMap())
) : this(whitelist, ClassCarpenterImpl(classLoader, whitelist, lenientCarpenter), evolutionSerializerGetter, fingerPrinter)
init {
fingerPrinter.setOwner(this)
}
val classloader: ClassLoader
get() = classCarpenter.classloader
val classloader: ClassLoader get() = classCarpenter.classloader
private fun getEvolutionSerializer(typeNotation: TypeNotation, newSerializer: AMQPSerializer<Any>,
schemas: SerializationSchemas) = evolutionSerializerGetter.getEvolutionSerializer(this, typeNotation, newSerializer, schemas)
private val logger = loggerFor<SerializerFactory>()
private fun getEvolutionSerializer(typeNotation: TypeNotation,
newSerializer: AMQPSerializer<Any>,
schemas: SerializationSchemas): AMQPSerializer<Any> {
return evolutionSerializerGetter.getEvolutionSerializer(this, typeNotation, newSerializer, schemas)
}
/**
* Look up, and manufacture if necessary, a serializer for the given type.
@ -380,6 +384,8 @@ open class SerializerFactory(
}
companion object {
private val logger = contextLogger()
fun isPrimitive(type: Type): Boolean = primitiveTypeName(type) != null
fun primitiveTypeName(type: Type): String? {
@ -469,4 +475,3 @@ open class SerializerFactory(
override fun toString(): String = "?"
}
}

View File

@ -63,7 +63,7 @@ fun CompositeType.carpenterSchema(classloader: ClassLoader,
}
try {
providesList.add(classloader.loadClass(it))
providesList.add(classloader.loadClass(it.stripGenerics()))
} catch (e: ClassNotFoundException) {
carpenterSchemas.addDepPair(this, name, it)
isCreatable = false

View File

@ -6,6 +6,8 @@ import net.corda.core.DeleteForDJVM
import net.corda.core.KeepForDJVM
import net.corda.core.serialization.ClassWhitelist
import net.corda.core.serialization.CordaSerializable
import net.corda.core.utilities.contextLogger
import net.corda.core.utilities.debug
import org.objectweb.asm.ClassWriter
import org.objectweb.asm.MethodVisitor
import org.objectweb.asm.Opcodes.*
@ -102,8 +104,9 @@ interface ClassCarpenter {
* Equals/hashCode methods are not yet supported.
*/
@DeleteForDJVM
class ClassCarpenterImpl(cl: ClassLoader, override val whitelist: ClassWhitelist) : ClassCarpenter {
constructor(whitelist: ClassWhitelist) : this(Thread.currentThread().contextClassLoader, whitelist)
class ClassCarpenterImpl(cl: ClassLoader = Thread.currentThread().contextClassLoader,
override val whitelist: ClassWhitelist,
private val lenient: Boolean = false) : ClassCarpenter {
// TODO: Generics.
// TODO: Sandbox the generated code when a security manager is in use.
@ -439,25 +442,36 @@ class ClassCarpenterImpl(cl: ClassLoader, override val whitelist: ClassWhitelist
// actually called, which is a bit too dynamic for my tastes.
val allFields = schema.fieldsIncludingSuperclasses()
for (itf in schema.interfaces) {
itf.methods.forEach {
val fieldNameFromItf = when {
it.name.startsWith("get") -> it.name.substring(3).decapitalize()
else -> throw InterfaceMismatchNonGetterException(itf, it)
methodLoop@
for (method in itf.methods) {
val fieldNameFromItf = if (method.name.startsWith("get")) {
method.name.substring(3).decapitalize()
} else if (lenient) {
logger.debug { "Ignoring interface $method which is not a getter" }
continue@methodLoop
} else {
throw InterfaceMismatchNonGetterException(itf, method)
}
// If we're trying to carpent a class that prior to serialisation / deserialization
// was made by a carpenter then we can ignore this (it will implement a plain get
// method from SimpleFieldAccess).
if (fieldNameFromItf.isEmpty() && SimpleFieldAccess::class.java in schema.interfaces) return@forEach
if (fieldNameFromItf.isEmpty() && SimpleFieldAccess::class.java in schema.interfaces) continue@methodLoop
if ((schema is ClassSchema) and (fieldNameFromItf !in allFields)) {
throw InterfaceMismatchMissingAMQPFieldException(itf, fieldNameFromItf)
if (lenient) {
logger.debug { "Ignoring interface $method which is not backed by an AMQP field" }
} else {
throw InterfaceMismatchMissingAMQPFieldException(itf, fieldNameFromItf)
}
}
}
}
}
companion object {
private val logger = contextLogger()
@JvmStatic
@Suppress("UNUSED")
fun getField(obj: Any, name: String): Any? = obj.javaClass.getMethod("get" + name.capitalize()).invoke(obj)

View File

@ -8,6 +8,9 @@ import org.junit.Test;
import java.io.NotSerializableException;
import static net.corda.serialization.internal.amqp.testutils.AMQPTestUtilsKt.testDefaultFactory;
import static org.assertj.core.api.Assertions.*;
@Ignore("Current behaviour allows for the serialization of objects with private members, this will be disallowed at some point in the future")
public class ErrorMessageTests {
private String errMsg(String property, String testname) {
@ -32,19 +35,10 @@ public class ErrorMessageTests {
@Test
public void testJavaConstructorAnnotations() {
EvolutionSerializerGetterBase evolutionSerialiserGetter = new EvolutionSerializerGetter();
FingerPrinter fingerPrinter = new SerializerFingerPrinter();
SerializerFactory factory1 = new SerializerFactory(
AllWhitelist.INSTANCE,
ClassLoader.getSystemClassLoader(),
evolutionSerialiserGetter,
fingerPrinter);
SerializationOutput ser = new SerializationOutput(testDefaultFactory());
SerializationOutput ser = new SerializationOutput(factory1);
Assertions.assertThatThrownBy(() -> ser.serialize(new C(1), TestSerializationContext.testSerializationContext))
assertThatThrownBy(() -> ser.serialize(new C(1), TestSerializationContext.testSerializationContext))
.isInstanceOf(NotSerializableException.class)
.hasMessage(errMsg("a", getClass().getName()));
}
}

View File

@ -1,7 +1,6 @@
package net.corda.serialization.internal.amqp;
import net.corda.core.serialization.SerializationCustomSerializer;
import net.corda.serialization.internal.AllWhitelist;
import net.corda.serialization.internal.amqp.testutils.TestSerializationContext;
import org.junit.Test;
@ -9,6 +8,8 @@ import java.io.NotSerializableException;
import java.util.ArrayList;
import java.util.List;
import static net.corda.serialization.internal.amqp.testutils.AMQPTestUtilsKt.testDefaultFactory;
public class JavaCustomSerializerTests {
/**
* The class lacks a public constructor that takes parameters it can associate
@ -87,10 +88,8 @@ public class JavaCustomSerializerTests {
}
@Test
public void serializeExample() throws NotSerializableException, NoSuchFieldException, IllegalAccessException {
SerializerFactory factory = new SerializerFactory(AllWhitelist.INSTANCE, ClassLoader.getSystemClassLoader(),
new EvolutionSerializerGetter(),
new SerializerFingerPrinter());
public void serializeExample() throws NotSerializableException {
SerializerFactory factory = testDefaultFactory();
SerializationOutput ser = new SerializationOutput(factory);
List<Integer> l = new ArrayList<Integer>(2);
@ -102,7 +101,5 @@ public class JavaCustomSerializerTests {
factory.registerExternal(ccs);
ser.serialize(e, TestSerializationContext.testSerializationContext);
}
}

View File

@ -1,11 +1,11 @@
package net.corda.serialization.internal.amqp;
import net.corda.core.serialization.SerializedBytes;
import net.corda.serialization.internal.AllWhitelist;
import net.corda.serialization.internal.amqp.testutils.TestSerializationContext;
import org.junit.Test;
import java.io.NotSerializableException;
import static net.corda.serialization.internal.amqp.testutils.AMQPTestUtilsKt.testDefaultFactory;
import static org.jgroups.util.Util.assertEquals;
public class JavaGenericsTest {
@ -27,11 +27,7 @@ public class JavaGenericsTest {
public void basicGeneric() throws NotSerializableException {
A a1 = new A(1);
SerializerFactory factory = new SerializerFactory(
AllWhitelist.INSTANCE,
ClassLoader.getSystemClassLoader(),
new EvolutionSerializerGetter(),
new SerializerFingerPrinter());
SerializerFactory factory = testDefaultFactory();
SerializationOutput ser = new SerializationOutput(factory);
SerializedBytes<?> bytes = ser.serialize(a1, TestSerializationContext.testSerializationContext);
@ -43,13 +39,9 @@ public class JavaGenericsTest {
}
private SerializedBytes<?> forceWildcardSerialize(A<?> a) throws NotSerializableException {
SerializerFactory factory = new SerializerFactory(
AllWhitelist.INSTANCE,
ClassLoader.getSystemClassLoader(),
new EvolutionSerializerGetter(),
new SerializerFingerPrinter());
SerializerFactory factory = testDefaultFactory();
return (new SerializationOutput(factory)).serialize(a, TestSerializationContext.testSerializationContext);
return (new SerializationOutput(factory)).serialize(a, TestSerializationContext.testSerializationContext);
}
private SerializedBytes<?> forceWildcardSerializeFactory(
@ -59,11 +51,7 @@ public class JavaGenericsTest {
}
private A<?> forceWildcardDeserialize(SerializedBytes<?> bytes) throws NotSerializableException {
SerializerFactory factory = new SerializerFactory(
AllWhitelist.INSTANCE,
ClassLoader.getSystemClassLoader(),
new EvolutionSerializerGetter(),
new SerializerFingerPrinter());
SerializerFactory factory = testDefaultFactory();
DeserializationInput des = new DeserializationInput(factory);
return des.deserialize(bytes, A.class, TestSerializationContext.testSerializationContext);
@ -85,11 +73,7 @@ public class JavaGenericsTest {
@Test
public void forceWildcardSharedFactory() throws NotSerializableException {
SerializerFactory factory = new SerializerFactory(
AllWhitelist.INSTANCE,
ClassLoader.getSystemClassLoader(),
new EvolutionSerializerGetter(),
new SerializerFingerPrinter());
SerializerFactory factory = testDefaultFactory();
SerializedBytes<?> bytes = forceWildcardSerializeFactory(new A(new Inner(29)), factory);
Inner i = (Inner)forceWildcardDeserializeFactory(bytes, factory).getT();

View File

@ -4,28 +4,25 @@ import com.google.common.collect.ImmutableList;
import net.corda.core.contracts.ContractState;
import net.corda.core.identity.AbstractParty;
import net.corda.core.serialization.SerializedBytes;
import net.corda.serialization.internal.AllWhitelist;
import net.corda.serialization.internal.amqp.testutils.TestSerializationContext;
import org.assertj.core.api.Assertions;
import org.jetbrains.annotations.NotNull;
import org.junit.Test;
import java.io.NotSerializableException;
import java.util.List;
import static net.corda.serialization.internal.amqp.testutils.AMQPTestUtilsKt.testDefaultFactory;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
class OuterClass1 {
protected SerializationOutput ser;
DeserializationInput desExisting;
DeserializationInput desRegen;
OuterClass1() {
SerializerFactory factory1 = new SerializerFactory(AllWhitelist.INSTANCE, ClassLoader.getSystemClassLoader(),
new EvolutionSerializerGetter(),
new SerializerFingerPrinter());
SerializerFactory factory1 = testDefaultFactory();
SerializerFactory factory2 = new SerializerFactory(AllWhitelist.INSTANCE, ClassLoader.getSystemClassLoader(),
new EvolutionSerializerGetter(),
new SerializerFingerPrinter());
SerializerFactory factory2 = testDefaultFactory();
this.ser = new SerializationOutput(factory1);
this.desExisting = new DeserializationInput(factory1);
@ -59,13 +56,9 @@ class OuterClass2 {
DeserializationInput desRegen;
OuterClass2() {
SerializerFactory factory1 = new SerializerFactory(AllWhitelist.INSTANCE, ClassLoader.getSystemClassLoader(),
new EvolutionSerializerGetter(),
new SerializerFingerPrinter());
SerializerFactory factory1 = testDefaultFactory();
SerializerFactory factory2 = new SerializerFactory(AllWhitelist.INSTANCE, ClassLoader.getSystemClassLoader(),
new EvolutionSerializerGetter(),
new SerializerFingerPrinter());
SerializerFactory factory2 = testDefaultFactory();
this.ser = new SerializationOutput(factory1);
this.desExisting = new DeserializationInput(factory1);
@ -104,9 +97,7 @@ abstract class AbstractClass2 {
protected SerializationOutput ser;
AbstractClass2() {
SerializerFactory factory = new SerializerFactory(AllWhitelist.INSTANCE, ClassLoader.getSystemClassLoader(),
new EvolutionSerializerGetter(),
new SerializerFingerPrinter());
SerializerFactory factory = testDefaultFactory();
this.ser = new SerializationOutput(factory);
}
@ -134,9 +125,7 @@ abstract class AbstractClass3 {
class Inherator5 extends AbstractClass3 {
public void run() throws NotSerializableException {
SerializerFactory factory = new SerializerFactory(AllWhitelist.INSTANCE, ClassLoader.getSystemClassLoader(),
new EvolutionSerializerGetter(),
new SerializerFingerPrinter());
SerializerFactory factory = testDefaultFactory();
SerializationOutput ser = new SerializationOutput(factory);
ser.serialize(new DummyState(), TestSerializationContext.testSerializationContext);
@ -154,9 +143,7 @@ class Inherator6 extends AbstractClass3 {
}
public void run() throws NotSerializableException {
SerializerFactory factory = new SerializerFactory(AllWhitelist.INSTANCE, ClassLoader.getSystemClassLoader(),
new EvolutionSerializerGetter(),
new SerializerFingerPrinter());
SerializerFactory factory = testDefaultFactory();
SerializationOutput ser = new SerializationOutput(factory);
ser.serialize(new Wrapper(new DummyState()), TestSerializationContext.testSerializationContext);
@ -166,57 +153,57 @@ class Inherator6 extends AbstractClass3 {
public class JavaNestedClassesTests {
@Test
public void publicNested() {
Assertions.assertThatThrownBy(() -> new OuterClass1().run()).isInstanceOf(
assertThatThrownBy(() -> new OuterClass1().run()).isInstanceOf(
NotSerializableException.class).hasMessageContaining(
"has synthetic fields and is likely a nested inner class");
}
@Test
public void privateNested() {
Assertions.assertThatThrownBy(() -> new OuterClass2().run()).isInstanceOf(
assertThatThrownBy(() -> new OuterClass2().run()).isInstanceOf(
NotSerializableException.class).hasMessageContaining(
"has synthetic fields and is likely a nested inner class");
}
@Test
public void publicNestedInherited() {
Assertions.assertThatThrownBy(() -> new Inherator1().run()).isInstanceOf(
assertThatThrownBy(() -> new Inherator1().run()).isInstanceOf(
NotSerializableException.class).hasMessageContaining(
"has synthetic fields and is likely a nested inner class");
Assertions.assertThatThrownBy(() -> new Inherator1().iRun()).isInstanceOf(
assertThatThrownBy(() -> new Inherator1().iRun()).isInstanceOf(
NotSerializableException.class).hasMessageContaining(
"has synthetic fields and is likely a nested inner class");
}
@Test
public void protectedNestedInherited() {
Assertions.assertThatThrownBy(() -> new Inherator2().run()).isInstanceOf(
assertThatThrownBy(() -> new Inherator2().run()).isInstanceOf(
NotSerializableException.class).hasMessageContaining(
"has synthetic fields and is likely a nested inner class");
Assertions.assertThatThrownBy(() -> new Inherator2().iRun()).isInstanceOf(
assertThatThrownBy(() -> new Inherator2().iRun()).isInstanceOf(
NotSerializableException.class).hasMessageContaining(
"has synthetic fields and is likely a nested inner class");
}
@Test
public void abstractNested() {
Assertions.assertThatThrownBy(() -> new Inherator4().run()).isInstanceOf(
assertThatThrownBy(() -> new Inherator4().run()).isInstanceOf(
NotSerializableException.class).hasMessageContaining(
"has synthetic fields and is likely a nested inner class");
}
@Test
public void abstractNestedFactoryOnNested() {
Assertions.assertThatThrownBy(() -> new Inherator5().run()).isInstanceOf(
assertThatThrownBy(() -> new Inherator5().run()).isInstanceOf(
NotSerializableException.class).hasMessageContaining(
"has synthetic fields and is likely a nested inner class");
}
@Test
public void abstractNestedFactoryOnNestedInWrapper() {
Assertions.assertThatThrownBy(() -> new Inherator6().run()).isInstanceOf(
assertThatThrownBy(() -> new Inherator6().run()).isInstanceOf(
NotSerializableException.class).hasMessageContaining(
"has synthetic fields and is likely a nested inner class");
}

View File

@ -3,15 +3,16 @@ package net.corda.serialization.internal.amqp;
import com.google.common.collect.ImmutableList;
import net.corda.core.contracts.ContractState;
import net.corda.core.identity.AbstractParty;
import net.corda.serialization.internal.AllWhitelist;
import net.corda.serialization.internal.amqp.testutils.TestSerializationContext;
import org.assertj.core.api.Assertions;
import org.jetbrains.annotations.NotNull;
import org.junit.Test;
import java.io.NotSerializableException;
import java.util.List;
import static net.corda.serialization.internal.amqp.testutils.AMQPTestUtilsKt.testDefaultFactory;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
abstract class JavaNestedInheritenceTestsBase {
class DummyState implements ContractState {
@Override @NotNull public List<AbstractParty> getParticipants() {
@ -33,38 +34,32 @@ class TemplateWrapper<T> {
public class JavaNestedInheritenceTests extends JavaNestedInheritenceTestsBase {
@Test
public void serializeIt() {
SerializerFactory factory = new SerializerFactory(AllWhitelist.INSTANCE, ClassLoader.getSystemClassLoader(),
new EvolutionSerializerGetter(),
new SerializerFingerPrinter());
SerializerFactory factory = testDefaultFactory();
SerializationOutput ser = new SerializationOutput(factory);
Assertions.assertThatThrownBy(() -> ser.serialize(new DummyState(), TestSerializationContext.testSerializationContext)).isInstanceOf(
assertThatThrownBy(() -> ser.serialize(new DummyState(), TestSerializationContext.testSerializationContext)).isInstanceOf(
NotSerializableException.class).hasMessageContaining(
"has synthetic fields and is likely a nested inner class");
}
@Test
public void serializeIt2() {
SerializerFactory factory = new SerializerFactory(AllWhitelist.INSTANCE, ClassLoader.getSystemClassLoader(),
new EvolutionSerializerGetter(),
new SerializerFingerPrinter());
SerializerFactory factory = testDefaultFactory();
SerializationOutput ser = new SerializationOutput(factory);
Assertions.assertThatThrownBy(() -> ser.serialize(new Wrapper (new DummyState()), TestSerializationContext.testSerializationContext)).isInstanceOf(
assertThatThrownBy(() -> ser.serialize(new Wrapper (new DummyState()), TestSerializationContext.testSerializationContext)).isInstanceOf(
NotSerializableException.class).hasMessageContaining(
"has synthetic fields and is likely a nested inner class");
}
@Test
public void serializeIt3() throws NotSerializableException {
SerializerFactory factory1 = new SerializerFactory(AllWhitelist.INSTANCE, ClassLoader.getSystemClassLoader(),
new EvolutionSerializerGetter(),
new SerializerFingerPrinter());
public void serializeIt3() {
SerializerFactory factory1 = testDefaultFactory();
SerializationOutput ser = new SerializationOutput(factory1);
Assertions.assertThatThrownBy(() -> ser.serialize(new TemplateWrapper<ContractState> (new DummyState()), TestSerializationContext.testSerializationContext)).isInstanceOf(
assertThatThrownBy(() -> ser.serialize(new TemplateWrapper<ContractState> (new DummyState()), TestSerializationContext.testSerializationContext)).isInstanceOf(
NotSerializableException.class).hasMessageContaining(
"has synthetic fields and is likely a nested inner class");
}

View File

@ -1,14 +1,15 @@
package net.corda.serialization.internal.amqp;
import net.corda.serialization.internal.AllWhitelist;
import net.corda.serialization.internal.amqp.testutils.TestSerializationContext;
import org.junit.Test;
import static org.junit.Assert.*;
import java.io.NotSerializableException;
import java.lang.reflect.Field;
import java.util.Map;
import static net.corda.serialization.internal.amqp.testutils.AMQPTestUtilsKt.testDefaultFactory;
import static org.junit.Assert.*;
public class JavaPrivatePropertyTests {
static class C {
private String a;
@ -76,10 +77,8 @@ public class JavaPrivatePropertyTests {
}
@Test
public void singlePrivateBooleanWithConstructor() throws NotSerializableException, NoSuchFieldException, IllegalAccessException {
SerializerFactory factory = new SerializerFactory(AllWhitelist.INSTANCE, ClassLoader.getSystemClassLoader(),
new EvolutionSerializerGetter(),
new SerializerFingerPrinter());
public void singlePrivateBooleanWithConstructor() throws NotSerializableException {
SerializerFactory factory = testDefaultFactory();
SerializationOutput ser = new SerializationOutput(factory);
DeserializationInput des = new DeserializationInput(factory);
@ -89,10 +88,8 @@ public class JavaPrivatePropertyTests {
}
@Test
public void singlePrivateBooleanWithNoConstructor() throws NotSerializableException, NoSuchFieldException, IllegalAccessException {
SerializerFactory factory = new SerializerFactory(AllWhitelist.INSTANCE, ClassLoader.getSystemClassLoader(),
new EvolutionSerializerGetter(),
new SerializerFingerPrinter());
public void singlePrivateBooleanWithNoConstructor() throws NotSerializableException {
SerializerFactory factory = testDefaultFactory();
SerializationOutput ser = new SerializationOutput(factory);
DeserializationInput des = new DeserializationInput(factory);
@ -104,10 +101,8 @@ public class JavaPrivatePropertyTests {
}
@Test
public void testCapitilsationOfIs() throws NotSerializableException, NoSuchFieldException, IllegalAccessException {
SerializerFactory factory = new SerializerFactory(AllWhitelist.INSTANCE, ClassLoader.getSystemClassLoader(),
new EvolutionSerializerGetter(),
new SerializerFingerPrinter());
public void testCapitilsationOfIs() throws NotSerializableException {
SerializerFactory factory = testDefaultFactory();
SerializationOutput ser = new SerializationOutput(factory);
DeserializationInput des = new DeserializationInput(factory);
@ -120,10 +115,8 @@ public class JavaPrivatePropertyTests {
}
@Test
public void singlePrivateIntWithBoolean() throws NotSerializableException, NoSuchFieldException, IllegalAccessException {
SerializerFactory factory = new SerializerFactory(AllWhitelist.INSTANCE, ClassLoader.getSystemClassLoader(),
new EvolutionSerializerGetter(),
new SerializerFingerPrinter());
public void singlePrivateIntWithBoolean() throws NotSerializableException {
SerializerFactory factory = testDefaultFactory();
SerializationOutput ser = new SerializationOutput(factory);
DeserializationInput des = new DeserializationInput(factory);
@ -136,9 +129,7 @@ public class JavaPrivatePropertyTests {
@Test
public void singlePrivateWithConstructor() throws NotSerializableException, NoSuchFieldException, IllegalAccessException {
SerializerFactory factory = new SerializerFactory(AllWhitelist.INSTANCE, ClassLoader.getSystemClassLoader(),
new EvolutionSerializerGetter(),
new SerializerFingerPrinter());
SerializerFactory factory = testDefaultFactory();
SerializationOutput ser = new SerializationOutput(factory);
DeserializationInput des = new DeserializationInput(factory);
@ -166,10 +157,7 @@ public class JavaPrivatePropertyTests {
@Test
public void singlePrivateWithConstructorAndGetter()
throws NotSerializableException, NoSuchFieldException, IllegalAccessException {
SerializerFactory factory = new SerializerFactory(AllWhitelist.INSTANCE,
ClassLoader.getSystemClassLoader(),
new EvolutionSerializerGetter(),
new SerializerFingerPrinter());
SerializerFactory factory = testDefaultFactory();
SerializationOutput ser = new SerializationOutput(factory);
DeserializationInput des = new DeserializationInput(factory);

View File

@ -1,13 +1,13 @@
package net.corda.serialization.internal.amqp;
import net.corda.core.serialization.SerializedBytes;
import net.corda.serialization.internal.amqp.testutils.TestSerializationContext;
import org.junit.Test;
import net.corda.serialization.internal.AllWhitelist;
import net.corda.core.serialization.SerializedBytes;
import java.io.NotSerializableException;
import static net.corda.serialization.internal.amqp.testutils.AMQPTestUtilsKt.testDefaultFactory;
public class JavaSerialiseEnumTests {
public enum Bras {
@ -30,10 +30,7 @@ public class JavaSerialiseEnumTests {
public void testJavaConstructorAnnotations() throws NotSerializableException {
Bra bra = new Bra(Bras.UNDERWIRE);
SerializerFactory factory1 = new SerializerFactory(AllWhitelist.INSTANCE, ClassLoader.getSystemClassLoader(),
new EvolutionSerializerGetter(),
new SerializerFingerPrinter());
SerializationOutput ser = new SerializationOutput(factory1);
SerializedBytes<Object> bytes = ser.serialize(bra, TestSerializationContext.testSerializationContext);
SerializationOutput ser = new SerializationOutput(testDefaultFactory());
ser.serialize(bra, TestSerializationContext.testSerializationContext);
}
}

View File

@ -1,7 +1,6 @@
package net.corda.serialization.internal.amqp;
import net.corda.core.serialization.ConstructorForDeserialization;
import net.corda.serialization.internal.AllWhitelist;
import net.corda.core.serialization.SerializedBytes;
import net.corda.serialization.internal.amqp.testutils.TestSerializationContext;
import org.apache.qpid.proton.codec.DecoderImpl;
@ -13,6 +12,7 @@ import java.io.NotSerializableException;
import java.nio.ByteBuffer;
import java.util.Objects;
import static net.corda.serialization.internal.amqp.testutils.AMQPTestUtilsKt.testDefaultFactory;
import static org.junit.Assert.assertTrue;
public class JavaSerializationOutputTests {
@ -176,14 +176,8 @@ public class JavaSerializationOutputTests {
}
private Object serdes(Object obj) throws NotSerializableException {
EvolutionSerializerGetterBase evolutionSerialiserGetter = new EvolutionSerializerGetter();
FingerPrinter fingerPrinter = new SerializerFingerPrinter();
SerializerFactory factory1 = new SerializerFactory(AllWhitelist.INSTANCE, ClassLoader.getSystemClassLoader(),
evolutionSerialiserGetter,
fingerPrinter);
SerializerFactory factory2 = new SerializerFactory(AllWhitelist.INSTANCE, ClassLoader.getSystemClassLoader(),
evolutionSerialiserGetter,
fingerPrinter);
SerializerFactory factory1 = testDefaultFactory();
SerializerFactory factory2 = testDefaultFactory();
SerializationOutput ser = new SerializationOutput(factory1);
SerializedBytes<Object> bytes = ser.serialize(obj, TestSerializationContext.testSerializationContext);

View File

@ -2,7 +2,6 @@ package net.corda.serialization.internal.amqp;
import net.corda.core.serialization.CordaSerializable;
import net.corda.core.serialization.SerializedBytes;
import net.corda.serialization.internal.AllWhitelist;
import net.corda.serialization.internal.amqp.testutils.TestSerializationContext;
import org.junit.Assert;
import org.junit.Test;
@ -10,6 +9,8 @@ import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import static net.corda.serialization.internal.amqp.testutils.AMQPTestUtilsKt.testDefaultFactory;
public class ListsSerializationJavaTest {
@CordaSerializable
@ -126,12 +127,7 @@ public class ListsSerializationJavaTest {
// 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 {
EvolutionSerializerGetterBase evolutionSerializerGetter = new EvolutionSerializerGetter();
FingerPrinter fingerPrinter = new SerializerFingerPrinter();
SerializerFactory factory1 = new SerializerFactory(
AllWhitelist.INSTANCE, ClassLoader.getSystemClassLoader(),
evolutionSerializerGetter,
fingerPrinter);
SerializerFactory factory1 = testDefaultFactory();
SerializationOutput ser = new SerializationOutput(factory1);
SerializedBytes<Object> bytes = ser.serialize(container, TestSerializationContext.testSerializationContext);
DeserializationInput des = new DeserializationInput(factory1);

View File

@ -1,16 +1,17 @@
package net.corda.serialization.internal.amqp;
import net.corda.core.serialization.SerializedBytes;
import net.corda.serialization.internal.AllWhitelist;
import net.corda.serialization.internal.amqp.testutils.TestSerializationContext;
import org.assertj.core.api.Assertions;
import org.junit.Test;
import static org.junit.Assert.*;
import java.io.NotSerializableException;
import java.util.ArrayList;
import java.util.List;
import static net.corda.serialization.internal.amqp.testutils.AMQPTestUtilsKt.testDefaultFactory;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.junit.Assert.assertEquals;
public class SetterConstructorTests {
static class C {
@ -119,13 +120,7 @@ public class SetterConstructorTests {
// despite having no constructor we should still be able to serialise an instance of C
@Test
public void serialiseC() throws NotSerializableException {
EvolutionSerializerGetterBase evolutionSerialiserGetter = new EvolutionSerializerGetter();
FingerPrinter fingerPrinter = new SerializerFingerPrinter();
SerializerFactory factory1 = new SerializerFactory(
AllWhitelist.INSTANCE,
ClassLoader.getSystemClassLoader(),
evolutionSerialiserGetter,
fingerPrinter);
SerializerFactory factory1 = testDefaultFactory();
SerializationOutput ser = new SerializationOutput(factory1);
@ -195,13 +190,7 @@ public class SetterConstructorTests {
@Test
public void deserialiseC() throws NotSerializableException {
EvolutionSerializerGetterBase evolutionSerialiserGetter = new EvolutionSerializerGetter();
FingerPrinter fingerPrinter = new SerializerFingerPrinter();
SerializerFactory factory1 = new SerializerFactory(
AllWhitelist.INSTANCE,
ClassLoader.getSystemClassLoader(),
evolutionSerialiserGetter,
fingerPrinter);
SerializerFactory factory1 = testDefaultFactory();
C cPre1 = new C();
@ -268,13 +257,7 @@ public class SetterConstructorTests {
@Test
public void serialiseOuterAndInner() throws NotSerializableException {
EvolutionSerializerGetterBase evolutionSerialiserGetter = new EvolutionSerializerGetter();
FingerPrinter fingerPrinter = new SerializerFingerPrinter();
SerializerFactory factory1 = new SerializerFactory(
AllWhitelist.INSTANCE,
ClassLoader.getSystemClassLoader(),
evolutionSerialiserGetter,
fingerPrinter);
SerializerFactory factory1 = testDefaultFactory();
Inner1 i1 = new Inner1("Hello");
Inner2 i2 = new Inner2();
@ -298,38 +281,26 @@ public class SetterConstructorTests {
@Test
public void typeMistmatch() {
EvolutionSerializerGetterBase evolutionSerialiserGetter = new EvolutionSerializerGetter();
FingerPrinter fingerPrinter = new SerializerFingerPrinter();
SerializerFactory factory1 = new SerializerFactory(
AllWhitelist.INSTANCE,
ClassLoader.getSystemClassLoader(),
evolutionSerialiserGetter,
fingerPrinter);
SerializerFactory factory1 = testDefaultFactory();
TypeMismatch tm = new TypeMismatch();
tm.setA(10);
assertEquals("10", tm.getA());
Assertions.assertThatThrownBy(() -> new SerializationOutput(factory1).serialize(tm,
assertThatThrownBy(() -> new SerializationOutput(factory1).serialize(tm,
TestSerializationContext.testSerializationContext)).isInstanceOf (
NotSerializableException.class);
}
@Test
public void typeMistmatch2() {
EvolutionSerializerGetterBase evolutionSerialiserGetter = new EvolutionSerializerGetter();
FingerPrinter fingerPrinter = new SerializerFingerPrinter();
SerializerFactory factory1 = new SerializerFactory(
AllWhitelist.INSTANCE,
ClassLoader.getSystemClassLoader(),
evolutionSerialiserGetter,
fingerPrinter);
SerializerFactory factory1 = testDefaultFactory();
TypeMismatch2 tm = new TypeMismatch2();
tm.setA("10");
assertEquals((Integer)10, tm.getA());
Assertions.assertThatThrownBy(() -> new SerializationOutput(factory1).serialize(tm,
assertThatThrownBy(() -> new SerializationOutput(factory1).serialize(tm,
TestSerializationContext.testSerializationContext)).isInstanceOf(
NotSerializableException.class);
}
@ -346,13 +317,7 @@ public class SetterConstructorTests {
cil.setL(l);
EvolutionSerializerGetterBase evolutionSerialiserGetter = new EvolutionSerializerGetter();
FingerPrinter fingerPrinter = new SerializerFingerPrinter();
SerializerFactory factory1 = new SerializerFactory(
AllWhitelist.INSTANCE,
ClassLoader.getSystemClassLoader(),
evolutionSerialiserGetter,
fingerPrinter);
SerializerFactory factory1 = testDefaultFactory();
// if we've got super / sub types on the setter vs the underlying type the wrong way around this will
// explode. See CORDA-1229 (https://r3-cev.atlassian.net/browse/CORDA-1229)

View File

@ -1,11 +1,8 @@
package net.corda.serialization.internal.amqp
import net.corda.serialization.internal.AllWhitelist
import net.corda.serialization.internal.amqp.testutils.*
import net.corda.serialization.internal.carpenter.*
import net.corda.serialization.internal.amqp.testutils.TestSerializationOutput
import net.corda.serialization.internal.amqp.testutils.deserialize
import net.corda.serialization.internal.amqp.testutils.serialize
import net.corda.serialization.internal.amqp.testutils.testDefaultFactoryNoEvolution
import org.junit.Test
import kotlin.test.*

View File

@ -1,15 +1,13 @@
package net.corda.serialization.internal.amqp
import net.corda.core.serialization.CordaSerializable
import net.corda.serialization.internal.carpenter.*
import net.corda.serialization.internal.AllWhitelist
import net.corda.serialization.internal.amqp.testutils.TestSerializationOutput
import net.corda.serialization.internal.amqp.testutils.testDefaultFactoryNoEvolution
import net.corda.serialization.internal.amqp.testutils.testDefaultFactoryWithWhitelist
import net.corda.serialization.internal.amqp.testutils.serialize
import net.corda.serialization.internal.amqp.testutils.deserialize
import net.corda.serialization.internal.amqp.testutils.*
import net.corda.serialization.internal.carpenter.*
import org.junit.Test
import kotlin.test.*
import kotlin.test.assertEquals
import kotlin.test.assertNotEquals
import kotlin.test.assertTrue
@CordaSerializable
interface I {

View File

@ -46,8 +46,8 @@ class FingerPrinterTestingTests {
val factory = SerializerFactory(
AllWhitelist,
ClassLoader.getSystemClassLoader(),
EvolutionSerializerGetterTesting(),
FingerPrinterTesting())
evolutionSerializerGetter = EvolutionSerializerGetterTesting(),
fingerPrinter = FingerPrinterTesting())
val blob = TestSerializationOutput(VERBOSE, factory).serializeAndReturnSchema(C(1, 2L))

View File

@ -7,13 +7,7 @@ import com.nhaarman.mockito_kotlin.whenever
import net.corda.client.rpc.RPCException
import net.corda.core.CordaException
import net.corda.core.CordaRuntimeException
import net.corda.core.contracts.Amount
import net.corda.core.contracts.Contract
import net.corda.core.contracts.ContractAttachment
import net.corda.core.contracts.ContractState
import net.corda.core.contracts.PrivacySalt
import net.corda.core.contracts.StateRef
import net.corda.core.contracts.TransactionState
import net.corda.core.contracts.*
import net.corda.core.crypto.Crypto
import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.secureRandomBytes
@ -22,48 +16,25 @@ import net.corda.core.identity.AbstractParty
import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.AbstractAttachment
import net.corda.core.internal.x500Name
import net.corda.core.serialization.ConstructorForDeserialization
import net.corda.core.serialization.CordaSerializable
import net.corda.core.serialization.EncodingWhitelist
import net.corda.core.serialization.MissingAttachmentsException
import net.corda.core.serialization.SerializationContext
import net.corda.core.serialization.SerializationFactory
import net.corda.core.serialization.*
import net.corda.core.transactions.LedgerTransaction
import net.corda.core.utilities.OpaqueBytes
import net.corda.node.serialization.amqp.AMQPServerSerializationScheme
import net.corda.nodeapi.internal.DEV_INTERMEDIATE_CA
import net.corda.nodeapi.internal.crypto.ContentSignerBuilder
import net.corda.serialization.internal.AllWhitelist
import net.corda.serialization.internal.CordaSerializationEncoding
import net.corda.serialization.internal.EmptyWhitelist
import net.corda.serialization.internal.GeneratedAttachment
import net.corda.serialization.internal.*
import net.corda.serialization.internal.amqp.SerializerFactory.Companion.isPrimitive
import net.corda.serialization.internal.amqp.testutils.deserialize
import net.corda.serialization.internal.amqp.testutils.serialize
import net.corda.serialization.internal.amqp.testutils.testDefaultFactory
import net.corda.serialization.internal.amqp.testutils.testDefaultFactoryNoEvolution
import net.corda.serialization.internal.amqp.testutils.testSerializationContext
import net.corda.serialization.internal.encodingNotPermittedFormat
import net.corda.serialization.internal.amqp.testutils.*
import net.corda.testing.contracts.DummyContract
import net.corda.testing.core.BOB_NAME
import net.corda.testing.core.SerializationEnvironmentRule
import net.corda.testing.core.TestIdentity
import net.corda.testing.internal.rigorousMock
import org.apache.activemq.artemis.api.core.SimpleString
import org.apache.qpid.proton.amqp.Decimal128
import org.apache.qpid.proton.amqp.Decimal32
import org.apache.qpid.proton.amqp.Decimal64
import org.apache.qpid.proton.amqp.Symbol
import org.apache.qpid.proton.amqp.UnsignedByte
import org.apache.qpid.proton.amqp.UnsignedInteger
import org.apache.qpid.proton.amqp.UnsignedLong
import org.apache.qpid.proton.amqp.UnsignedShort
import org.apache.qpid.proton.amqp.*
import org.apache.qpid.proton.codec.DecoderImpl
import org.apache.qpid.proton.codec.EncoderImpl
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatExceptionOfType
import org.assertj.core.api.Assertions.assertThatThrownBy
import org.assertj.core.api.Assertions.catchThrowable
import org.assertj.core.api.Assertions.*
import org.bouncycastle.cert.X509v2CRLBuilder
import org.bouncycastle.cert.jcajce.JcaX509CRLConverter
import org.bouncycastle.jce.provider.BouncyCastleProvider
@ -79,20 +50,7 @@ import java.io.NotSerializableException
import java.math.BigDecimal
import java.math.BigInteger
import java.security.cert.X509CRL
import java.time.DayOfWeek
import java.time.Duration
import java.time.Instant
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.LocalTime
import java.time.Month
import java.time.MonthDay
import java.time.OffsetDateTime
import java.time.OffsetTime
import java.time.Period
import java.time.Year
import java.time.YearMonth
import java.time.ZonedDateTime
import java.time.*
import java.time.temporal.ChronoUnit
import java.util.*
import kotlin.reflect.full.superclasses
@ -249,9 +207,13 @@ class SerializationOutputTests(private val compression: CordaSerializationEncodi
if (compression != null) doReturn(true).whenever(it).acceptEncoding(compression)
}
private fun defaultFactory() = SerializerFactory(
AllWhitelist, ClassLoader.getSystemClassLoader(),
EvolutionSerializerGetterTesting())
private fun defaultFactory(): SerializerFactory {
return SerializerFactory(
AllWhitelist,
ClassLoader.getSystemClassLoader(),
evolutionSerializerGetter = EvolutionSerializerGetterTesting()
)
}
private inline fun <reified T : Any> serdes(obj: T,
factory: SerializerFactory = defaultFactory(),

View File

@ -1,16 +1,25 @@
package net.corda.serialization.internal.amqp.testutils
import net.corda.core.internal.copyTo
import net.corda.core.internal.div
import net.corda.core.internal.packageName
import net.corda.core.serialization.SerializationContext
import net.corda.core.serialization.SerializedBytes
import org.apache.qpid.proton.codec.Data
import net.corda.core.utilities.OpaqueBytes
import net.corda.serialization.internal.AllWhitelist
import net.corda.serialization.internal.EmptyWhitelist
import net.corda.serialization.internal.amqp.*
import net.corda.testing.common.internal.ProjectStructure
import org.apache.qpid.proton.codec.Data
import org.junit.Test
import java.io.File.separatorChar
import java.io.NotSerializableException
import java.nio.file.StandardCopyOption.REPLACE_EXISTING
fun testDefaultFactory() = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader())
fun testDefaultFactoryNoEvolution() = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader(),
EvolutionSerializerGetterTesting())
fun testDefaultFactoryNoEvolution(): SerializerFactory {
return SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader(), evolutionSerializerGetter = EvolutionSerializerGetterTesting())
}
fun testDefaultFactoryWithWhitelist() = SerializerFactory(EmptyWhitelist, ClassLoader.getSystemClassLoader())
class TestSerializationOutput(
@ -41,8 +50,25 @@ class TestSerializationOutput(
}
}
fun testName(): String = Thread.currentThread().stackTrace[2].methodName
fun testName(): String {
val classLoader = Thread.currentThread().contextClassLoader
return Thread.currentThread().stackTrace.first {
try {
classLoader.loadClass(it.className).getMethod(it.methodName).isAnnotationPresent(Test::class.java)
} catch (e: Exception) {
false
}
}.methodName
}
fun Any.testResourceName(): String = "${javaClass.simpleName}.${testName()}"
fun Any.writeTestResource(bytes: OpaqueBytes) {
val dir = ProjectStructure.projectRootDir / "serialization" / "src" / "test" / "resources" / javaClass.packageName.replace('.', separatorChar)
bytes.open().copyTo(dir / testResourceName(), REPLACE_EXISTING)
}
fun Any.readTestResource(): ByteArray = javaClass.getResourceAsStream(testResourceName()).readBytes()
@Throws(NotSerializableException::class)
inline fun <reified T : Any> DeserializationInput.deserializeAndReturnEnvelope(

View File

@ -2,6 +2,7 @@ package net.corda.serialization.internal.carpenter
import net.corda.core.internal.uncheckedCast
import net.corda.serialization.internal.AllWhitelist
import org.assertj.core.api.Assertions.assertThatExceptionOfType
import org.junit.Test
import java.beans.Introspector
import java.lang.reflect.Field
@ -145,21 +146,40 @@ class ClassCarpenterTest {
assertEquals(1, i.b)
}
@Test(expected = InterfaceMismatchException::class)
fun `mismatched interface`() {
val schema1 = ClassSchema(
@Test
fun `unimplemented interface method with lenient = false`() {
val schemaA = ClassSchema(
"gen.A",
mapOf("a" to NonNullableField(String::class.java)))
val schema2 = ClassSchema(
val schemaB = ClassSchema(
"gen.B",
mapOf("c" to NonNullableField(Int::class.java)),
schema1,
schemaA,
interfaces = listOf(DummyInterface::class.java))
val clazz = cc.build(schema2)
val i = clazz.constructors[0].newInstance("xa", 1) as DummyInterface
assertEquals(1, i.b)
assertThatExceptionOfType(InterfaceMismatchException::class.java).isThrownBy { cc.build(schemaB) }
}
@Test
fun `unimplemented interface method with lenient = true`() {
val cc = ClassCarpenterImpl(whitelist = AllWhitelist, lenient = true)
val schemaA = ClassSchema(
"gen.A",
mapOf("a" to NonNullableField(String::class.java)))
val schemaB = ClassSchema(
"gen.B",
mapOf("c" to NonNullableField(Int::class.java)),
schemaA,
interfaces = listOf(DummyInterface::class.java))
val classB = cc.build(schemaB)
val b = classB.constructors[0].newInstance("xa", 1) as DummyInterface
assertEquals("xa", b.a)
assertEquals(1, classB.getMethod("getC").invoke(b))
assertThatExceptionOfType(AbstractMethodError::class.java).isThrownBy { b.b }
}
@Test

View File

@ -5,6 +5,7 @@ import net.corda.serialization.internal.amqp.*
import net.corda.serialization.internal.amqp.Field
import net.corda.serialization.internal.amqp.Schema
import net.corda.serialization.internal.amqp.testutils.serialize
import net.corda.serialization.internal.amqp.testutils.testName
fun mangleName(name: String) = "${name}__carpenter"
@ -47,7 +48,6 @@ open class AmqpCarpenterBase(whitelist: ClassWhitelist) {
var factory = SerializerFactoryExternalCarpenter(cc)
fun serialise(clazz: Any) = SerializationOutput(factory).serialize(clazz)
fun testName(): String = Thread.currentThread().stackTrace[2].methodName
@Suppress("NOTHING_TO_INLINE")
inline fun classTestName(clazz: String) = "${this.javaClass.name}\$${testName()}\$$clazz"
}

View File

@ -0,0 +1,49 @@
package net.corda.serialization.internal.carpenter
import net.corda.core.serialization.CordaSerializable
import net.corda.core.serialization.SerializationFactory
import net.corda.core.serialization.deserialize
import net.corda.serialization.internal.amqp.testutils.readTestResource
import net.corda.testing.core.SerializationEnvironmentRule
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatExceptionOfType
import org.junit.Rule
import org.junit.Test
class SerDeserCarpentryTest {
@Rule
@JvmField
val testSerialization = SerializationEnvironmentRule()
@Test
fun implementingGenericInterface() {
// Original class that was serialised
// data class GenericData(val a: Int) : GenericInterface<String>
// writeTestResource(GenericData(123).serialize())
val data = readTestResource().deserialize<GenericInterface<*>>()
assertThat(data.javaClass.getMethod("getA").invoke(data)).isEqualTo(123)
}
@Test
fun lenientCarpenter() {
// Original class that was serialised
// data class Data(val b: Int) : AInterface {
// override val a: Int get() = b
// }
// writeTestResource(Data(123).serialize())
val data = readTestResource().deserialize<AInterface>(context = SerializationFactory.defaultFactory.defaultContext.withLenientCarpenter())
assertThat(data.javaClass.getMethod("getB").invoke(data)).isEqualTo(123)
assertThatExceptionOfType(AbstractMethodError::class.java).isThrownBy { data.a }
}
@Suppress("unused")
@CordaSerializable
interface GenericInterface<T>
@CordaSerializable
interface AInterface {
val a: Int
}
}

View File

@ -7,6 +7,7 @@ import net.corda.client.jackson.JacksonSupport
import net.corda.core.internal.isRegularFile
import net.corda.core.internal.rootMessage
import net.corda.core.serialization.SerializationContext
import net.corda.core.serialization.SerializationFactory
import net.corda.core.serialization.deserialize
import net.corda.core.serialization.internal.SerializationEnvironmentImpl
import net.corda.core.serialization.internal._contextSerializationEnv
@ -33,7 +34,7 @@ fun main(args: Array<String>) {
if (main.verbose) {
throwable.printStackTrace()
} else {
System.err.println("*ERROR*: ${throwable.rootMessage ?: "Use --verbose for more details"}")
System.err.println("*ERROR*: ${throwable.rootMessage}. Use --verbose for more details")
}
exitProcess(1)
}
@ -91,7 +92,8 @@ class Main : Runnable {
}
val mapper = JacksonSupport.createNonRpcMapper(factory, fullParties)
val deserialized = bytes.deserialize<Any>()
// Deserialise with the lenient carpenter as we only care for the AMQP field getters
val deserialized = bytes.deserialize<Any>(context = SerializationFactory.defaultFactory.defaultContext.withLenientCarpenter())
println(deserialized.javaClass.name)
mapper.writeValue(System.out, deserialized)
}