This is an automated email from the ASF dual-hosted git repository.
reta pushed a commit to branch 3.6.x-fixes
in repository https://gitbox.apache.org/repos/asf/cxf.git
The following commit(s) were added to refs/heads/3.6.x-fixes by this push:
new 82c2443e55e CXF-9211: [JAX-RS proxy clients] Use template URL instead
of actual path values for JAX-RS micrometer metrics (#3100)
82c2443e55e is described below
commit 82c2443e55e2ec9117313b45e5f427a1a9583ab6
Author: Andriy Redko <[email protected]>
AuthorDate: Tue May 12 22:40:53 2026 -0400
CXF-9211: [JAX-RS proxy clients] Use template URL instead of actual path
values for JAX-RS micrometer metrics (#3100)
(cherry picked from commit 99b0a407dc85f754de45185b5a2ab25d527ac277)
---
.../org/apache/cxf/jaxrs/utils/JAXRSUtils.java | 19 +++++++++-
.../apache/cxf/jaxrs/client/ClientProxyImpl.java | 2 +
.../spring/boot/SpringJaxrsApplicationTest.java | 44 +++++++++++++++++++++-
.../systest/jaxrs/spring/boot/SpringJaxrsTest.java | 2 +-
4 files changed, 63 insertions(+), 4 deletions(-)
diff --git
a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/JAXRSUtils.java
b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/JAXRSUtils.java
index f9075db21ca..3307d54b332 100644
--- a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/JAXRSUtils.java
+++ b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/JAXRSUtils.java
@@ -47,6 +47,7 @@ import java.util.TreeMap;
import java.util.function.Supplier;
import java.util.logging.Level;
import java.util.logging.Logger;
+import java.util.regex.Pattern;
import java.util.stream.Collectors;
import javax.ws.rs.ClientErrorException;
@@ -204,6 +205,7 @@ public final class JAXRSUtils {
"java.util.concurrent.CompletionStage"
));
private static final LazyLoadedClass DATA_SOURCE_CLASS = new
LazyLoadedClass("javax.activation.DataSource");
+ private static final Pattern URI_SCHEME =
Pattern.compile("^([a-zA-Z]{2,20}):\\/\\/", Pattern.CASE_INSENSITIVE);
// Class to lazily call the ClassLoaderUtil.loadClass, but do it once
// and cache the result. Then use the class to create instances as needed.
@@ -2101,14 +2103,27 @@ public final class JAXRSUtils {
String template = basePath;
if (StringUtils.isEmpty(template)) {
template = "/";
- } else if (!template.startsWith("/")) {
+ } else if (!template.startsWith("/") && !hasScheme(template)) {
template = "/" + template;
}
template = combineUriTemplates(template, classPathTemplate);
return combineUriTemplates(template, methodPathTemplate);
}
-
+
+ /**
+ * Checks if the URI string is absolute with the scheme
+ * @param uriStr URI string
+ * @return "true" if the URI string is absolute with the scheme, "false"
otherwise
+ */
+ private static boolean hasScheme(String uriStr) {
+ if (uriStr == null) {
+ return false;
+ } else {
+ return URI_SCHEME.matcher(uriStr).find();
+ }
+ }
+
/**
* Gets the URI template of the operation from its resource info
* to assemble final URI template
diff --git
a/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/ClientProxyImpl.java
b/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/ClientProxyImpl.java
index db7c84ecc3c..22dcdc4d494 100644
---
a/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/ClientProxyImpl.java
+++
b/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/ClientProxyImpl.java
@@ -89,6 +89,7 @@ import org.apache.cxf.jaxrs.model.ClassResourceInfo;
import org.apache.cxf.jaxrs.model.OperationResourceInfo;
import org.apache.cxf.jaxrs.model.Parameter;
import org.apache.cxf.jaxrs.model.ParameterType;
+import org.apache.cxf.jaxrs.model.URITemplate;
import org.apache.cxf.jaxrs.utils.AnnotationUtils;
import org.apache.cxf.jaxrs.utils.FormUtils;
import org.apache.cxf.jaxrs.utils.InjectionUtils;
@@ -920,6 +921,7 @@ public class ClientProxyImpl extends AbstractClient
implements
outMessage.put(PROXY_METHOD_PARAM_BODY_INDEX, bodyIndex);
}
outMessage.getInterceptorChain().add(bodyWriter);
+ outMessage.put(URITemplate.URI_TEMPLATE,
JAXRSUtils.getUriTemplate(outMessage, cri, ori));
Map<String, Object> reqContext = getRequestContext(outMessage);
reqContext.put(OperationResourceInfo.class.getName(), ori);
diff --git
a/systests/spring-boot/src/test/java/org/apache/cxf/systest/jaxrs/spring/boot/SpringJaxrsApplicationTest.java
b/systests/spring-boot/src/test/java/org/apache/cxf/systest/jaxrs/spring/boot/SpringJaxrsApplicationTest.java
index b5e2c185373..65630920975 100644
---
a/systests/spring-boot/src/test/java/org/apache/cxf/systest/jaxrs/spring/boot/SpringJaxrsApplicationTest.java
+++
b/systests/spring-boot/src/test/java/org/apache/cxf/systest/jaxrs/spring/boot/SpringJaxrsApplicationTest.java
@@ -21,6 +21,7 @@ package org.apache.cxf.systest.jaxrs.spring.boot;
import java.time.Duration;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Map;
import javax.ws.rs.InternalServerErrorException;
@@ -420,7 +421,7 @@ public class SpringJaxrsApplicationTest {
entry("exception", "None"),
entry("method", "GET"),
entry("operation", "getBook"),
- entry("uri", "http://localhost:" + port +
"/api/app/library/100"),
+ entry("uri", "http://localhost:" + port +
"/api/app/library/{id}"),
entry("outcome", "CLIENT_ERROR"),
entry("status", "404"));
}
@@ -453,10 +454,51 @@ public class SpringJaxrsApplicationTest {
entry("status", "UNKNOWN"));
}
+ @Test
+ public void testJaxrsProxySubresourceSuccessMetric() {
+ final LibraryApi api = createApi(port);
+
+ final Collection<Book> books = api.catalog().getCatalog("cxf");
+ assertThat(books).hasSize(1);
+
+ await()
+ .atMost(Duration.ofSeconds(1))
+ .ignoreException(MeterNotFoundException.class)
+ .until(() -> registry.get("cxf.server.requests").timers(),
not(empty()));
+ RequiredSearch serverRequestMetrics =
registry.get("cxf.server.requests");
+
+ Map<Object, Object> serverTags =
serverRequestMetrics.timer().getId().getTags().stream()
+ .collect(toMap(Tag::getKey, Tag::getValue));
+
+ assertThat(serverTags)
+ .containsOnly(
+ entry("exception", "None"),
+ entry("method", "GET"),
+ entry("operation", "catalog"),
+ entry("uri", "/api/app/library/catalog/{catalog}"),
+ entry("outcome", "SUCCESS"),
+ entry("status", "200"));
+
+ RequiredSearch clientRequestMetrics =
registry.get("cxf.client.requests");
+
+ Map<Object, Object> clientTags =
clientRequestMetrics.timer().getId().getTags().stream()
+ .collect(toMap(Tag::getKey, Tag::getValue));
+
+ assertThat(clientTags)
+ .containsOnly(
+ entry("exception", "None"),
+ entry("method", "GET"),
+ entry("operation", "getCatalog"),
+ entry("uri", "http://localhost:" + port +
"/api/app/library/catalog/{catalog}"),
+ entry("outcome", "SUCCESS"),
+ entry("status", "200"));
+ }
+
private LibraryApi createApi(int portToUse) {
final JAXRSClientFactoryBean factory = new JAXRSClientFactoryBean();
factory.setAddress("http://localhost:" + portToUse +
"/api/app/library");
factory.setFeatures(Arrays.asList(new
MetricsFeature(metricsProvider)));
+ factory.setProvider(new JacksonJsonProvider());
factory.setResourceClass(LibraryApi.class);
return factory.create(LibraryApi.class);
}
diff --git
a/systests/spring-boot/src/test/java/org/apache/cxf/systest/jaxrs/spring/boot/SpringJaxrsTest.java
b/systests/spring-boot/src/test/java/org/apache/cxf/systest/jaxrs/spring/boot/SpringJaxrsTest.java
index e32f6bc0f9b..81fc27c14fd 100644
---
a/systests/spring-boot/src/test/java/org/apache/cxf/systest/jaxrs/spring/boot/SpringJaxrsTest.java
+++
b/systests/spring-boot/src/test/java/org/apache/cxf/systest/jaxrs/spring/boot/SpringJaxrsTest.java
@@ -390,7 +390,7 @@ public class SpringJaxrsTest {
entry("exception", "None"),
entry("method", "GET"),
entry("operation", "getBook"),
- entry("uri", "http://localhost:" + port + "/api/library/100"),
+ entry("uri", "http://localhost:" + port + "/api/library/{id}"),
entry("outcome", "CLIENT_ERROR"),
entry("status", "404"));
}