ResponseTypes.multipleInstancesOf() type mismatch

I have a simple rest endpoint that looks like:

    @GetMapping("/products/admin")
    fun getProductsAdmin(
        @RequestParam(required = false) state: ProductState = ProductState.PENDING)
    : CompletableFuture<List<ProductAdminView>> {
        return queryGateway.query(GetProducts(state),
            ResponseTypes.multipleInstancesOf(ProductAdminView::class.java))
    }

The query handler looks like:

  @QueryHandler
    fun handle(query: GetProducts): List<ProductAdminView> {
        return productRepository.findByState(query.state)
            .map { productDocument ->
                ProductAdminView(
                    id = productDocument.id,
                    name = productDocument.name,
                    description = productDocument.description,
                    price = productDocument.price,
                    inStock = productDocument.inStock,
                    imageUrl = productDocument.imageUrl,
                    state = productDocument.state
                )
            }
    }

This unfortunately results in an exception:

java.lang.IllegalArgumentException: Retrieved response [class java.util.ArrayList] is not convertible to a List of the expected response type [class dev.fidil.monostore.product.ProductAdminView]
	at org.axonframework.messaging.responsetypes.MultipleInstancesResponseType.convert(MultipleInstancesResponseType.java:180) ~[axon-messaging-4.9.2.jar:4.9.2]
	at org.axonframework.messaging.responsetypes.MultipleInstancesResponseType.convert(MultipleInstancesResponseType.java:47) ~[axon-messaging-4.9.2.jar:4.9.2]
	at org.axonframework.messaging.responsetypes.ConvertingResponseMessage.getPayload(ConvertingResponseMessage.java:102) ~[axon-messaging-4.9.2.jar:4.9.2]
	at org.axonframework.queryhandling.DefaultQueryGateway.lambda$query$2(DefaultQueryGateway.java:97) ~[axon-messaging-4.9.2.jar:4.9.2]
	at java.base/java.util.concurrent.CompletableFuture$UniAccept.tryFire(CompletableFuture.java:718) ~[na:na]
	at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:510) ~[na:na]
	at java.base/java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:2147) ~[na:na]
	at org.axonframework.axonserver.connector.query.AxonServerQueryBus$ResponseProcessingTask.lambda$run$0(AxonServerQueryBus.java:905) ~[axon-server-connector-4.9.2.jar:4.9.2]
	at org.axonframework.tracing.Span.run(Span.java:101) ~[axon-messaging-4.9.2.jar:4.9.2]
	at org.axonframework.axonserver.connector.query.AxonServerQueryBus$ResponseProcessingTask.run(AxonServerQueryBus.java:904) ~[axon-server-connector-4.9.2.jar:4.9.2]
	at org.axonframework.axonserver.connector.PriorityRunnable.run(PriorityRunnable.java:58) ~[axon-server-connector-4.9.2.jar:4.9.2]
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) ~[na:na]
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) ~[na:na]
	at java.base/java.lang.Thread.run(Thread.java:833) ~[na:na]

I feel like I’m missing something simple but I cannot see it. It seems like the query handler might be wrapping an extra list around its response somehow. Any help much appreciated.

I am using Axon Framework 4.9.3 with mongodb as read store.

Assuming you use use Jackson for serialisation the query messages and responses, you need something like:

@Bean
@Primary
fun serializer(objectMapper: ObjectMapper): Serializer {
    return JacksonSerializer.builder()
            .objectMapper(objectMapper.copy())
            .defaultTyping()
            .lenientDeserialization()
            .build()
}

For the primary serializer used. Jackson will not add typing info by default, and therefore, it can’t deserialize the elements of the list.

Thanks for the reply!

Adding the suggested serializer bean produces an exception:

Caused by: com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `org.axonframework.eventhandling.tokenstore.ConfigToken` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('org.axonframework.eventhandling.tokenstore.ConfigToken')
 at [Source: (byte[])"["org.axonframework.eventhandling.tokenstore.ConfigToken",{"config":["java.util.Collections$SingletonMap",{"id":"acdb5308-8814-41e7-b850-6b5957cc9222"}]}]"; line: 1, column: 2]
	at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:63) ~[jackson-databind-2.15.4.jar:2.15.4]
	at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1739) ~[jackson-databind-2.15.4.jar:2.15.4]
	at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1364) ~[jackson-databind-2.15.4.jar:2.15.4]
	at com.fasterxml.jackson.databind.deser.std.StdDeserializer._deserializeFromString(StdDeserializer.java:311) ~[jackson-databind-2.15.4.jar:2.15.4]
	at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromString(BeanDeserializerBase.java:1514) ~[jackson-databind-2.15.4.jar:2.15.4]
	at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeOther(BeanDeserializer.java:197) ~[jackson-databind-2.15.4.jar:2.15.4]
	at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:187) ~[jackson-databind-2.15.4.jar:2.15.4]
	at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeFromArray(BeanDeserializer.java:647) ~[jackson-databind-2.15.4.jar:2.15.4]
	at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeOther(BeanDeserializer.java:211) ~[jackson-databind-2.15.4.jar:2.15.4]
	at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:187) ~[jackson-databind-2.15.4.jar:2.15.4]
	at com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:323) ~[jackson-databind-2.15.4.jar:2.15.4]
	at com.fasterxml.jackson.databind.ObjectReader._bindAndClose(ObjectReader.java:2105) ~[jackson-databind-2.15.4.jar:2.15.4]
	at com.fasterxml.jackson.databind.ObjectReader.readValue(ObjectReader.java:1583) ~[jackson-databind-2.15.4.jar:2.15.4]
	at org.axonframework.serialization.json.JacksonSerializer.deserialize(JacksonSerializer.java:205) ~[axon-messaging-4.9.3.jar:4.9.3]
	... 50 common frames omitted

Did you maybe make changes to the Mongo Token store configuration? It seems like the token was stored with a serializer with default typing, but now default typing is disabled.

I didn’t make any changes to the mongo token store, but it definitely didn’t like the new jackson configuration until I deleted the mongo token store. It worked great once I did. Thanks again!

1 Like