Corda Serialization Whitelist - serialization

I was trying to serialized a class (DTO) to be used in send and receive
in flows.My DTO class is not in the same module as flows. I
am getting the below errors
1.With #CordaSerializable annotation , My DTO class is not getting serialized and it is throwing
java.io.NotSerializableException: Class "class com.e_mobility.dto.dashboard.DashboardDTO" is not on the whitelist or annotated with #CordaSerializable
With manual whitelisting like below
class CustomSerializationWhiteList : SerializationWhitelist {
override val whitelist: List<Class<*>> = listOf(DTO::class.java)
}
I am getting this error during runtime
net.corda.core.serialization.internal.MissingSerializerException: Unable to create an object serializer for type class com.e_mobility.dto.dashboard.DashboardDTO:
Mandatory constructor parameters [arg0, arg1, arg2, arg3, arg4, arg5, arg6] are missing from the readable properties []
Either provide getters or readable fields for [arg0, arg1, arg2, arg3, arg4, arg5, arg6], or provide a custom serializer for this type
Please help me to resolve this error. (edited)

As you are creating a custom type, did you check that all the needed requirements are fulfilled in your class? The annotation alone might be not enough. From the related Corda documentation about serialization with custom types:
The class must be compiled with parameter names included in the .class file. This is the default in Kotlin but must be turned on in
Java using the -parameters command line option to javac
The class must be annotated with #CordaSerializable
The declared types of constructor arguments, getters, and setters must be supported, and where generics are used, the generic parameter
must be a supported type, an open wildcard (*), or a bounded wildcard
which is currently widened to an open wildcard
Any superclass must adhere to the same rules, but can be abstract
Object graph cycles are not supported, so an object cannot refer to itself, directly or indirectly

Related

Why does casting to a generic work without an instance of that type?

