quarkus
quarkus copied to clipboard
Can't use other dataformat of Jackson like xml for Jackson Rest Client
Describe the bug
We can't use another data format of Jackson than xml, csv, yaml ... with a Jackson Rest client. We can only deserialize Json format.
Jackson proposes multiple data format to serialize/deserialize. It could be interresting to use them with Quarkus.
Quarkus proposes to customize ObjectMapper using @ClientObjectMapper but we can't create a XmlMapper which extends ObjectMapper and use for deserializing HTTP response with media type "application/xml"
I try documentation:
When the quarkus-rest-client-jackson extension is installed, Quarkus will use the application/json media type by default for most return values, unless the media type is explicitly set via @Produces or @Consumes annotations.
If you don’t rely on the JSON default, it is heavily recommended to annotate your endpoints with the @Produces and @Consumes annotations to define precisely the expected content-types. It will allow to narrow down the number of Jakarta REST providers (which can be seen as converters) included in the native executable.
But no effect.
Expected behavior
You must let Jackson to deserialize HTTP response using the custom ObjectMapper defined with @ClientObjectMapper. The Jackson rest client can consumes another media type like "application/xml" "application/csv" or "application/yaml", ...
Actual behavior
We have an error:
Error when we process XML: jakarta.ws.rs.ProcessingException: Response could not be mapped to type class MyXmlObject for response with media type application/xml. Hints: Consider adding the 'quarkus-rest-client-reactive-jaxb' extension
at org.jboss.resteasy.reactive.client.impl.ClientReaderInterceptorContextImpl.proceed(ClientReaderInterceptorContextImpl.java:132)
at org.jboss.resteasy.reactive.client.impl.ClientSerialisers.invokeClientReader(ClientSerialisers.java:160)
at org.jboss.resteasy.reactive.client.impl.RestClientRequestContext.readEntity(RestClientRequestContext.java:209)
at org.jboss.resteasy.reactive.client.handlers.ClientResponseCompleteRestHandler.mapToResponse(ClientResponseCompleteRestHandler.java:105)
at org.jboss.resteasy.reactive.client.handlers.ClientResponseCompleteRestHandler.handle(ClientResponseCompleteRestHandler.java:35)
at org.jboss.resteasy.reactive.client.handlers.ClientResponseCompleteRestHandler.handle(ClientResponseCompleteRestHandler.java:31)
at org.jboss.resteasy.reactive.common.core.AbstractResteasyReactiveContext.invokeHandler(AbstractResteasyReactiveContext.java:231)
at org.jboss.resteasy.reactive.common.core.AbstractResteasyReactiveContext.run(AbstractResteasyReactiveContext.java:147)
How to Reproduce?
quarkus extension add quarkus-rest-client-jackson- Add to pom :
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
- Create a rest client
package com.client;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import io.quarkus.rest.client.reactive.jackson.ClientObjectMapper;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES;
@Path("/api")
@RegisterRestClient(configKey = "my-api")
public interface CustomRestClient {
@ClientObjectMapper
static ObjectMapper getXmlMapper() {
return XmlMapper.builder()
.configure(FAIL_ON_UNKNOWN_PROPERTIES, false)
.build();
}
@GET
@Consumes("application/xml")
MyXmlObject get();
}
Output of uname -a or ver
Linux L-5CD3476MQP 5.15.153.1-microsoft-standard-WSL2 #1 SMP Fri Mar 29 23:14:13 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux
Output of java -version
openjdk version "17.0.10" 2024-01-16 OpenJDK Runtime Environment Temurin-17.0.10+7 (build 17.0.10+7) OpenJDK 64-Bit Server VM Temurin-17.0.10+7 (build 17.0.10+7, mixed mode, sharing)
Quarkus version or git rev
3.12.0
Build tool (ie. output of mvnw --version or gradlew --version)
Apache Maven 3.9.6 (bc0240f3c744dd6b6ec2920b3cd08dcc295161ae) Maven home: /home/xxx/.m2/wrapper/dists/apache-maven-3.9.6-bin/e68bf935/apache-maven-3.9.6 Java version: 17.0.10, vendor: Eclipse Adoptium, runtime: /home/xxx/.jbang/cache/jdks/17 Default locale: en, platform encoding: UTF-8 OS name: "linux", version: "5.15.153.1-microsoft-standard-wsl2", arch: "amd64", family: "unix"
Additional information
No response
/cc @cescoffier (rest-client), @geoand (jackson,rest-client), @gsmet (jackson), @maxandersen (jbang), @quarkusio/devtools (jbang)
As far as i know Quarkus supports only JAX-B for XML serialisation/deserialisation.
Maybe you could write your own MessageBodyWriter / MessageBodyReader (https://quarkus.io/guides/rest#readers-and-writers-mapping-entities-and-http-bodies). I know it works for Quarkus-REST, for the REST-Client i am not sure.
Yes, it's for rest service not for client.
In fact I find a workaround
package com.client;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import io.quarkus.rest.client.reactive.jackson.ClientObjectMapper;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import java.io.IOException;
import java.io.InputStream;
import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES;
@Path("/api")
@RegisterRestClient(configKey = "my-api")
public interface CustomRestClient {
@GET
@Consumes("application/xml")
InputStream get();
default MyXmlObject get2() throws IOException {
final ObjectMapper mapper = XmlMapper.builder()
.configure(FAIL_ON_UNKNOWN_PROPERTIES, false)
.build();
return mapper.readValue(get(), MyXmlObject.class);
}
}
In my case I need only one call, so I can create mapper directly in get 2.
I use extension quarkus-rest-client not quarkus-rest-client-jackson.
But I think it's a bug. Normally we should use extension quarkus-rest-client-jackson and configure the ObjectMapper like we want. It seems there are some restrictions on media type. But Jackson can serialize and deserialize multiple data format
Thanks for reporting this.
I'll say right off the bat, that I do not consider this a bug. The quarkus-rest-client-jackson extension is only meant to handle json (one could argue that the name could be better, but that's not going to change).
It is absolutely possible to use other formats, but you need to handle add your own MessageBodyReader and MessageBodyWriter implementations.
It's a shame to limit this lib to the json format, given that Jackson manages several of them. If it's not a bug, it could be an enhancement or a name change of lib.
Thanks for the feedback.
it could be an enhancement or a name change of lib.
Right, we should consider this