diff --git a/bom/application/pom.xml b/bom/application/pom.xml
index 3c37f3131f632..d699b3a03fe18 100644
--- a/bom/application/pom.xml
+++ b/bom/application/pom.xml
@@ -54,7 +54,7 @@
4.0.4
4.0.0
3.7.0
- 2.6.0
+ 2.6.1
6.2.6
4.4.0
2.1.0
@@ -84,7 +84,7 @@
4.0.1
4.0.4
9.6
- 2.15.0
+ 2.15.1
16.0.0.Final
3.0-alpha-2
2.1.0
@@ -136,7 +136,7 @@
1.2.6
5.3.2
2.2
- 5.10.0
+ 5.10.1
1.5.0
14.0.21.Final
4.6.5.Final
@@ -146,7 +146,7 @@
1.0.4
3.5.3.Final
2.5.1
- 3.6.0
+ 3.6.1
1.8.0
1.1.10.5
0.100.0
@@ -160,7 +160,7 @@
1.9.21
1.7.3
0.27.0
- 1.6.0
+ 1.6.2
4.0.3
3.2.0
4.2.0
@@ -188,7 +188,7 @@
5.8.0
4.10.1
2.0.2.Final
- 22.0.5
+ 23.0.0
1.15.1
3.38.0
2.22.0
@@ -197,10 +197,10 @@
2.1
4.7.5
1.1.0
- 1.24.0
+ 1.25.0
1.11.0
2.10.1
- 1.1.1.Final
+ 1.1.2.Final
2.20.0
1.3.0.Final
1.11.3
@@ -2207,6 +2207,11 @@
quarkus-funqy-amazon-lambda
${project.version}
+
+ io.quarkus
+ quarkus-funqy-amazon-lambda-deployment
+ ${project.version}
+
io.quarkus
quarkus-funqy-google-cloud-functions
diff --git a/build-parent/pom.xml b/build-parent/pom.xml
index 14eeb01c05c7a..ae8c28c5ea334 100644
--- a/build-parent/pom.xml
+++ b/build-parent/pom.xml
@@ -101,7 +101,7 @@
- 22.0.5
+ 23.0.0
19.0.3
quay.io/keycloak/keycloak:${keycloak.version}
quay.io/keycloak/keycloak:${keycloak.wildfly.version}-legacy
diff --git a/core/runtime/src/main/java/io/quarkus/runtime/configuration/ConfigDiagnostic.java b/core/runtime/src/main/java/io/quarkus/runtime/configuration/ConfigDiagnostic.java
index 6a28d740a1713..41d698b81a3d1 100644
--- a/core/runtime/src/main/java/io/quarkus/runtime/configuration/ConfigDiagnostic.java
+++ b/core/runtime/src/main/java/io/quarkus/runtime/configuration/ConfigDiagnostic.java
@@ -184,7 +184,7 @@ public static Set configFiles(Path configFilesLocation) throws IOExcepti
Set configFiles = new HashSet<>();
try (DirectoryStream candidates = Files.newDirectoryStream(configFilesLocation, CONFIG_FILES_FILTER)) {
for (Path candidate : candidates) {
- configFiles.add(candidate.toString());
+ configFiles.add(candidate.toUri().getPath());
}
}
return configFiles;
diff --git a/devtools/cli/src/main/java/io/quarkus/cli/ProjectExtensionsAdd.java b/devtools/cli/src/main/java/io/quarkus/cli/ProjectExtensionsAdd.java
index 3b1266ecdae52..4d3e1572d771c 100644
--- a/devtools/cli/src/main/java/io/quarkus/cli/ProjectExtensionsAdd.java
+++ b/devtools/cli/src/main/java/io/quarkus/cli/ProjectExtensionsAdd.java
@@ -17,7 +17,7 @@ public class ProjectExtensionsAdd extends BaseBuildCommand implements Callable extensions;
@Override
diff --git a/devtools/cli/src/main/java/io/quarkus/cli/ProjectExtensionsRemove.java b/devtools/cli/src/main/java/io/quarkus/cli/ProjectExtensionsRemove.java
index adf82223bccfc..2affcc921bf42 100644
--- a/devtools/cli/src/main/java/io/quarkus/cli/ProjectExtensionsRemove.java
+++ b/devtools/cli/src/main/java/io/quarkus/cli/ProjectExtensionsRemove.java
@@ -17,7 +17,7 @@ public class ProjectExtensionsRemove extends BaseBuildCommand implements Callabl
@CommandLine.Mixin
RunModeOption runMode;
- @CommandLine.Parameters(arity = "1", paramLabel = "EXTENSION", description = "Extension(s) to remove from this project.")
+ @CommandLine.Parameters(arity = "1", paramLabel = "EXTENSION", description = "Extension(s) to remove from this project.", split = ",")
Set extensions;
@Override
diff --git a/devtools/cli/src/test/java/io/quarkus/cli/CliDriver.java b/devtools/cli/src/test/java/io/quarkus/cli/CliDriver.java
index 6bbbc63a26463..60af7b5aabb94 100644
--- a/devtools/cli/src/test/java/io/quarkus/cli/CliDriver.java
+++ b/devtools/cli/src/test/java/io/quarkus/cli/CliDriver.java
@@ -319,7 +319,7 @@ public static Result invokeExtensionRemoveQute(Path projectRoot, Path file) thro
}
public static Result invokeExtensionAddMultiple(Path projectRoot, Path file) throws Exception {
- // add the qute extension
+ // add amazon-lambda-http and jackson extensions
Result result = execute(projectRoot, "extension", "add", "amazon-lambda-http", "jackson", "-e", "-B", "--verbose");
Assertions.assertEquals(CommandLine.ExitCode.OK, result.exitCode,
"Expected OK return code. Result:\n" + result);
@@ -345,7 +345,7 @@ public static Result invokeExtensionAddMultiple(Path projectRoot, Path file) thr
}
public static Result invokeExtensionRemoveMultiple(Path projectRoot, Path file) throws Exception {
- // add the qute extension
+ // remove amazon-lambda-http and jackson extensions
Result result = execute(projectRoot, "extension", "remove", "amazon-lambda-http", "jackson", "-e", "-B", "--verbose");
Assertions.assertEquals(CommandLine.ExitCode.OK, result.exitCode,
"Expected OK return code. Result:\n" + result);
@@ -370,6 +370,52 @@ public static Result invokeExtensionRemoveMultiple(Path projectRoot, Path file)
return result;
}
+ public static Result invokeExtensionAddMultipleCommas(Path projectRoot, Path file) throws Exception {
+ Result result = execute(projectRoot, "extension", "add",
+ "quarkus-resteasy-reactive-jsonb,quarkus-resteasy-reactive-jackson", "-e", "-B", "--verbose");
+ Assertions.assertEquals(CommandLine.ExitCode.OK, result.exitCode,
+ "Expected OK return code. Result:\n" + result);
+
+ result = invokeValidateExtensionList(projectRoot);
+ Assertions.assertTrue(result.stdout.contains("quarkus-qute"),
+ "Expected quarkus-qute to be in the list of extensions. Result:\n" + result);
+ Assertions.assertTrue(result.stdout.contains("quarkus-resteasy-reactive-jsonb"),
+ "Expected quarkus-resteasy-reactive-jsonb to be in the list of extensions. Result:\n" + result);
+ Assertions.assertTrue(result.stdout.contains("quarkus-resteasy-reactive-jackson"),
+ "Expected quarkus-resteasy-reactive-jackson to be in the list of extensions. Result:\n" + result);
+
+ String content = CliDriver.readFileAsString(file);
+ Assertions.assertTrue(content.contains("quarkus-qute"),
+ "quarkus-qute should still be listed as a dependency. Result:\n" + content);
+ Assertions.assertTrue(content.contains("quarkus-resteasy-reactive-jsonb"),
+ "quarkus-resteasy-reactive-jsonb should be listed as a dependency. Result:\n" + content);
+ Assertions.assertTrue(content.contains("quarkus-resteasy-reactive-jackson"),
+ "quarkus-resteasy-reactive-jackson should be listed as a dependency. Result:\n" + content);
+
+ return result;
+ }
+
+ public static Result invokeExtensionRemoveMultipleCommas(Path projectRoot, Path file) throws Exception {
+ Result result = execute(projectRoot, "extension", "remove",
+ "quarkus-resteasy-reactive-jsonb,quarkus-resteasy-reactive-jackson", "-e", "-B", "--verbose");
+ Assertions.assertEquals(CommandLine.ExitCode.OK, result.exitCode,
+ "Expected OK return code. Result:\n" + result);
+
+ result = invokeValidateExtensionList(projectRoot);
+ Assertions.assertFalse(result.stdout.contains("quarkus-resteasy-reactive-jsonb"),
+ "quarkus-resteasy-reactive-jsonb should not be in the list of extensions. Result:\n" + result);
+ Assertions.assertFalse(result.stdout.contains("quarkus-resteasy-reactive-jackson"),
+ "quarkus-resteasy-reactive-jackson should not be in the list of extensions. Result:\n" + result);
+
+ String content = CliDriver.readFileAsString(file);
+ Assertions.assertFalse(content.contains("quarkus-resteasy-reactive-jsonb"),
+ "quarkus-resteasy-reactive-jsonb should not be listed as a dependency. Result:\n" + content);
+ Assertions.assertFalse(content.contains("quarkus-resteasy-reactive-jackson"),
+ "quarkus-resteasy-reactive-jackson should not be listed as a dependency. Result:\n" + content);
+
+ return result;
+ }
+
public static Result invokeExtensionListInstallable(Path projectRoot) throws Exception {
Result result = CliDriver.execute(projectRoot, "extension", "list", "-e", "-B", "--verbose", "-i");
Assertions.assertEquals(CommandLine.ExitCode.OK, result.exitCode,
diff --git a/devtools/cli/src/test/java/io/quarkus/cli/CliProjectMavenTest.java b/devtools/cli/src/test/java/io/quarkus/cli/CliProjectMavenTest.java
index d8782c4f1b0d2..4653a21a73723 100644
--- a/devtools/cli/src/test/java/io/quarkus/cli/CliProjectMavenTest.java
+++ b/devtools/cli/src/test/java/io/quarkus/cli/CliProjectMavenTest.java
@@ -145,8 +145,10 @@ public void testExtensionList() throws Exception {
CliDriver.invokeExtensionAddRedundantQute(project);
CliDriver.invokeExtensionListInstallable(project);
CliDriver.invokeExtensionAddMultiple(project, pom);
+ CliDriver.invokeExtensionAddMultipleCommas(project, pom);
CliDriver.invokeExtensionRemoveQute(project, pom);
CliDriver.invokeExtensionRemoveMultiple(project, pom);
+ CliDriver.invokeExtensionRemoveMultipleCommas(project, pom);
CliDriver.invokeExtensionListInstallableSearch(project);
CliDriver.invokeExtensionListFormatting(project);
diff --git a/docs/src/main/asciidoc/kafka.adoc b/docs/src/main/asciidoc/kafka.adoc
index 819d70d996dbe..b559acfa4d85d 100644
--- a/docs/src/main/asciidoc/kafka.adoc
+++ b/docs/src/main/asciidoc/kafka.adoc
@@ -1952,10 +1952,8 @@ mp.messaging.outgoing.fruit-out.compression.type=snappy
----
In JVM mode, it will work out of the box.
-However, to compile your application to a native executable, you need to:
-
-1. Uses GraalVM 21.+
-2. Add `quarkus.kafka.snappy.enabled=true` to your `application.properties`
+However, to compile your application to a native executable, you need to
+add `quarkus.kafka.snappy.enabled=true` to your `application.properties`.
In native mode, Snappy is disabled by default as the use of Snappy requires embedding a native library and unpacking it when the application starts.
diff --git a/docs/src/main/asciidoc/logging.adoc b/docs/src/main/asciidoc/logging.adoc
index a9329d517f4b1..81afed44a01c7 100644
--- a/docs/src/main/asciidoc/logging.adoc
+++ b/docs/src/main/asciidoc/logging.adoc
@@ -841,4 +841,5 @@ NOTE: If applicable, MDC data is stored in a _duplicated context_, which is an i
[[loggingConfigurationReference]]
== Logging configuration reference
+include::{generated-dir}/config/quarkus-log-logging-log-build-time-config.adoc[opts=optional, leveloffset=+1]
include::{generated-dir}/config/quarkus-log-logging-log-config.adoc[opts=optional, leveloffset=+1]
diff --git a/docs/src/main/asciidoc/native-reference.adoc b/docs/src/main/asciidoc/native-reference.adoc
index 5aaf0176fef95..4880f74a2051b 100644
--- a/docs/src/main/asciidoc/native-reference.adoc
+++ b/docs/src/main/asciidoc/native-reference.adoc
@@ -846,8 +846,8 @@ we need the following cypher script which will import the data within the CSV fi
[source,cypher]
----
-CREATE CONSTRAINT unique_vm_id ON (v:VM) ASSERT v.vmId IS UNIQUE;
-CREATE CONSTRAINT unique_method_id ON (m:Method) ASSERT m.methodId IS UNIQUE;
+CREATE CONSTRAINT unique_vm_id FOR (v:VM) REQUIRE v.vmId IS UNIQUE;
+CREATE CONSTRAINT unique_method_id FOR (m:Method) REQUIRE m.methodId IS UNIQUE;
LOAD CSV WITH HEADERS FROM 'file:///reports/call_tree_vm.csv' AS row
MERGE (v:VM {vmId: row.Id, name: row.Name})
diff --git a/docs/src/main/asciidoc/rest-client-reactive.adoc b/docs/src/main/asciidoc/rest-client-reactive.adoc
index b3c063bccdda2..1fea2b5a03736 100644
--- a/docs/src/main/asciidoc/rest-client-reactive.adoc
+++ b/docs/src/main/asciidoc/rest-client-reactive.adoc
@@ -974,7 +974,7 @@ public interface SseClient {
Multi> get();
- class HeartbeatFilter implements Predicate> {
+ class HeartbeatFilter implements Predicate> {
@Override
public boolean test(SseEvent event) {
diff --git a/docs/src/main/asciidoc/security-openid-connect-dev-services.adoc b/docs/src/main/asciidoc/security-openid-connect-dev-services.adoc
index ee38209a69427..0d99374a5b348 100644
--- a/docs/src/main/asciidoc/security-openid-connect-dev-services.adoc
+++ b/docs/src/main/asciidoc/security-openid-connect-dev-services.adoc
@@ -225,7 +225,7 @@ For more information, see xref:security-oidc-bearer-token-authentication.adoc#in
[[keycloak-initialization]]
=== Keycloak Initialization
-The `quay.io/keycloak/keycloak:22.0.5` image which contains a Keycloak distribution powered by Quarkus is used to start a container by default.
+The `quay.io/keycloak/keycloak:23.0.0` image which contains a Keycloak distribution powered by Quarkus is used to start a container by default.
`quarkus.keycloak.devservices.image-name` can be used to change the Keycloak image name. For example, set it to `quay.io/keycloak/keycloak:19.0.3-legacy` to use a Keycloak distribution powered by WildFly.
Note that only a Quarkus based Keycloak distribution is available starting from Keycloak `20.0.0`.
diff --git a/docs/sync-web-site.sh b/docs/sync-web-site.sh
index 353e45c2c58e0..6f310b98c61dd 100755
--- a/docs/sync-web-site.sh
+++ b/docs/sync-web-site.sh
@@ -32,6 +32,7 @@ fi
if [ -z $TARGET_DIR ]; then
TARGET_DIR=target/web-site
+ rm -rf ${TARGET_DIR}
GIT_OPTIONS=""
if [[ "$QUARKUS_WEB_SITE_PUSH" != "true" ]]; then
GIT_OPTIONS="--depth=1"
diff --git a/extensions/elasticsearch-rest-client-common/deployment/src/main/java/io/quarkus/elasticsearch/restclient/common/deployment/DevServicesElasticsearchProcessor.java b/extensions/elasticsearch-rest-client-common/deployment/src/main/java/io/quarkus/elasticsearch/restclient/common/deployment/DevServicesElasticsearchProcessor.java
index 065acd241b0c0..e36b279d99b4a 100644
--- a/extensions/elasticsearch-rest-client-common/deployment/src/main/java/io/quarkus/elasticsearch/restclient/common/deployment/DevServicesElasticsearchProcessor.java
+++ b/extensions/elasticsearch-rest-client-common/deployment/src/main/java/io/quarkus/elasticsearch/restclient/common/deployment/DevServicesElasticsearchProcessor.java
@@ -220,7 +220,7 @@ private DevServicesResultBuildItem.RunningDevService startElasticsearch(
container.withLabel(DEV_SERVICE_LABEL, config.serviceName);
}
if (config.port.isPresent()) {
- container.setPortBindings(List.of(config.port.get() + ":" + config.port.get()));
+ container.setPortBindings(List.of(config.port.get() + ":" + ELASTICSEARCH_PORT));
}
timeout.ifPresent(container::withStartupTimeout);
diff --git a/extensions/elasticsearch-rest-client/deployment/src/test/java/io/quarkus/elasticsearch/restclient/lowlevel/runtime/DevServicesElasticsearchDevModeCustomPortTestCase.java b/extensions/elasticsearch-rest-client/deployment/src/test/java/io/quarkus/elasticsearch/restclient/lowlevel/runtime/DevServicesElasticsearchDevModeCustomPortTestCase.java
new file mode 100644
index 0000000000000..2f9a9e39a3ec9
--- /dev/null
+++ b/extensions/elasticsearch-rest-client/deployment/src/test/java/io/quarkus/elasticsearch/restclient/lowlevel/runtime/DevServicesElasticsearchDevModeCustomPortTestCase.java
@@ -0,0 +1,45 @@
+package io.quarkus.elasticsearch.restclient.lowlevel.runtime;
+
+import static org.hamcrest.Matchers.endsWith;
+import static org.hamcrest.Matchers.equalTo;
+
+import org.jboss.shrinkwrap.api.asset.StringAsset;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import io.quarkus.test.QuarkusDevModeTest;
+import io.restassured.RestAssured;
+
+public class DevServicesElasticsearchDevModeCustomPortTestCase {
+ @RegisterExtension
+ static QuarkusDevModeTest test = new QuarkusDevModeTest()
+ .withApplicationRoot((jar) -> jar
+ .addClass(TestResource.class)
+ .addAsResource(new StringAsset("quarkus.elasticsearch.devservices.port=19200"), "application.properties"));
+
+ @Test
+ public void checkConfiguredPort() {
+ RestAssured
+ .when().get("/fruits/configured-hosts")
+ .then().body(endsWith(":19200"));
+
+ }
+
+ @Test
+ public void testDatasource() throws Exception {
+ var fruit = new TestResource.Fruit();
+ fruit.id = "1";
+ fruit.name = "banana";
+ fruit.color = "yellow";
+
+ RestAssured
+ .given().body(fruit).contentType("application/json")
+ .when().post("/fruits")
+ .then().statusCode(204);
+
+ RestAssured.when().get("/fruits/search?term=color&match=yellow")
+ .then()
+ .statusCode(200)
+ .body(equalTo("[{\"id\":\"1\",\"name\":\"banana\",\"color\":\"yellow\"}]"));
+ }
+}
diff --git a/extensions/elasticsearch-rest-client/deployment/src/test/java/io/quarkus/elasticsearch/restclient/lowlevel/runtime/TestResource.java b/extensions/elasticsearch-rest-client/deployment/src/test/java/io/quarkus/elasticsearch/restclient/lowlevel/runtime/TestResource.java
index 5a10c4ebb8d67..4ab00a0f385d7 100644
--- a/extensions/elasticsearch-rest-client/deployment/src/test/java/io/quarkus/elasticsearch/restclient/lowlevel/runtime/TestResource.java
+++ b/extensions/elasticsearch-rest-client/deployment/src/test/java/io/quarkus/elasticsearch/restclient/lowlevel/runtime/TestResource.java
@@ -11,6 +11,7 @@
import jakarta.ws.rs.QueryParam;
import org.apache.http.util.EntityUtils;
+import org.eclipse.microprofile.config.ConfigProvider;
import org.elasticsearch.client.Request;
import org.elasticsearch.client.Response;
import org.elasticsearch.client.RestClient;
@@ -57,6 +58,12 @@ public List search(@QueryParam("term") String term, @QueryParam("match")
return results;
}
+ @GET
+ @Path("/configured-hosts")
+ public String configuredHosts() {
+ return ConfigProvider.getConfig().getConfigValue("quarkus.elasticsearch.hosts").getValue();
+ }
+
public static class Fruit {
public String id;
public String name;
diff --git a/extensions/hibernate-reactive/deployment/src/test/java/io/quarkus/hibernate/reactive/mapping/id/optimizer/optimizer/IdOptimizerDefaultNoneTest.java b/extensions/hibernate-reactive/deployment/src/test/java/io/quarkus/hibernate/reactive/mapping/id/optimizer/optimizer/IdOptimizerDefaultNoneTest.java
index 2ff9f955a727c..fcc9da07c9937 100644
--- a/extensions/hibernate-reactive/deployment/src/test/java/io/quarkus/hibernate/reactive/mapping/id/optimizer/optimizer/IdOptimizerDefaultNoneTest.java
+++ b/extensions/hibernate-reactive/deployment/src/test/java/io/quarkus/hibernate/reactive/mapping/id/optimizer/optimizer/IdOptimizerDefaultNoneTest.java
@@ -2,6 +2,7 @@
import org.hibernate.id.enhanced.NoopOptimizer;
import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import io.quarkus.hibernate.reactive.SchemaUtil;
@@ -22,6 +23,7 @@ public class IdOptimizerDefaultNoneTest extends AbstractIdOptimizerDefaultTest {
.overrideConfigKey("quarkus.hibernate-orm.mapping.id.optimizer.default", "none");
@Override
+ @Test
@Disabled("The 'none' optimizer will produce a different stream of IDs (1 then 51 then 101 then ...)")
public void ids(UniAsserter asserter) {
super.ids(asserter);
diff --git a/extensions/micrometer/runtime/src/main/java/io/quarkus/micrometer/runtime/binder/mpmetrics/MetricRegistryAdapter.java b/extensions/micrometer/runtime/src/main/java/io/quarkus/micrometer/runtime/binder/mpmetrics/MetricRegistryAdapter.java
index be354011e3b89..4bffa61ee7830 100644
--- a/extensions/micrometer/runtime/src/main/java/io/quarkus/micrometer/runtime/binder/mpmetrics/MetricRegistryAdapter.java
+++ b/extensions/micrometer/runtime/src/main/java/io/quarkus/micrometer/runtime/binder/mpmetrics/MetricRegistryAdapter.java
@@ -90,13 +90,13 @@ public Counter counter(Metadata metadata, Tag... tags) {
Counter interceptorCounter(Metadata metadata, String... tags) {
return internalCounter(internalGetMetadata(metadata, MetricType.COUNTER),
- new MetricDescriptor(metadata.getName(), tags));
+ new MetricDescriptor(metadata.getName(), scopeTags(tags)));
}
Counter injectedCounter(org.eclipse.microprofile.metrics.annotation.Metric annotation) {
return internalCounter(
internalGetMetadata(annotation.name(), MetricType.COUNTER).merge(annotation),
- new MetricDescriptor(annotation.name(), annotation.tags()));
+ new MetricDescriptor(annotation.name(), scopeTags(annotation.tags())));
}
CounterAdapter internalCounter(MpMetadata metadata, MetricDescriptor id) {
@@ -138,13 +138,13 @@ public ConcurrentGauge concurrentGauge(Metadata metadata, Tag... tags) {
ConcurrentGaugeImpl interceptorConcurrentGauge(Metadata metadata, String... tags) {
return internalConcurrentGauge(internalGetMetadata(metadata, MetricType.CONCURRENT_GAUGE),
- new MetricDescriptor(metadata.getName(), tags));
+ new MetricDescriptor(metadata.getName(), scopeTags(tags)));
}
ConcurrentGaugeImpl injectedConcurrentGauge(org.eclipse.microprofile.metrics.annotation.Metric annotation) {
return internalConcurrentGauge(
internalGetMetadata(annotation.name(), MetricType.CONCURRENT_GAUGE).merge(annotation),
- new MetricDescriptor(annotation.name(), annotation.tags()));
+ new MetricDescriptor(annotation.name(), scopeTags(annotation.tags())));
}
ConcurrentGaugeImpl internalConcurrentGauge(MpMetadata metadata, MetricDescriptor id) {
@@ -276,7 +276,7 @@ public Histogram histogram(Metadata metadata, Tag... tags) {
HistogramAdapter injectedHistogram(org.eclipse.microprofile.metrics.annotation.Metric annotation) {
return internalHistogram(
internalGetMetadata(annotation.name(), MetricType.HISTOGRAM).merge(annotation),
- new MetricDescriptor(annotation.name(), annotation.tags()));
+ new MetricDescriptor(annotation.name(), scopeTags(annotation.tags())));
}
HistogramAdapter internalHistogram(MpMetadata metadata, MetricDescriptor id) {
@@ -319,7 +319,7 @@ public Meter meter(Metadata metadata, Tag... tags) {
MeterAdapter injectedMeter(org.eclipse.microprofile.metrics.annotation.Metric annotation) {
return internalMeter(
internalGetMetadata(annotation.name(), MetricType.METERED).merge(annotation),
- new MetricDescriptor(annotation.name(), annotation.tags()));
+ new MetricDescriptor(annotation.name(), scopeTags(annotation.tags())));
}
MeterAdapter internalMeter(MpMetadata metadata, MetricDescriptor id) {
@@ -363,12 +363,12 @@ public Timer timer(Metadata metadata, Tag... tags) {
TimerAdapter injectedTimer(org.eclipse.microprofile.metrics.annotation.Metric annotation) {
return internalTimer(
internalGetMetadata(annotation.name(), MetricType.TIMER).merge(annotation),
- new MetricDescriptor(annotation.name(), annotation.tags()));
+ new MetricDescriptor(annotation.name(), scopeTags(annotation.tags())));
}
TimerAdapter interceptorTimer(Metadata metadata, String... tags) {
return internalTimer(internalGetMetadata(metadata, MetricType.TIMER),
- new MetricDescriptor(metadata.getName(), tags));
+ new MetricDescriptor(metadata.getName(), scopeTags(tags)));
}
TimerAdapter internalTimer(MpMetadata metadata, MetricDescriptor id) {
@@ -465,7 +465,7 @@ public Metadata getMetadata(String name) {
TimerAdapter injectedSimpleTimer(org.eclipse.microprofile.metrics.annotation.Metric annotation) {
return internalSimpleTimer(
internalGetMetadata(annotation.name(), MetricType.SIMPLE_TIMER).merge(annotation),
- new MetricDescriptor(annotation.name(), annotation.tags()));
+ new MetricDescriptor(annotation.name(), scopeTags(annotation.tags())));
}
TimerAdapter internalSimpleTimer(MpMetadata metadata, MetricDescriptor id) {
@@ -657,14 +657,23 @@ public Type getType() {
return null;
}
+ Tags scopeTags() {
+ return Tags.of("scope", this.type.getName());
+ }
+
Tags scopeTags(Tag... tags) {
- Tags out = Tags.of("scope", this.type.getName());
+ Tags out = scopeTags();
for (Tag t : tags) {
out = out.and(t.getTagName(), t.getTagValue());
}
return out;
}
+ Tags scopeTags(String... tags) {
+ Tags in = Tags.of(tags);
+ return scopeTags().and(in);
+ }
+
private MpMetadata internalGetMetadata(String name, MetricType type) {
MpMetadata result = metadataMap.computeIfAbsent(name, k -> new MpMetadata(name, type));
if (result.type != type) {
diff --git a/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/DevServicesConfig.java b/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/DevServicesConfig.java
index 05a69f6df1015..fd3ee7e96b0a9 100644
--- a/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/DevServicesConfig.java
+++ b/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/DevServicesConfig.java
@@ -35,7 +35,7 @@ public class DevServicesConfig {
* string.
* Set 'quarkus.keycloak.devservices.keycloak-x-image' to override this check.
*/
- @ConfigItem(defaultValue = "quay.io/keycloak/keycloak:22.0.5")
+ @ConfigItem(defaultValue = "quay.io/keycloak/keycloak:23.0.0")
public String imageName;
/**
diff --git a/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/KeycloakDevServicesProcessor.java b/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/KeycloakDevServicesProcessor.java
index 23ffebaa2e6a2..019a3e4fad943 100644
--- a/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/KeycloakDevServicesProcessor.java
+++ b/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/KeycloakDevServicesProcessor.java
@@ -108,7 +108,7 @@ public class KeycloakDevServicesProcessor {
private static final String KEYCLOAK_QUARKUS_HOSTNAME = "KC_HOSTNAME";
private static final String KEYCLOAK_QUARKUS_ADMIN_PROP = "KEYCLOAK_ADMIN";
private static final String KEYCLOAK_QUARKUS_ADMIN_PASSWORD_PROP = "KEYCLOAK_ADMIN_PASSWORD";
- private static final String KEYCLOAK_QUARKUS_START_CMD = "start --storage=chm --http-enabled=true --hostname-strict=false --hostname-strict-https=false";
+ private static final String KEYCLOAK_QUARKUS_START_CMD = "start --http-enabled=true --hostname-strict=false --hostname-strict-https=false";
private static final String JAVA_OPTS = "JAVA_OPTS";
private static final String OIDC_USERS = "oidc.users";
diff --git a/extensions/redis-cache/runtime/src/main/java/io/quarkus/cache/redis/runtime/RedisCacheInfoBuilder.java b/extensions/redis-cache/runtime/src/main/java/io/quarkus/cache/redis/runtime/RedisCacheInfoBuilder.java
index 80113eee560ba..7fd99591c1ba9 100644
--- a/extensions/redis-cache/runtime/src/main/java/io/quarkus/cache/redis/runtime/RedisCacheInfoBuilder.java
+++ b/extensions/redis-cache/runtime/src/main/java/io/quarkus/cache/redis/runtime/RedisCacheInfoBuilder.java
@@ -31,7 +31,7 @@ public static Set build(Set cacheNames, RedisCachesBuild
if (namedRuntimeConfig != null && namedRuntimeConfig.expireAfterWrite.isPresent()) {
cacheInfo.expireAfterWrite = namedRuntimeConfig.expireAfterWrite;
- } else if (defaultRuntimeConfig.expireAfterAccess.isPresent()) {
+ } else if (defaultRuntimeConfig.expireAfterWrite.isPresent()) {
cacheInfo.expireAfterWrite = defaultRuntimeConfig.expireAfterWrite;
}
diff --git a/extensions/resteasy-reactive/jaxrs-client-reactive/deployment/src/main/java/io/quarkus/jaxrs/client/reactive/deployment/JaxrsClientReactiveProcessor.java b/extensions/resteasy-reactive/jaxrs-client-reactive/deployment/src/main/java/io/quarkus/jaxrs/client/reactive/deployment/JaxrsClientReactiveProcessor.java
index b96c574255bfa..cea258ce2771c 100644
--- a/extensions/resteasy-reactive/jaxrs-client-reactive/deployment/src/main/java/io/quarkus/jaxrs/client/reactive/deployment/JaxrsClientReactiveProcessor.java
+++ b/extensions/resteasy-reactive/jaxrs-client-reactive/deployment/src/main/java/io/quarkus/jaxrs/client/reactive/deployment/JaxrsClientReactiveProcessor.java
@@ -47,7 +47,6 @@
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.regex.Pattern;
-import java.util.stream.Collectors;
import jakarta.ws.rs.ProcessingException;
import jakarta.ws.rs.RuntimeType;
@@ -287,9 +286,8 @@ void setupClientProxies(JaxrsClientReactiveRecorder recorder,
scannedParameterContainers.addAll(parameterContainersBuildItem.getClassNames());
}
reflectiveClassBuildItemBuildProducer.produce(ReflectiveClassBuildItem
- .builder(scannedParameterContainers.stream().map(name -> name.toString()).collect(Collectors.toSet())
- .toArray(new String[0]))
- .fields().build());
+ .builder(scannedParameterContainers.stream().map(DotName::toString).distinct().toArray(String[]::new))
+ .methods().fields().build());
if (resourceScanningResultBuildItem.isEmpty()
|| resourceScanningResultBuildItem.get().getResult().getClientInterfaces().isEmpty()) {
diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive-kotlin-serialization-common/runtime/src/main/java/io/quarkus/resteasy/reactive/kotlin/serialization/common/runtime/JsonConfig.java b/extensions/resteasy-reactive/quarkus-resteasy-reactive-kotlin-serialization-common/runtime/src/main/java/io/quarkus/resteasy/reactive/kotlin/serialization/common/runtime/JsonConfig.java
index df47f1c32e7c0..bc64347ff3d76 100644
--- a/extensions/resteasy-reactive/quarkus-resteasy-reactive-kotlin-serialization-common/runtime/src/main/java/io/quarkus/resteasy/reactive/kotlin/serialization/common/runtime/JsonConfig.java
+++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive-kotlin-serialization-common/runtime/src/main/java/io/quarkus/resteasy/reactive/kotlin/serialization/common/runtime/JsonConfig.java
@@ -129,6 +129,12 @@ public class JsonConfig {
@ConfigItem(defaultValue = "false")
public boolean decodeEnumsCaseInsensitive = false;
+ /**
+ * Specifies if trailing comma is allowed.
+ */
+ @ConfigItem(defaultValue = "false")
+ public boolean allowTrailingComma = false;
+
@Override
public String toString() {
return new StringJoiner(", ", JsonConfig.class.getSimpleName() + "[", "]")
@@ -144,6 +150,7 @@ public String toString() {
.add("allowSpecialFloatingPointValues=" + allowSpecialFloatingPointValues)
.add("useAlternativeNames=" + useAlternativeNames)
.add("decodeEnumsCaseInsensitive=" + decodeEnumsCaseInsensitive)
+ .add("allowTrailingComma=" + allowTrailingComma)
.toString();
}
}
diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive-kotlin-serialization-common/runtime/src/main/kotlin/io/quarkus/resteasy/reactive/kotlin/serialization/common/runtime/JsonProducer.kt b/extensions/resteasy-reactive/quarkus-resteasy-reactive-kotlin-serialization-common/runtime/src/main/kotlin/io/quarkus/resteasy/reactive/kotlin/serialization/common/runtime/JsonProducer.kt
index 45ea46cde67a8..89dc0289b1104 100644
--- a/extensions/resteasy-reactive/quarkus-resteasy-reactive-kotlin-serialization-common/runtime/src/main/kotlin/io/quarkus/resteasy/reactive/kotlin/serialization/common/runtime/JsonProducer.kt
+++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive-kotlin-serialization-common/runtime/src/main/kotlin/io/quarkus/resteasy/reactive/kotlin/serialization/common/runtime/JsonProducer.kt
@@ -38,6 +38,7 @@ class JsonProducer {
useAlternativeNames = configuration.json.useAlternativeNames
useArrayPolymorphism = configuration.json.useArrayPolymorphism
decodeEnumsCaseInsensitive = configuration.json.decodeEnumsCaseInsensitive
+ allowTrailingComma = configuration.json.allowTrailingComma
configuration.json.namingStrategy.ifPresent { strategy ->
loadStrategy(this, strategy, this@JsonProducer)
diff --git a/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/SmallRyeOpenApiProcessor.java b/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/SmallRyeOpenApiProcessor.java
index 851e82a60e179..f73cfa65aeeeb 100644
--- a/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/SmallRyeOpenApiProcessor.java
+++ b/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/SmallRyeOpenApiProcessor.java
@@ -244,6 +244,7 @@ void registerAutoSecurityFilter(BuildProducer syntheticB
@BuildStep
@Record(ExecutionTime.STATIC_INIT)
void registerAnnotatedUserDefinedRuntimeFilters(BuildProducer syntheticBeans,
+ BuildProducer reflectiveClass,
OpenApiFilteredIndexViewBuildItem apiFilteredIndexViewBuildItem,
OpenApiRecorder recorder) {
Config config = ConfigProvider.getConfig();
@@ -256,6 +257,7 @@ void registerAnnotatedUserDefinedRuntimeFilters(BuildProducer springComponent.principalNameFromObject(new Person("user")), "user", USER);
}
+ @Test
+ public void testPrincipalNameFromObjectIsNot() {
+ assertFailureFor(() -> springComponent.principalNameFromObjectIsNot(new Person("whatever")),
+ UnauthorizedException.class,
+ ANONYMOUS);
+ assertSuccess(() -> springComponent.principalNameFromObjectIsNot(new Person("whatever")), "whatever", USER);
+ assertFailureFor(() -> springComponent.principalNameFromObjectIsNot(new Person("user")), ForbiddenException.class,
+ USER);
+ }
+
@Test
public void testNotSecured() {
assertSuccess(() -> springComponent.notSecured(), "notSecured", ANONYMOUS);
diff --git a/extensions/spring-security/deployment/src/test/java/io/quarkus/spring/security/deployment/springapp/SpringComponent.java b/extensions/spring-security/deployment/src/test/java/io/quarkus/spring/security/deployment/springapp/SpringComponent.java
index 0d86e8406fcf3..68a8af6552c6d 100644
--- a/extensions/spring-security/deployment/src/test/java/io/quarkus/spring/security/deployment/springapp/SpringComponent.java
+++ b/extensions/spring-security/deployment/src/test/java/io/quarkus/spring/security/deployment/springapp/SpringComponent.java
@@ -37,6 +37,11 @@ public String principalNameFromObject(Person person) {
return person.getName();
}
+ @PreAuthorize("#person.name != authentication.principal.username")
+ public String principalNameFromObjectIsNot(Person person) {
+ return person.getName();
+ }
+
public String notSecured() {
return "notSecured";
}
diff --git a/extensions/spring-security/runtime/src/main/java/io/quarkus/spring/security/runtime/interceptor/SpringSecurityRecorder.java b/extensions/spring-security/runtime/src/main/java/io/quarkus/spring/security/runtime/interceptor/SpringSecurityRecorder.java
index 8101bdd0991b6..591c08d8bd892 100644
--- a/extensions/spring-security/runtime/src/main/java/io/quarkus/spring/security/runtime/interceptor/SpringSecurityRecorder.java
+++ b/extensions/spring-security/runtime/src/main/java/io/quarkus/spring/security/runtime/interceptor/SpringSecurityRecorder.java
@@ -70,8 +70,9 @@ public SecurityCheck fromGeneratedClass(String generatedClassName) {
}
public SecurityCheck principalNameFromParameterObjectSecurityCheck(int index, String expectedParameterClass,
- String stringPropertyAccessorClass, String propertyName) {
+ String stringPropertyAccessorClass, String propertyName,
+ PrincipalNameFromParameterObjectSecurityCheck.CheckType checkType) {
return PrincipalNameFromParameterObjectSecurityCheck.of(index, expectedParameterClass, stringPropertyAccessorClass,
- propertyName);
+ propertyName, checkType);
}
}
diff --git a/extensions/spring-security/runtime/src/main/java/io/quarkus/spring/security/runtime/interceptor/check/PrincipalNameFromParameterObjectSecurityCheck.java b/extensions/spring-security/runtime/src/main/java/io/quarkus/spring/security/runtime/interceptor/check/PrincipalNameFromParameterObjectSecurityCheck.java
index c34e97b6d5f7b..63da575e48187 100644
--- a/extensions/spring-security/runtime/src/main/java/io/quarkus/spring/security/runtime/interceptor/check/PrincipalNameFromParameterObjectSecurityCheck.java
+++ b/extensions/spring-security/runtime/src/main/java/io/quarkus/spring/security/runtime/interceptor/check/PrincipalNameFromParameterObjectSecurityCheck.java
@@ -23,22 +23,24 @@ public class PrincipalNameFromParameterObjectSecurityCheck implements SecurityCh
private final Class> expectedParameterClass;
private final Class extends StringPropertyAccessor> stringPropertyAccessorClass;
private final String propertyName;
+ private final CheckType checkType;
private PrincipalNameFromParameterObjectSecurityCheck(int index, String expectedParameterClass,
- String stringPropertyAccessorClass, String propertyName) throws ClassNotFoundException {
+ String stringPropertyAccessorClass, String propertyName, CheckType checkType) throws ClassNotFoundException {
this.index = index;
this.expectedParameterClass = Class.forName(expectedParameterClass, false,
Thread.currentThread().getContextClassLoader());
this.stringPropertyAccessorClass = (Class extends StringPropertyAccessor>) Class.forName(stringPropertyAccessorClass,
false, Thread.currentThread().getContextClassLoader());
this.propertyName = propertyName;
+ this.checkType = checkType;
}
public static PrincipalNameFromParameterObjectSecurityCheck of(int index, String expectedParameterClass,
- String stringPropertyAccessorClass, String propertyName) {
+ String stringPropertyAccessorClass, String propertyName, CheckType checkType) {
try {
return new PrincipalNameFromParameterObjectSecurityCheck(index, expectedParameterClass, stringPropertyAccessorClass,
- propertyName);
+ propertyName, checkType);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
@@ -70,8 +72,14 @@ private void doApply(SecurityIdentity identity, Object[] parameters, String clas
}
String name = identity.getPrincipal().getName();
- if (!name.equals(parameterValueStr)) {
- throw new ForbiddenException();
+ if (checkType == CheckType.EQ) {
+ if (!name.equals(parameterValueStr)) {
+ throw new ForbiddenException();
+ }
+ } else if (checkType == CheckType.NEQ) {
+ if (name.equals(parameterValueStr)) {
+ throw new ForbiddenException();
+ }
}
}
@@ -84,4 +92,9 @@ private IllegalStateException genericNotApplicableException(String className, St
"PrincipalNameFromParameterObjectSecurityCheck with index " + index + " cannot be applied to '" + className
+ "#" + methodName + "'");
}
+
+ public enum CheckType {
+ EQ,
+ NEQ
+ }
}
diff --git a/independent-projects/arc/pom.xml b/independent-projects/arc/pom.xml
index 9fcf219e160dd..5cf3128c08d0c 100644
--- a/independent-projects/arc/pom.xml
+++ b/independent-projects/arc/pom.xml
@@ -54,7 +54,7 @@
1.6.Final
3.24.2
- 5.10.0
+ 5.10.1
1.9.21
1.7.3
5.7.0
diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanDeployment.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanDeployment.java
index f64a96a1c42f5..8b22177b9da75 100644
--- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanDeployment.java
+++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanDeployment.java
@@ -953,8 +953,14 @@ private List findBeans(Collection beanDefiningAnnotations, Li
.map(StereotypeInfo::getName)
.collect(Collectors.toSet());
+ Set seenClasses = new HashSet<>();
+
// If needed use the specialized immutable index to discover beans
for (ClassInfo beanClass : beanArchiveImmutableIndex.getKnownClasses()) {
+ if (!seenClasses.add(beanClass.name())) {
+ // avoid discovering the same bean twice
+ continue;
+ }
if (Modifier.isInterface(beanClass.flags()) || Modifier.isAbstract(beanClass.flags())
|| beanClass.isAnnotation() || beanClass.isEnum()) {
@@ -1579,6 +1585,29 @@ private void validateBeans(List errors, Consumer
}
}
}
+
+ List>> duplicateBeanIds = beans.stream()
+ .collect(Collectors.groupingBy(BeanInfo::getIdentifier))
+ .entrySet()
+ .stream()
+ .filter(entry -> entry.getValue().size() > 1)
+ .collect(Collectors.toList());
+ if (!duplicateBeanIds.isEmpty()) {
+ String separator = "====================";
+ StringBuilder error = new StringBuilder("\n")
+ .append(separator).append(separator).append(separator).append(separator).append("\n")
+ .append("Multiple beans with the same identifier found!\n")
+ .append("----------------------------------------------\n")
+ .append("This is an internal error. Please report a bug and attach the following listing.\n\n");
+ for (Map.Entry> entry : duplicateBeanIds) {
+ error.append(entry.getKey()).append(" -> ").append(entry.getValue().size()).append(" beans:\n");
+ for (BeanInfo bean : entry.getValue()) {
+ error.append("- ").append(bean).append("\n");
+ }
+ }
+ error.append(separator).append(separator).append(separator).append(separator).append("\n");
+ errors.add(new DeploymentException(error.toString()));
+ }
}
private void findNamespaces(BeanInfo bean, Set namespaces) {
diff --git a/independent-projects/bootstrap/pom.xml b/independent-projects/bootstrap/pom.xml
index 42aa44afb02e2..ad9f2f590dadf 100644
--- a/independent-projects/bootstrap/pom.xml
+++ b/independent-projects/bootstrap/pom.xml
@@ -46,7 +46,7 @@
3.24.2
0.9.5
3.5.3.Final
- 5.10.0
+ 5.10.1
3.9.6
0.9.0.M2
3.10.2
@@ -61,7 +61,7 @@
4.0.1
2.0.1
1.16.0
- 2.15.0
+ 2.15.1
3.13.0
32.1.3-jre
1.0.1
diff --git a/independent-projects/extension-maven-plugin/pom.xml b/independent-projects/extension-maven-plugin/pom.xml
index 909d80325c1ff..3b7c4993340c4 100644
--- a/independent-projects/extension-maven-plugin/pom.xml
+++ b/independent-projects/extension-maven-plugin/pom.xml
@@ -44,7 +44,7 @@
3.10.2
2.15.3
1.3.2
- 5.10.0
+ 5.10.1
diff --git a/independent-projects/junit5-virtual-threads/pom.xml b/independent-projects/junit5-virtual-threads/pom.xml
index d30d68dcb74ef..cdb450b45d62b 100644
--- a/independent-projects/junit5-virtual-threads/pom.xml
+++ b/independent-projects/junit5-virtual-threads/pom.xml
@@ -48,7 +48,7 @@
2.23.0
1.9.0
- 5.10.0
+ 5.10.1
diff --git a/independent-projects/qute/pom.xml b/independent-projects/qute/pom.xml
index ca6c9c5db9f07..f618d9bee11b4 100644
--- a/independent-projects/qute/pom.xml
+++ b/independent-projects/qute/pom.xml
@@ -41,7 +41,7 @@
11
11
11
- 5.10.0
+ 5.10.1
3.24.2
3.1.6
1.7.0
diff --git a/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/ClientReaderInterceptorContextImpl.java b/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/ClientReaderInterceptorContextImpl.java
index 200f0c5bcc8eb..99fa3837fd647 100644
--- a/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/ClientReaderInterceptorContextImpl.java
+++ b/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/ClientReaderInterceptorContextImpl.java
@@ -91,7 +91,8 @@ public Object proceed() throws IOException, WebApplicationException {
}
}
- StringBuilder errorMessage = new StringBuilder("Response could not be mapped to type " + entityType);
+ StringBuilder errorMessage = new StringBuilder(
+ "Response could not be mapped to type " + entityType + " for response with media type " + mediaType);
if (!contextualizers.isEmpty()) {
var input = new MissingMessageBodyReaderErrorMessageContextualizer.Input() {
@Override
diff --git a/independent-projects/resteasy-reactive/pom.xml b/independent-projects/resteasy-reactive/pom.xml
index 5089c255879c7..5ce2d22175a19 100644
--- a/independent-projects/resteasy-reactive/pom.xml
+++ b/independent-projects/resteasy-reactive/pom.xml
@@ -50,7 +50,7 @@
4.0.1
3.1.6
1.12.12
- 5.10.0
+ 5.10.1
3.9.6
3.24.2
3.5.3.Final
diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/ResteasyReactiveRequestContext.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/ResteasyReactiveRequestContext.java
index dedaf7dd127cd..2248a8f7763ac 100644
--- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/ResteasyReactiveRequestContext.java
+++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/ResteasyReactiveRequestContext.java
@@ -226,18 +226,20 @@ public void setMaxPathParams(int maxPathParams) {
}
}
- public String getPathParam(int index) {
- return doGetPathParam(index, pathParamValues);
+ public String getPathParam(int index, boolean encoded) {
+ return doGetPathParam(index, pathParamValues, encoded);
}
- private String doGetPathParam(int index, Object pathParamValues) {
+ private String doGetPathParam(int index, Object pathParamValues, boolean encoded) {
if (pathParamValues instanceof String[]) {
- return ((String[]) pathParamValues)[index];
+ String pathParam = ((String[]) pathParamValues)[index];
+ return encoded ? pathParam : Encode.decodePath(pathParam);
}
if (index > 1) {
throw new IndexOutOfBoundsException();
}
- return (String) pathParamValues;
+ String pathParam = (String) pathParamValues;
+ return encoded ? pathParam : Encode.decodePath(pathParam);
}
public ResteasyReactiveRequestContext setPathParamValue(int index, String value) {
@@ -926,18 +928,11 @@ public String getPathParameter(String name, boolean encoded) {
Integer index = target.getPathParameterIndexes().get(name);
String value;
if (index != null) {
- value = getPathParam(index);
- } else {
- // Check previous resources if the path is not defined in the current target
- value = getResourceLocatorPathParam(name);
- }
-
- // It's possible to inject a path param that's not defined, return null in this case
- if (encoded && value != null) {
- return Encode.encodeQueryParam(value);
+ return getPathParam(index, encoded);
}
- return value;
+ // Check previous resources if the path is not defined in the current target
+ return getResourceLocatorPathParam(name, encoded);
}
@Override
@@ -996,8 +991,8 @@ public ResteasyReactiveResourceInfo getResteasyReactiveResourceInfo() {
public abstract Runnable registerTimer(long millis, Runnable task);
- public String getResourceLocatorPathParam(String name) {
- return getResourceLocatorPathParam(name, (PreviousResource) getProperty(PreviousResource.PROPERTY_KEY));
+ public String getResourceLocatorPathParam(String name, boolean encoded) {
+ return getResourceLocatorPathParam(name, (PreviousResource) getProperty(PreviousResource.PROPERTY_KEY), encoded);
}
public FormData getFormData() {
@@ -1009,7 +1004,7 @@ public ResteasyReactiveRequestContext setFormData(FormData formData) {
return this;
}
- private String getResourceLocatorPathParam(String name, PreviousResource previousResource) {
+ private String getResourceLocatorPathParam(String name, PreviousResource previousResource, boolean encoded) {
if (previousResource == null) {
return null;
}
@@ -1020,13 +1015,13 @@ private String getResourceLocatorPathParam(String name, PreviousResource previou
for (URITemplate.TemplateComponent component : classPath.components) {
if (component.name != null) {
if (component.name.equals(name)) {
- return doGetPathParam(index, previousResource.locatorPathParamValues);
+ return doGetPathParam(index, previousResource.locatorPathParamValues, encoded);
}
index++;
} else if (component.names != null) {
for (String nm : component.names) {
if (nm.equals(name)) {
- return doGetPathParam(index, previousResource.locatorPathParamValues);
+ return doGetPathParam(index, previousResource.locatorPathParamValues, encoded);
}
}
index++;
@@ -1036,19 +1031,19 @@ private String getResourceLocatorPathParam(String name, PreviousResource previou
for (URITemplate.TemplateComponent component : previousResource.locatorTarget.getPath().components) {
if (component.name != null) {
if (component.name.equals(name)) {
- return doGetPathParam(index, previousResource.locatorPathParamValues);
+ return doGetPathParam(index, previousResource.locatorPathParamValues, encoded);
}
index++;
} else if (component.names != null) {
for (String nm : component.names) {
if (nm.equals(name)) {
- return doGetPathParam(index, previousResource.locatorPathParamValues);
+ return doGetPathParam(index, previousResource.locatorPathParamValues, encoded);
}
}
index++;
}
}
- return getResourceLocatorPathParam(name, previousResource.prev);
+ return getResourceLocatorPathParam(name, previousResource.prev, encoded);
}
public abstract boolean resumeExternalProcessing();
diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/parameters/LocatableResourcePathParamExtractor.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/parameters/LocatableResourcePathParamExtractor.java
index 835be0b515340..e478141b7c45c 100644
--- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/parameters/LocatableResourcePathParamExtractor.java
+++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/parameters/LocatableResourcePathParamExtractor.java
@@ -12,7 +12,7 @@ public LocatableResourcePathParamExtractor(String name) {
@Override
public Object extractParameter(ResteasyReactiveRequestContext context) {
- return context.getResourceLocatorPathParam(name);
+ return context.getResourceLocatorPathParam(name, false);
}
}
diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/parameters/PathParamExtractor.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/parameters/PathParamExtractor.java
index ccfa99edca5c3..d56f72b856bf5 100644
--- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/parameters/PathParamExtractor.java
+++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/parameters/PathParamExtractor.java
@@ -1,6 +1,8 @@
package org.jboss.resteasy.reactive.server.core.parameters;
+import java.util.Arrays;
import java.util.List;
+import java.util.stream.Collectors;
import org.jboss.resteasy.reactive.common.util.Encode;
import org.jboss.resteasy.reactive.server.core.ResteasyReactiveRequestContext;
@@ -19,14 +21,14 @@ public PathParamExtractor(int index, boolean encoded, boolean single) {
@Override
public Object extractParameter(ResteasyReactiveRequestContext context) {
- String pathParam = context.getPathParam(index);
- if (encoded) {
- pathParam = Encode.encodeQueryParam(pathParam);
- }
+ String pathParam = context.getPathParam(index, true);
if (single) {
- return pathParam;
+ return encoded ? pathParam : Encode.decodePath(pathParam);
} else {
- return List.of(pathParam.split("/"));
+ return encoded
+ ? List.of(pathParam.split("/"))
+ : Arrays.stream(pathParam.split("/")).map(Encode::decodePath)
+ .collect(Collectors.toList());
}
}
}
diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/jaxrs/UriInfoImpl.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/jaxrs/UriInfoImpl.java
index 7cbd13cb272a6..987bbf2838113 100644
--- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/jaxrs/UriInfoImpl.java
+++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/jaxrs/UriInfoImpl.java
@@ -152,7 +152,7 @@ public MultivaluedMap getPathParameters(boolean decode) {
RuntimeResource target = currentRequest.getTarget();
if (target != null) { // a target can be null if this happens in a filter that runs before the target is set
for (Entry pathParam : target.getPathParameterIndexes().entrySet()) {
- pathParams.add(pathParam.getKey(), currentRequest.getPathParam(pathParam.getValue()));
+ pathParams.add(pathParam.getKey(), currentRequest.getPathParam(pathParam.getValue(), false));
}
}
}
diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/mapping/RequestMapper.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/mapping/RequestMapper.java
index 5d8d5fc931191..7fd7cb535f518 100644
--- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/mapping/RequestMapper.java
+++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/mapping/RequestMapper.java
@@ -8,8 +8,6 @@
import java.util.Map;
import java.util.regex.Matcher;
-import org.jboss.resteasy.reactive.common.util.URIDecoder;
-
public class RequestMapper {
private static final String[] EMPTY_STRING_ARRAY = new String[0];
@@ -111,7 +109,7 @@ private RequestMatch mapFromPathMatcher(String path, PathMatcher.PathMatch3.24.2
2.15.3
4.0.1
- 5.10.0
- 1.24.0
+ 5.10.1
+ 1.25.0
3.5.3.Final
5.3.1
3.2.1
diff --git a/integration-tests/micrometer-mp-metrics/src/main/java/io/quarkus/it/micrometer/mpmetrics/MessageResource.java b/integration-tests/micrometer-mp-metrics/src/main/java/io/quarkus/it/micrometer/mpmetrics/MessageResource.java
index 2105c7ef33831..6ce3276f3f970 100644
--- a/integration-tests/micrometer-mp-metrics/src/main/java/io/quarkus/it/micrometer/mpmetrics/MessageResource.java
+++ b/integration-tests/micrometer-mp-metrics/src/main/java/io/quarkus/it/micrometer/mpmetrics/MessageResource.java
@@ -1,34 +1,60 @@
package io.quarkus.it.micrometer.mpmetrics;
+import java.util.Collection;
+import java.util.Objects;
+
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
+import org.eclipse.microprofile.metrics.Counter;
+import org.eclipse.microprofile.metrics.annotation.Metric;
+
+import io.micrometer.core.instrument.Meter;
import io.micrometer.core.instrument.MeterRegistry;
+import io.micrometer.core.instrument.search.Search;
@Path("/message")
public class MessageResource {
private final MeterRegistry registry;
+ private final Counter first;
+ private final Counter second;
- public MessageResource(MeterRegistry registry) {
+ public MessageResource(MeterRegistry registry,
+ @Metric(name = "first-counter") final Counter first,
+ @Metric(name = "second-counter") final Counter second) {
this.registry = registry;
+ this.first = Objects.requireNonNull(first);
+ this.second = Objects.requireNonNull(second);
}
@GET
public String message() {
+ first.inc();
+ second.inc();
return registry.getClass().getName();
}
@GET
@Path("fail")
public String fail() {
+ first.inc();
throw new NullPointerException("Failed on purpose");
}
@GET
@Path("item/{id}")
public String item(@PathParam("id") String id) {
+ second.inc();
return "return message with id " + id;
}
+
+ @GET
+ @Path("mpmetrics")
+ public String metrics() {
+ Collection meters = Search.in(registry).name(s -> s.contains("mpmetrics")).meters();
+ meters.addAll(Search.in(registry).name(s -> s.endsWith("-counter")).meters());
+ return meters.stream().allMatch(x -> x.getId().getTag("scope") != null) ? "OK" : "FAIL";
+ }
}
diff --git a/integration-tests/micrometer-mp-metrics/src/test/java/io/quarkus/it/micrometer/mpmetrics/MPMetricsTest.java b/integration-tests/micrometer-mp-metrics/src/test/java/io/quarkus/it/micrometer/mpmetrics/MPMetricsTest.java
index 7d47a0f85cba2..d7c2e9fc02344 100644
--- a/integration-tests/micrometer-mp-metrics/src/test/java/io/quarkus/it/micrometer/mpmetrics/MPMetricsTest.java
+++ b/integration-tests/micrometer-mp-metrics/src/test/java/io/quarkus/it/micrometer/mpmetrics/MPMetricsTest.java
@@ -70,7 +70,10 @@ void validateMetricsOutput_1() {
"io_quarkus_it_micrometer_mpmetrics_PrimeResource_highestPrimeNumberSoFar2{scope=\"application\"} 887.0"))
// the counter associated with a timed method should have been removed
- .body(not(containsString("io_quarkus_it_micrometer_mpmetrics_PrimeResource_checkPrime")));
+ .body(not(containsString("io_quarkus_it_micrometer_mpmetrics_PrimeResource_checkPrime")))
+
+ // no calls to /message
+ .body(not(containsString("/message")));
}
@Test
@@ -83,7 +86,7 @@ void callPrimeGen_4() {
}
@Test
- @Order(8)
+ @Order(6)
void callMessage() {
given()
.when().get("/message")
@@ -91,6 +94,24 @@ void callMessage() {
.statusCode(200);
}
+ @Test
+ @Order(7)
+ void callMessageFail() {
+ given()
+ .when().get("/message/fail")
+ .then()
+ .statusCode(500);
+ }
+
+ @Test
+ @Order(8)
+ void callMessageId() {
+ given()
+ .when().get("/message/item/35")
+ .then()
+ .statusCode(200);
+ }
+
@Test
@Order(9)
void validateMetricsOutput_2() {
@@ -106,7 +127,10 @@ void validateMetricsOutput_2() {
"highestPrimeNumberSoFar 887.0"))
.body(containsString(
"io_quarkus_it_micrometer_mpmetrics_InjectedInstance_notPrime_total{scope=\"application\"}"))
- .body(not(containsString("/message")));
+ .body(containsString(
+ "first_counter_total{scope=\"application\"}"))
+ .body(containsString(
+ "second_counter_total{scope=\"application\"}"));
}
@Test
@@ -123,4 +147,13 @@ void validateJsonOutput() {
Matchers.equalTo(887.0f));
}
+ @Test
+ @Order(11)
+ void meters() {
+ given()
+ .when().get("/message/mpmetrics")
+ .then()
+ .statusCode(200)
+ .log().body();
+ }
}
diff --git a/pom.xml b/pom.xml
index 90c5862d3c077..3e14413b69ea7 100644
--- a/pom.xml
+++ b/pom.xml
@@ -60,7 +60,7 @@
jdbc:postgresql:hibernate_orm_test
4.5.1
- 0.0.99
+ 0.0.100
false
false
diff --git a/test-framework/jacoco/runtime/src/main/java/io/quarkus/jacoco/runtime/ReportCreator.java b/test-framework/jacoco/runtime/src/main/java/io/quarkus/jacoco/runtime/ReportCreator.java
index e118708a6c684..2d440c3762e13 100644
--- a/test-framework/jacoco/runtime/src/main/java/io/quarkus/jacoco/runtime/ReportCreator.java
+++ b/test-framework/jacoco/runtime/src/main/java/io/quarkus/jacoco/runtime/ReportCreator.java
@@ -37,6 +37,16 @@ public ReportCreator(ReportInfo reportInfo, JacocoConfig config) {
@Override
public void run() {
+ // Ugly workaround:
+ // Multiple ReportCreator shutdown hooks might run concurrently, possibly corrupting the report file(s) - e.g. when using @TestProfile.
+ // By locking on a class from the parent CL, all hooks are "serialized", one after another.
+ // In the long run there should only be as many hooks as there are different Jacoco configs...usually there will be only one config anyway!
+ synchronized (ExecFileLoader.class) {
+ doRun();
+ }
+ }
+
+ private void doRun() {
File targetdir = new File(reportInfo.reportDir);
targetdir.mkdirs();
try {