I've created 2 kotlin methods: one to check a type and another to cast an object. They look like:
fun Any?.isOfType(type: Class<*>): Boolean{
return type.isInstance(this)
// return `this is T` does NOT work.
}
and
fun <T> Any?.castToType(): T {
return this as T
// Works, albeit with a warning.
}
I've read some posts on generics and erasures, but I can't get over what seems to be a discrepancy.
Why is it that checking for the type of an object cannot be done with generics, but casting to a generic can?
The question is why:
fun <T> Any?.castToType() = this as T // compiles with warning
"hello".castToType<Int>()
"works" but this won't even compile:
fun <T> Any?.isOfType() = this is T // won't compile
"hello".isOfType<Int>()
Actually both don't really work. In both cases the type is erased at runtime. So why does one compile and the other doesn't?
this is T cannot work at runtime since the type of T is unknown and thus the compiler has to reject it.
this as T on the other hand might work:
"hello".castToType<Int>() // no runtime error but NOP
"hello".castToType<Int>().minus(1) // throws ClassCastException
2.0.castToType<Int>().minus(1) // no runtime error, returns 1
In some cases it works, in others it throws an exception. Now every unchecked cast can either succeed or lead to runtime exceptions (with or without generic types) so it makes sense to show a warning instead of a compile error.
Summary
unchecked casts with generic types are no different from unchecked casts without generic types, they are dangerous but a warning is sufficient
type checks with generic types on the other hand are impossible at runtime
Addendum
The official documentation explains type erasure and why is-checks with type arguments can't succeed at runtime:
At runtime, the instances of generic types do not hold any information about their actual type arguments. The type information is said to be erased. For example, the instances of Foo and Foo<Baz?> are erased to just Foo<*>.
Due to the type erasure, there is no general way to check whether an instance of a generic type was created with certain type arguments at runtime, and the compiler prohibits such is-checks such as ints is List or list is T (type parameter)
(https://kotlinlang.org/docs/generics.html#type-erasure)
In my own words: I can't check whether A is B if I don't know what B is. If B is a class I can check against an instance of that class (that's why type.isInstance(this) works) but if B is a generic type, the runtime has no information on it (it was erased by the compiler).
This isn't about casting vs checking; it's about using generics vs class objects.
The second example is generic; it uses T as a type parameter. Unfortunately, because generics are implemented using type erasure, this means that the type isn't available at runtime (because it has been erased, and replaced by the relevant upper bound — Any? in this case). This is why operations such as type checking or casting to a type parameter can be unsafe and give compilation warnings.
The first example, though, doesn't use a type parameter; instead, it uses a parameter which is called type, but is a Class object, representing a particular class. This is a value which is provided at runtime, just like any other method parameter, and so you can call methods such as cast() and isInstance() to handle some type issues at runtime. However, they're closely related to reflection, and have some of the same disadvantages, such as fragility, ugly code, and limited compile-time checks.
(Kotlin code often uses KClass objects instead of Java Class objects, but the principle is the same.)
It may be worth highlighting the difference between class and type, which are related but subtly different. For example, String is both a class and a type, while String? is another type derived from the same class. LinkedList is a class, but not a type (because it needs a type parameter); LinkedList<Int> is a type.
Types can of course be derived from interfaces as well as from classes, e.g. Runnable, or MutableList<Int>.
This is relevant to the question, because generics use type parameters, while Class objects represent classes.

Kotlin: Generic types in Kotlin

To get the class definition to be used for example for json deserialization the following can be used in Kotlin:
Map::class.java
A example usage is the following:
val map = mapper.readValue(json, Map::class.java)
But now how to have the generic type definition?
Something like this does not compile:
val map = mapper.readValue(decodedString, Map<String, String>::class.java)
So my question is: What is the generic equivalent to *::class.java
Class<T> (in Java) or KClass<T> (in Kotlin) can only represent classes, not all types. If the API you're using only uses Class<T> or KClass<T>, it simply doesn't support generic types (at least in those functions).
Instead, KType (or Type in Java) is the proper type to use to represent the complete type information including generics. You could use it this way:
val myMapType: KType = typeOf<Map<String,String>>()
Unfortunately, KType doesn't have a type parameter (it's not KType<T>), and that makes it impossible to use for compile-time type checking: you can't have the equivalent of fun deserialize(Input, KClass<T>): T using KType instead of KClass, because you can't define the T for the return type by using only a KType argument.
There are several tricks to work around this:
In both Java and Kotlin, one of the ways is to get this information through inheritance by providing a generic superclass and inheriting from it.
In general, serialization APIs (especially the deserializing part) provide workarounds using this, such as Jackson's TypeReference or Gson's TypeToken. It's basically their version of Type but with a type parameter to have some compile-time type safety.
In Kotlin, there is sometimes another way depending on the situation: making use of reified type parameters. Using inline functions, the compiler can know more information at compile time about the type parameters by replacing them with the actual inferred type at the call site when inlining the function's body. This allows things like T::class in the inline function's body. This is how you can get functions like typeOf to get a KType.
Some Kotlin-specific APIs of deserialization libraries use inline functions to remove the hassle from the user, and get type information directly. This is what jackson-module-kotlin does by providing an inline readValue extension without a Class argument, which reifies the type parameter to get the target type information

What are nullable rules when calling Java from Kotlin

Why does Kotlin in one case infer type returned from Java to be nullable and in another case it is can be either, nullable or non-nullable?
I've checked both HashMap.get and JsonNode.get and I could not identify any #NotNull-like annotations neither in calsses nor anywhere in inheritance chain. What makes Kotlin treating those 2 calls differently?
I have read documentation https://kotlinlang.org/docs/java-interop.html#null-safety-and-platform-types but it explanation use "Platform Types" without explaining what those are and it does not explain differences in behavior anyway.
import com.fasterxml.jackson.databind.JsonNode
private fun docType(node: JsonNode, map: java.util.HashMap<String,String>) {
val x: JsonNode = node.get("doc_type") // DOES compile and can throw NPE at runtime
val y: JsonNode? = node.get("doc_type") // DOES compile and Kotlin's type system will force you to check for null
val z: String = map.get("a") // ERROR: Type mismatch: inferred type is String? but String was expected
}
Kotlin provides seamless interoperability with Java, without compromising its own null-safety... almost. One exception is that Kotlin assumes that all types that are defined in Java are not-null.
To understand, let's look at JsonNode.get()
Platform types
public JsonNode get(String fieldName) { return null; }
Note that JsonNode is defined in Java, and is a therefore 'platform type' - and Kotlin does not 'translate' it to JsonNode?, even though that would be technically correct (because in Java all types are nullable).
When calling Java from Kotlin, for convenience it's assumed that the platform type is non-nullable. If this wasn't the case, you would always have to check that any instance of any platform type is not null.
So, to answer your question about what a 'platform type' is, it's a term that means
some type that is defined in an external target language,
you can't mention it explicitly in Kotlin code (but there's probably a synonymous Kotlin equivalent),
and we're going to assume that it's non-nullable for convenience.
Also the notation is <type>!, for example String! - which we can take to mean String or String?
Nullability annotations
The closest Java equivalent of Kotlin's nullable ? symbol are nullability annotations, which the Kotlin compiler can parse and take into account. However, none are used on JsonNode methods. And so Kotlin will quite happily assume that node.get("") will return JsonNode, not JsonNode?.
As you noted, there are none defined for HashMap.get(...).
So how does Kotlin know that map.get("a") returns a nullable type?
Type inference
Type inference can't help. The (Java) method signature
public V get(Object key) {
//...
}
indicates that a HashMap<String, String> should return String, not String?. Something else must be going on...
Mapped types
For most Java types, Kotlin will just use the definition as provided. But for some, Kotlin decides to treat them specially, and completely replace the Java definition with its own version.
You can see the list of mapped types in the docs. And while HashMap isn't in there, Map is. And so, when we're writing Kotlin code, HashMap doesn't inherit from java.util.Map - because it's mapped to kotlin.collections.Map
Aside: in fact if you try and use java.util.Map you'll get a warning
So if we look at the code for the get function that kotlin.collections.Map defines, we can see that it returns a nullable value type
/**
* Returns the value corresponding to the given [key], or `null` if such a key is not present in the map.
*/
public operator fun get(key: K): V?
And so the Kotlin compiler can look at HashMap.get(...) and deduce that, because it's implementing kotlin.collections.Map.get(...), the returned value must be a nullable value, which in our case is String?.
Workaround: External annotations
For whatever reason, Jackson doesn't use the nullability annotations that would solve this problem. Fortunately IntelliJ provides a workaround that, while not as strict, will provide helpful warnings: external annotations.
Once I follow the instructions...
Alt+Enter → 'Annotate method...'
Select 'Nullable' annotation
Save annotations.xml
Now node.get("") will show an warning.
This annotation isn't visible to the Kotlin compiler, so it can only be a warning - not a compilation error.
java.util.HashMap.get implements the interface method java.util.Map.get. Kotlin maps some Java types to its own types internally. The full table of these mappings is available on the website. In our particular case, we see that java.util.Map gets mapped internally to kotlin.collections.Map, whose get function looks like
abstract operator fun get(key: K): V?
So as far as Kotlin is concerned, java.util.Map is just a funny name for kotlin.collections.Map, and all of the methods on java.util.Map actually have the signatures of the corresponding ones from kotlin.collections.Map (which are basically the same except with correct null annotations).
So while the first two node.get calls are Java calls and return platform types, the third one (as far as Kotlin is concerned) is actually calling a method Kotlin understands: namely, get from its own Map type. And that type has an explicit nullability annotation already available, so Kotlin can confidently say that that value can be null and needs to be checked.

