This is an automated email from the ASF dual-hosted git repository.
reta pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cxf.git
The following commit(s) were added to refs/heads/main by this push:
new 8d52cc9a8a Add ContextResolver support on the JAX-RS client side
(#2132)
8d52cc9a8a is described below
commit 8d52cc9a8a8d0547c076c5becb33dd34285c0ff4
Author: Andriy Redko <[email protected]>
AuthorDate: Fri Nov 1 09:59:04 2024 -0400
Add ContextResolver support on the JAX-RS client side (#2132)
---
.../cxf/jaxrs/client/ClientProviderFactory.java | 12 ++
.../systest/jaxrs/JAXRS31ClientServerBookTest.java | 172 +++++++++++++++++++++
2 files changed, 184 insertions(+)
diff --git
a/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/ClientProviderFactory.java
b/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/ClientProviderFactory.java
index 7c03a414b9..ae3cf81ae9 100644
---
a/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/ClientProviderFactory.java
+++
b/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/ClientProviderFactory.java
@@ -27,6 +27,7 @@ import jakarta.ws.rs.client.ClientRequestFilter;
import jakarta.ws.rs.client.ClientResponseFilter;
import jakarta.ws.rs.client.RxInvokerProvider;
import jakarta.ws.rs.core.Configuration;
+import jakarta.ws.rs.ext.ContextResolver;
import org.apache.cxf.Bus;
import org.apache.cxf.BusFactory;
import org.apache.cxf.common.util.ClassHelper;
@@ -42,6 +43,8 @@ public final class ClientProviderFactory extends
ProviderFactory {
new ArrayList<>(1);
private List<ProviderInfo<ResponseExceptionMapper<?>>>
responseExceptionMappers =
new ArrayList<>(1);
+ private List<ProviderInfo<ContextResolver<?>>> contextResolvers =
+ new ArrayList<>();
private RxInvokerProvider<?> rxInvokerProvider;
private ClientProviderFactory(Bus bus) {
super(bus);
@@ -98,6 +101,10 @@ public final class ClientProviderFactory extends
ProviderFactory {
if (RxInvokerProvider.class.isAssignableFrom(providerCls)) {
this.rxInvokerProvider =
RxInvokerProvider.class.cast(provider.getProvider());
}
+
+ if (filterContractSupported(provider, providerCls,
ContextResolver.class)) {
+ addProviderToList(contextResolvers, provider);
+ }
}
Collections.sort(clientRequestFilters,
new
BindingPriorityComparator(ClientRequestFilter.class, true));
@@ -125,6 +132,7 @@ public final class ClientProviderFactory extends
ProviderFactory {
responseExceptionMappers.clear();
clientRequestFilters.clear();
clientResponseFilters.clear();
+ contextResolvers.clear();
}
public List<ProviderInfo<ClientRequestFilter>> getClientRequestFilters() {
@@ -135,6 +143,10 @@ public final class ClientProviderFactory extends
ProviderFactory {
return Collections.unmodifiableList(clientResponseFilters);
}
+ public List<ProviderInfo<ContextResolver<?>>> getContextResolvers() {
+ return Collections.unmodifiableList(contextResolvers);
+ }
+
@Override
public Configuration getConfiguration(Message m) {
return (Configuration)m.getExchange().getOutMessage()
diff --git
a/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRS31ClientServerBookTest.java
b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRS31ClientServerBookTest.java
new file mode 100644
index 0000000000..bf1d6aefcd
--- /dev/null
+++
b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRS31ClientServerBookTest.java
@@ -0,0 +1,172 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.cxf.systest.jaxrs;
+
+import java.lang.reflect.Type;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.concurrent.ThreadLocalRandom;
+
+import jakarta.json.bind.Jsonb;
+import jakarta.json.bind.JsonbBuilder;
+import jakarta.json.bind.JsonbConfig;
+import jakarta.json.bind.serializer.DeserializationContext;
+import jakarta.json.bind.serializer.JsonbDeserializer;
+import jakarta.json.bind.serializer.JsonbSerializer;
+import jakarta.json.bind.serializer.SerializationContext;
+import jakarta.json.stream.JsonGenerator;
+import jakarta.json.stream.JsonParser;
+import jakarta.ws.rs.Consumes;
+import jakarta.ws.rs.POST;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.RuntimeType;
+import jakarta.ws.rs.client.Client;
+import jakarta.ws.rs.client.ClientBuilder;
+import jakarta.ws.rs.client.Entity;
+import jakarta.ws.rs.core.UriBuilder;
+import jakarta.ws.rs.ext.ContextResolver;
+import org.apache.cxf.Bus;
+import org.apache.cxf.endpoint.Server;
+import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
+import org.apache.cxf.jaxrs.provider.jsrjsonb.JsrJsonbProvider;
+import org.apache.cxf.testutil.common.AbstractBusClientServerTestBase;
+import org.apache.cxf.testutil.common.AbstractServerTestServerBase;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import static jakarta.ws.rs.RuntimeType.CLIENT;
+import static jakarta.ws.rs.RuntimeType.SERVER;
+import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON;
+import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON_TYPE;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertTrue;
+
+public class JAXRS31ClientServerBookTest extends
AbstractBusClientServerTestBase {
+ public static final String PORT = BookServer31.PORT;
+
+ @BeforeClass
+ public static void startServers() throws Exception {
+ assertTrue("server did not launch correctly",
launchServer(BookServer31.class, true));
+ }
+
+ @Test
+ public final void shouldUseApplicationProvidedJsonbInstance() throws
URISyntaxException {
+ final String origin = String.format("Origin(%d)",
ThreadLocalRandom.current().nextInt(1000));
+ try (Client client = ClientBuilder
+ .newBuilder()
+ .register(new JsrJsonbProvider())
+ .register(new CustomJsonbProvider(CLIENT))
+ .build()) {
+
+ final Book book = new Book();
+ book.setName(origin);
+
+ final URI effectiveUri = UriBuilder
+ .fromUri("http://localhost:" + PORT + "/")
+ .path("bookstore")
+ .build();
+
+ final Book response = client
+ .target(effectiveUri)
+ .request(APPLICATION_JSON_TYPE)
+ .buildPost(Entity.entity(book, APPLICATION_JSON_TYPE))
+ .invoke(Book.class);
+
+ final String expectedWaypoints = String.join(",", origin,
+ "CustomSerializer(CLIENT)",
+ "CustomDeserializer(SERVER)",
+ "BookResource",
+ "CustomSerializer(SERVER)",
+ "CustomDeserializer(CLIENT)");
+
+ assertThat(response.getName(), is(expectedWaypoints));
+ }
+ }
+
+ public static final class BookServer31 extends
AbstractServerTestServerBase {
+ public static final String PORT = allocatePort(BookServer31.class);
+
+ @Override
+ protected Server createServer(Bus bus) throws Exception {
+ JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
+ sf.setResourceClasses(BookStoreResource.class);
+ sf.setProvider(new JsrJsonbProvider());
+ sf.setProvider(new CustomJsonbProvider(SERVER));
+ sf.setAddress("http://localhost:" + PORT + "/");
+ return sf.create();
+ }
+
+ public static void main(String[] args) throws Exception {
+ new BookServer31().start();
+ }
+ }
+
+ @Path("/bookstore")
+ public static class BookStoreResource {
+ @POST
+ @Consumes(APPLICATION_JSON)
+ @Produces(APPLICATION_JSON)
+ public Book echo(final Book book) {
+ book.setName(String.join(",", book.getName(), "BookResource"));
+ return book;
+ }
+ }
+
+ public static final class CustomJsonbProvider implements
ContextResolver<Jsonb> {
+ private final RuntimeType runtimeType;
+
+ private CustomJsonbProvider(final RuntimeType runtimeType) {
+ this.runtimeType = runtimeType;
+ }
+
+ public Jsonb getContext(final Class<?> type) {
+ if (!Book.class.isAssignableFrom(type)) {
+ return null;
+ }
+
+ return JsonbBuilder.create(new JsonbConfig()
+ .withSerializers(new CustomSerializer())
+ .withDeserializers(new CustomDeserializer()));
+ }
+
+ private final class CustomSerializer implements JsonbSerializer<Book> {
+ @Override
+ public void serialize(final Book book, final JsonGenerator
generator, final SerializationContext ctx) {
+ generator.writeStartObject();
+ generator.write("name",
String.format("%s,CustomSerializer(%s)", book.getName(),
+ CustomJsonbProvider.this.runtimeType));
+ generator.writeEnd();
+ }
+ }
+
+ private final class CustomDeserializer implements
JsonbDeserializer<Book> {
+ @Override
+ public Book deserialize(final JsonParser parser, final
DeserializationContext ctx, final Type rtType) {
+ final Book book = new Book();
+ book.setName(String.format("%s,CustomDeserializer(%s)",
parser.getObject().getString("name"),
+ CustomJsonbProvider.this.runtimeType));
+ return book;
+ }
+ }
+ }
+}