Upcasters for JSON and XML

Hi folks,

I changed my events and I’m building the upcasters. Since the library I’m building is used with different serializers, I’m proud to write two upcasters for XML and JSON. My question is how can I determine what to use… The docs says:

To achieve the best performance, ensure that all upcasters in the same chain (where one’s output is another’s input) work on the same content type.

So I ended up in detecting the representation content type from the IntermediateEventRepresentation inside my canUpcast method. Is there any trick how to do this best?

My current approach (as Kotlin extension function) is:

fun IntermediateEventRepresentation.contentType(): RepresentationContentType {
  if (this.data.data is Document) {
    return RepresentationContentType.XML
  } else if (this.data.data is String) {
    return RepresentationContentType.JSON
  throw IllegalStateException("Unknown content type of ${this.data.data}")

In addition, my local installation where this library is used without Axon Server uses XStream and JPA-Based Event store. The events are stored in a domain_event_entry in a blob (varchar(max)) field and I get it’s content as a bytearray (which is converted to string the XML representation).

As far as I understood, I have to define a ContentTypeConverter from ByteArray to Document then right? It is loaded via service loader, so an META-INF/services/org.axonframework.serialization.ContentTypeConverter must contain a FQCN of the converter class?

That’s an interesting use case. I do see some challenges with the implementation above.
The actual format in which the data is delivered depends on the results of the previous upcaster in the chain, or on the format in which it is stored.
If there would be an XML based serializer, and an upcaster that returns its result as a String, this implementation would falsely assume that the format is JSON.

To detect this properly, I think there is a method missing that would allow you to “ask” whether the type of data can be converted to a specific type. In that case, you could ask the intermediateRepresentation whether it canConvertDataTo(Document.class) or otherwise canConvertDataTo(JsonNode.class).

Alternatively (or even additionally), exposing the Serializer from the IntermediateRepresentation could provide a few hooks for potential use cases in the future.

I think this would be great addition to have in the framework. Would you be up to create an issue for this in GitHub? Or maybe even a PR? :slight_smile:

1 Like

Hi Allard,

I think the canConvert method is a good idea, but I see troubles with exposing the serializer. As far as I understand, the serializer is used only in order to read the data from the storage and thus only exists in the InitialEventRepresentation, the UpcastedEventRepresentation uses converters only, so the only thing we could build is a call from intermediate representation to the previous, resulting in a chain of calls down to the InitialEventRepresentation and that would return the initial Serializer.

Do you mean it like I described it or am I missing something?

I’ll create an issue in Github and the PR for it.



Hi Simon,

the serializer is available at every stage of the upcasting process, but right now it isn’t explicitly passed to the UpcastedEventRepresentation because that implementation didn’t need it. It could indeed get it from the source.
But thinking a bit more about the pros and cons of exposing it, I think I come to the same conclusion: it’s problematic. The goal of the serializer is to convert binary data into object structure and vice versa. During upcasting, there is no such thing as conversion into “object structure” yet, as the binary structure (or a slightly different representation thereof) still needs to take shape.

So let’s stick with exposing the canConvert method on the IntermediateEventRepresentation class.

In time you were away and I was not reading the forum, I created the issue here:

and a PR fixing it:

I provide both methods, since I believe the getSerializer() method does no harm but is indeed useful for further scenarios.

It is up to your technical expertise to decide if it should be a part of the framework, just give me some feedback on the PR and I’ll remove it.



1 Like