How can I encode a typed class with Kotlinx Serialization?

I'd like to encode a given class of type T: EventData with Kotlinx Serialization encodeToString.
This is my code:
class EventDispatcher<T: EventData>(
val pubSubTemplate: PubSubTemplate
) {
/**
* Dispatch an event to the game engine event manager pipeline
*/
fun dispatchEvent(event: T, initiator: String) {
val eventData: String = Json.encodeToString(event)
}
The compiler tells me:
Cannot use `T` as reified type parameter. Use a class instead
Is there a way to make this still work?
For Json.encodeToString(event) to work, it needs the type information for T. But, this type information is lost at runtime due to the way how generics work in Kotlin/Java.
One way to retain the type information would be by making dispatchEvent an inline function with T as a reified type parameter.
However, this also raises the question how you want to serialize event. You could also use polymorphic serialization of EventData, rather than trying to serialize T. This will include an additional class discriminator in your serialized output (it necessarily has to for polymorphic serialization/deserialization to work).
If you serialize the concrete type T, this class discriminator wouldn't be included, which is questionable; how would whoever will deserialize this know what type it is?
In short, I think you need polymorphic serialization.

Combine JsonDeserialize#contentAs with JsonDeserialize#contentConverter or JsonDeserialize#contentUsing for custom deserialization

In JsonDeserialize annotation documentation the contentAs field is supposed to define the "Concrete type to deserialize content".
I tried to use this in combination, with either a Converter (via contentConverter field of the same annotation) or a JsonDeserializer (via contentUsing field of the same annotation), by extending either StdConverter or StdDeserializer, respectively, in an attempt to create an agnostic custom deserializer.
I cannot find a way to access the JsonDeserialize#contentAs information inside any of these two classes.
I am aware that the classes I extend from have a type parameter, I just put an Object class there. Documentation states
contentAs Concrete type to deserialize content (elements of a Collection/array, values of Maps) values as, instead of type otherwise declared. Must be a subtype of declared type; otherwise an exception may be thrown by deserializer.
Apparently I am applying the #JsonDeserializer annotation on a Collection of some persistable Class. I want to deserialize each such object, solely by knowing its id. Well, if I could only get that very type I defined in the #JsonDeserializer#contentAs field...
Can anyone tell me if this is possible anyhow?
I managed to implement the agnostic deserializer withou the use of #JsonDeserializer#contentAs after all.
After reading the javadocs of com.fasterxml.jackson.databind.JsonDeserializer I concluded that my custom deserializer should implement the com.fasterxml.jackson.databind.deser.ContextualDeserializer interface.
Inside the implementation of ContextualDeserializer#createContextual(DeserializationContext ctxt, BeanProperty property)
I could finally get access to the class type of the content of the collection, which I applied the #JsonDeserialize annotation on,
by calling:
ctxt.getContextualType().getRawClass()
NOTE that the same call inside the implementation of com.fasterxml.jackson.databind.JsonDeserializer#deserialize(com.fasterxml.jackson.core.JsonParser, com.fasterxml.jackson.databind.DeserializationContext) returned null, hence the need of the aforementioned interface.
All I had to do then is store the returned class in a member field (of type Class< ? >) of the custom deserializer and use it in the execution of JsonDeserializer#deserialize()
The only thing that remains to check is whether an instance of this custom deserializer is shared between threads. I only did some minor checks; I used the same implementation for two different collections of different types. I observed that ContextualDeserializer#createContextual(DeserializationContext ctxt, BeanProperty property) was called once (among multiple deserialization invokations), for each distinct type that was going to be deserialized. After checking during debugging, it seems that the same deserializer object is used for the same type. In my case, since what I store in the member field is this type itself, I don't mind if the same deserializer is used for the same java type to be deserialized because they should contain the same value. So we 're clear on this aspect as well.
EDIT: It appears all I have to do is update the com.fasterxml.jackson.databind.deser.std.StdDeserializer#_valueClass value to the now known class. Since it is final and since the ContextualDeserializer#createContextual(DeserializationContext ctxt, BeanProperty property) returns a JsonSerializer object, which is actually used,
instead of returning "this" serializer I can create a new one, passing the discovered class in the constructor, which actually sets the StdDeserializer#_valueClass to the class I actually want, and I'm all set!
Finally, NOTE that I didn't have to use the #JsonDeserializer#contentAs annotationfield as I get the value from the ctxt.getContextualType().getRawClass() statement inside ContextualDeserializer#createContextual(DeserializationContext ctxt, BeanProperty property) implementation