diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 7ffe773060c4f..9df0e488cf3af 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -184,6 +184,7 @@ updates: - dependency-name: biz.paluch.logging:logstash-gelf - dependency-name: org.bitbucket.b_c:jose4j - dependency-name: io.fabric8:maven-model-helper + - dependency-name: org.codejive:java-properties ignore: # this one cannot be upgraded due to the usage of proxies in new versions # the proxy implements interfaces in a random order which causes issues diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml index ec0ced15ae954..7aaec6dcc712a 100644 --- a/.mvn/extensions.xml +++ b/.mvn/extensions.xml @@ -17,6 +17,6 @@ io.quarkus.develocity quarkus-project-develocity-extension - 1.1.1 + 1.1.3 diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 7ada2a259ee04..a7a94b2848cd4 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -92,14 +92,14 @@ 23.1.2 1.8.0 - 2.17.1 + 2.17.2 1.0.0.Final 3.14.0 1.17.0 1.7.0 - 7.0.1.Final + 7.0.2.Final 2.4 8.0.0.Final 8.14.0 diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/filesystem/StaticFileManager.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/filesystem/StaticFileManager.java index d3706c1e133e5..acfad17471237 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/dev/filesystem/StaticFileManager.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/filesystem/StaticFileManager.java @@ -31,8 +31,9 @@ public Iterable getJavaSources(Iterable runtim // so we reinitialize this to re-compute the field (and other related fields) during native application's // runtime runtimeReInitClass.produce(new RuntimeReinitializedClassBuildItem("org.wildfly.common.net.HostName")); + runtimeReInitClass.produce(new RuntimeReinitializedClassBuildItem("io.smallrye.common.net.HostName")); } private Boolean isSslNativeEnabled(SslNativeConfigBuildItem sslNativeConfig, diff --git a/docs/src/main/asciidoc/cdi-integration.adoc b/docs/src/main/asciidoc/cdi-integration.adoc index 0ff90a1fb144a..f6775181e5a64 100644 --- a/docs/src/main/asciidoc/cdi-integration.adoc +++ b/docs/src/main/asciidoc/cdi-integration.adoc @@ -76,7 +76,7 @@ IMPORTANT: It is not possible to conditionally enable/disable additional beans v ---- @BuildStep AdditionalBeanBuildItem additionalBeans() { - return new AdditionalBeanBuildItem(SmallRyeHealthReporter.class, HealthServlet.class)); <1> + return new AdditionalBeanBuildItem(SmallRyeHealthReporter.class, HealthServlet.class); <1> } ---- <1> `AdditionalBeanBuildItem.Builder` can be used for more complex use cases. diff --git a/docs/src/main/asciidoc/security-customization.adoc b/docs/src/main/asciidoc/security-customization.adoc index 5a0ee041e6672..b42ce570911ed 100644 --- a/docs/src/main/asciidoc/security-customization.adoc +++ b/docs/src/main/asciidoc/security-customization.adoc @@ -682,7 +682,7 @@ The observers can be either synchronous or asynchronous. * `io.quarkus.oidc.SecurityEvent` * `io.quarkus.vertx.http.runtime.security.FormAuthenticationEvent` -[[TIP]] +[TIP] For more information about security events specific to the Quarkus OpenID Connect extension, please see the xref:security-oidc-code-flow-authentication.adoc#listen-to-authentication-events[Listening to important authentication events] section of the OIDC code flow mechanism for protecting web applications guide. diff --git a/docs/src/main/asciidoc/security-keycloak-authorization.adoc b/docs/src/main/asciidoc/security-keycloak-authorization.adoc index 94d844883ebc9..a4d34e1407fd5 100644 --- a/docs/src/main/asciidoc/security-keycloak-authorization.adoc +++ b/docs/src/main/asciidoc/security-keycloak-authorization.adoc @@ -226,7 +226,7 @@ To start a Keycloak server, use the following Docker command: docker run --name keycloak -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin -p 8543:8443 -v "$(pwd)"/config/keycloak-keystore.jks:/etc/keycloak-keystore.jks quay.io/keycloak/keycloak:{keycloak.version} start --hostname-strict=false --https-key-store-file=/etc/keycloak-keystore.jks ---- -where `keycloak.version` must be `23.0.0` or later and the `keycloak-keystore.jks` can be found in https://github.com/quarkusio/quarkus-quickstarts/blob/main/security-keycloak-authorization-quickstart/config/keycloak-keystore.jks[quarkus-quickstarts/security-keycloak-authorization-quickstart/config]. +where `keycloak.version` must be `25.0.0` or later and the `keycloak-keystore.jks` can be found in https://github.com/quarkusio/quarkus-quickstarts/blob/main/security-keycloak-authorization-quickstart/config/keycloak-keystore.jks[quarkus-quickstarts/security-keycloak-authorization-quickstart/config]. Try to access your Keycloak server at https://localhost:8543[localhost:8543]. diff --git a/docs/src/main/asciidoc/security-oidc-auth0-tutorial.adoc b/docs/src/main/asciidoc/security-oidc-auth0-tutorial.adoc index 6e1ffbb1d991f..6fe1d7753f41e 100644 --- a/docs/src/main/asciidoc/security-oidc-auth0-tutorial.adoc +++ b/docs/src/main/asciidoc/security-oidc-auth0-tutorial.adoc @@ -689,7 +689,7 @@ quarkus.oidc.auth-server-url=https://dev-3ve0cgn7.us.auth0.com which is all what is needed for the OIDC `service` application to fetch Auth0 public verification keys and use them to verify Auth0 access tokens in JWT format. -[[NOTE]] +[NOTE] ==== In this tutorial you have already configured the OIDC `hybrid` application which can handle both authorization code and bearer token authentication flows. In production you will run microservices as separate servers but for the sake of simplicity `ApiEchoService` will not have to be started as a second server with its own configuration containing `quarkus.oidc.auth-server-url=https://dev-3ve0cgn7.us.auth0.com` only, and therefore the current configuration which already has the Auth0 dev tenant address configured will be reused. diff --git a/docs/src/main/asciidoc/security-oidc-bearer-token-authentication-tutorial.adoc b/docs/src/main/asciidoc/security-oidc-bearer-token-authentication-tutorial.adoc index 67717da4065b1..c4a6a64a9a0e3 100644 --- a/docs/src/main/asciidoc/security-oidc-bearer-token-authentication-tutorial.adoc +++ b/docs/src/main/asciidoc/security-oidc-bearer-token-authentication-tutorial.adoc @@ -217,7 +217,7 @@ For more information, see the <> section. docker run --name keycloak -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin -p 8180:8080 quay.io/keycloak/keycloak:{keycloak.version} start-dev ---- ==== -* Where the `keycloak.version` is set to version `23.0.0` or later. +* Where the `keycloak.version` is set to version `25.0.0` or later. . You can access your Keycloak server at http://localhost:8180[localhost:8180]. . To access the Keycloak Administration console, log in as the `admin` user by using the following login credentials: diff --git a/docs/src/main/asciidoc/security-oidc-code-flow-authentication-tutorial.adoc b/docs/src/main/asciidoc/security-oidc-code-flow-authentication-tutorial.adoc index 63d99eab3b2fc..f47b743a12086 100644 --- a/docs/src/main/asciidoc/security-oidc-code-flow-authentication-tutorial.adoc +++ b/docs/src/main/asciidoc/security-oidc-code-flow-authentication-tutorial.adoc @@ -201,7 +201,7 @@ To start a Keycloak server, use Docker and run the following command: docker run --name keycloak -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin -p 8180:8080 quay.io/keycloak/keycloak:{keycloak.version} start-dev ---- -where `keycloak.version` is set to `23.0.0` or later. +where `keycloak.version` is set to `25.0.0` or later. You can access your Keycloak Server at http://localhost:8180[localhost:8180]. diff --git a/docs/src/main/asciidoc/security-openid-connect-client.adoc b/docs/src/main/asciidoc/security-openid-connect-client.adoc index 9876031aee273..d279a870375c0 100644 --- a/docs/src/main/asciidoc/security-openid-connect-client.adoc +++ b/docs/src/main/asciidoc/security-openid-connect-client.adoc @@ -535,7 +535,7 @@ To start a Keycloak Server, you can use Docker and just run the following comman docker run --name keycloak -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin -p 8180:8080 quay.io/keycloak/keycloak:{keycloak.version} start-dev ---- -Set `{keycloak.version}` to `23.0.0` or later. +Set `{keycloak.version}` to `25.0.0` or later. You can access your Keycloak Server at http://localhost:8180[localhost:8180]. diff --git a/docs/src/main/asciidoc/security-openid-connect-multitenancy.adoc b/docs/src/main/asciidoc/security-openid-connect-multitenancy.adoc index 0cca72b4f7dad..d031ecdcd0071 100644 --- a/docs/src/main/asciidoc/security-openid-connect-multitenancy.adoc +++ b/docs/src/main/asciidoc/security-openid-connect-multitenancy.adoc @@ -351,7 +351,7 @@ To start a Keycloak server, you can use Docker and run the following command: docker run --name keycloak -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin -p 8180:8080 quay.io/keycloak/keycloak:{keycloak.version} start-dev ---- -where `keycloak.version` is set to `23.0.0` or higher. +where `keycloak.version` is set to `25.0.0` or higher. Access your Keycloak server at http://localhost:8180[localhost:8180]. diff --git a/docs/src/main/asciidoc/telemetry-micrometer.adoc b/docs/src/main/asciidoc/telemetry-micrometer.adoc index c986d7b46c186..a61966fa16d76 100644 --- a/docs/src/main/asciidoc/telemetry-micrometer.adoc +++ b/docs/src/main/asciidoc/telemetry-micrometer.adoc @@ -179,7 +179,7 @@ Given the following declaration of a timer: `registry.timer("http.server.request === Define dimensions for aggregation Metrics, single numerical measurements, often have additional data captured with them. This ancillary data is used to group or aggregate metrics for analysis. -The Micrometer API refers to this dimensional data as tags, but you may it referred to as "labels" or "attributes" in other documentation sources. +The Micrometer API refers to this dimensional data as tags, but you may see it referred to as "labels" or "attributes" in other documentation sources. Micrometer is built primariliy for backend monitoring systems that support dimensional data (metric names that are enchriched with key/value pairs). For heirarchical systems that only support a flat metric name, Micrometer will flatten the set of key/value pairs (sorted by key) and add them to the name. diff --git a/docs/src/main/java/io/quarkus/docs/generation/AssembleDownstreamDocumentation.java b/docs/src/main/java/io/quarkus/docs/generation/AssembleDownstreamDocumentation.java index 6f23fd809cd4c..2a88d1d2b106c 100755 --- a/docs/src/main/java/io/quarkus/docs/generation/AssembleDownstreamDocumentation.java +++ b/docs/src/main/java/io/quarkus/docs/generation/AssembleDownstreamDocumentation.java @@ -426,7 +426,7 @@ private static String rewriteContent(String fileName, addError(errors, fileName, "Unable to find title for: " + mr.group() + " [" + reference + "]"); title = "~~ unknown title ~~"; } - return "xref:" + trimReference(mr.group(1)) + "[" + title.trim() + "]"; + return "xref:" + trimReference(mr.group(1)) + "[" + escapeXrefTitleForReplaceAll(title) + "]"; }); content = ANGLE_BRACKETS_WITHOUT_DESCRIPTION_PATTERN.matcher(content).replaceAll(mr -> { @@ -436,11 +436,11 @@ private static String rewriteContent(String fileName, addError(errors, fileName, "Unable to find title for: " + mr.group() + " [" + reference + "]"); title = "~~ unknown title ~~"; } - return "xref:" + trimReference(mr.group(1)) + "[" + title.trim() + "]"; + return "xref:" + trimReference(mr.group(1)) + "[" + escapeXrefTitleForReplaceAll(title) + "]"; }); content = ANGLE_BRACKETS_WITH_DESCRIPTION_PATTERN.matcher(content).replaceAll(mr -> { - return "xref:" + trimReference(mr.group(1)) + "[" + mr.group(2).trim() + "]"; + return "xref:" + trimReference(mr.group(1)) + "[" + escapeXrefTitleForReplaceAll(mr.group(2)) + "]"; }); content = XREF_GUIDE_PATTERN.matcher(content).replaceAll(mr -> { @@ -466,6 +466,10 @@ private static String rewriteContent(String fileName, return content; } + private static String escapeXrefTitleForReplaceAll(String title) { + return title.trim().replace("]", "\\\\]"); + } + private static String trimReference(String reference) { reference = normalizeAdoc(reference); diff --git a/extensions/amazon-lambda/maven-archetype/src/main/resources/archetype-resources/gradle.properties b/extensions/amazon-lambda/maven-archetype/src/main/resources/archetype-resources/gradle.properties index 644310c2b3a94..c77b7693b0052 100644 --- a/extensions/amazon-lambda/maven-archetype/src/main/resources/archetype-resources/gradle.properties +++ b/extensions/amazon-lambda/maven-archetype/src/main/resources/archetype-resources/gradle.properties @@ -1,5 +1,5 @@ -#Gradle properties -#Tue Mar 17 10:20:48 UTC 2020 +# Gradle properties + quarkusPluginVersion=${project.version} quarkusPlatformArtifactId=quarkus-bom quarkusPlatformVersion=${project.version} diff --git a/extensions/cache/runtime/src/main/java/io/quarkus/cache/runtime/CacheResultInterceptor.java b/extensions/cache/runtime/src/main/java/io/quarkus/cache/runtime/CacheResultInterceptor.java index f635d965a518e..f16d6674ee7ed 100644 --- a/extensions/cache/runtime/src/main/java/io/quarkus/cache/runtime/CacheResultInterceptor.java +++ b/extensions/cache/runtime/src/main/java/io/quarkus/cache/runtime/CacheResultInterceptor.java @@ -1,7 +1,6 @@ package io.quarkus.cache.runtime; import java.time.Duration; -import java.util.concurrent.Executor; import java.util.function.Function; import java.util.function.Supplier; @@ -17,10 +16,6 @@ import io.smallrye.mutiny.Multi; import io.smallrye.mutiny.TimeoutException; import io.smallrye.mutiny.Uni; -import io.vertx.core.Context; -import io.vertx.core.Handler; -import io.vertx.core.Vertx; -import io.vertx.core.impl.ContextInternal; @CacheResult(cacheName = "") // The `cacheName` attribute is @Nonbinding. @Interceptor @@ -58,7 +53,6 @@ public Object intercept(InvocationContext invocationContext) throws Throwable { try { ReturnType returnType = determineReturnType(invocationContext.getMethod().getReturnType()); if (returnType != ReturnType.NonAsync) { - Context context = Vertx.currentContext(); Uni cacheValue = cache.getAsync(key, new Function>() { @SuppressWarnings("unchecked") @Override @@ -76,48 +70,6 @@ public Uni apply(Object key) { public Uni apply(Throwable throwable) { return cache.invalidate(key).replaceWith(throwable); } - }).emitOn(new Executor() { - // We need make sure we go back to the original context when the cache value is computed. - // Otherwise, we would always emit on the context having computed the value, which could - // break the duplicated context isolation. - @Override - public void execute(Runnable command) { - Context ctx = Vertx.currentContext(); - if (context == null) { - // We didn't capture a context - if (ctx == null) { - // We are not on a context => we can execute immediately. - command.run(); - } else { - // We are on a context. - // We cannot continue on the current context as we may share a duplicated context. - // We need a new one. Note that duplicate() does not duplicate the duplicated context, - // but the root context. - ((ContextInternal) ctx).duplicate() - .runOnContext(new Handler() { - @Override - public void handle(Void ignored) { - command.run(); - } - }); - } - } else { - // We captured a context. - if (ctx == context) { - // We are on the same context => we can execute immediately - command.run(); - } else { - // 1) We are not on a context (ctx == null) => we need to switch to the captured context. - // 2) We are on a different context (ctx != null) => we need to switch to the captured context. - context.runOnContext(new Handler() { - @Override - public void handle(Void ignored) { - command.run(); - } - }); - } - } - } }); if (binding.lockTimeout() <= 0) { diff --git a/extensions/cache/runtime/src/main/java/io/quarkus/cache/runtime/caffeine/CaffeineCacheImpl.java b/extensions/cache/runtime/src/main/java/io/quarkus/cache/runtime/caffeine/CaffeineCacheImpl.java index dff31eb8dab1e..278c1ebc3ab15 100644 --- a/extensions/cache/runtime/src/main/java/io/quarkus/cache/runtime/caffeine/CaffeineCacheImpl.java +++ b/extensions/cache/runtime/src/main/java/io/quarkus/cache/runtime/caffeine/CaffeineCacheImpl.java @@ -8,6 +8,7 @@ import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; +import java.util.concurrent.Executor; import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; @@ -26,6 +27,10 @@ import io.quarkus.cache.runtime.AbstractCache; import io.quarkus.cache.runtime.NullValueConverter; import io.smallrye.mutiny.Uni; +import io.vertx.core.Context; +import io.vertx.core.Handler; +import io.vertx.core.Vertx; +import io.vertx.core.impl.ContextInternal; /** * This class is an internal Quarkus cache implementation using Caffeine. Do not use it explicitly from your Quarkus @@ -99,6 +104,7 @@ public CompletionStage get() { @Override public Uni getAsync(K key, Function> valueLoader) { Objects.requireNonNull(key, NULL_KEYS_NOT_SUPPORTED_MSG); + Context context = Vertx.currentContext(); return Uni.createFrom() .completionStage(new Supplier>() { @Override @@ -119,7 +125,51 @@ public CompletableFuture apply(Object key) { recorder.doRecord(key); return result; } - }).map(fromCacheValue()); + }) + .map(fromCacheValue()) + .emitOn(new Executor() { + // We need make sure we go back to the original context when the cache value is computed. + // Otherwise, we would always emit on the context having computed the value, which could + // break the duplicated context isolation. + @Override + public void execute(Runnable command) { + Context ctx = Vertx.currentContext(); + if (context == null) { + // We didn't capture a context + if (ctx == null) { + // We are not on a context => we can execute immediately. + command.run(); + } else { + // We are on a context. + // We cannot continue on the current context as we may share a duplicated context. + // We need a new one. Note that duplicate() does not duplicate the duplicated context, + // but the root context. + ((ContextInternal) ctx).duplicate() + .runOnContext(new Handler() { + @Override + public void handle(Void ignored) { + command.run(); + } + }); + } + } else { + // We captured a context. + if (ctx == context) { + // We are on the same context => we can execute immediately + command.run(); + } else { + // 1) We are not on a context (ctx == null) => we need to switch to the captured context. + // 2) We are on a different context (ctx != null) => we need to switch to the captured context. + context.runOnContext(new Handler() { + @Override + public void handle(Void ignored) { + command.run(); + } + }); + } + } + } + }); } @Override diff --git a/extensions/hibernate-search-standalone-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/standalone/elasticsearch/runtime/HibernateSearchStandaloneBuildTimeConfig.java b/extensions/hibernate-search-standalone-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/standalone/elasticsearch/runtime/HibernateSearchStandaloneBuildTimeConfig.java index 8ef6845e7aa04..fc3de18ff9b91 100644 --- a/extensions/hibernate-search-standalone-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/standalone/elasticsearch/runtime/HibernateSearchStandaloneBuildTimeConfig.java +++ b/extensions/hibernate-search-standalone-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/standalone/elasticsearch/runtime/HibernateSearchStandaloneBuildTimeConfig.java @@ -269,7 +269,7 @@ interface MappingConfig { * Associations between entities must be bi-directional: * specifying the inverse side of associations through `@AssociationInverseSide` *is required*, * unless reindexing is disabled for that association through `@IndexingDependency(reindexOnUpdate = ...)`. - * `tree`:: + * `document`:: * Entities indexed through Hibernate Search are the root of a document, * i.e. an indexed entity "owns" other entities it references through associations, * which *cannot* be updated independently of the indexed entity. diff --git a/extensions/infinispan-cache/runtime/src/main/java/io/quarkus/cache/infinispan/runtime/InfinispanCacheImpl.java b/extensions/infinispan-cache/runtime/src/main/java/io/quarkus/cache/infinispan/runtime/InfinispanCacheImpl.java index a92f6f4e70fd7..cc0ea14720eb6 100644 --- a/extensions/infinispan-cache/runtime/src/main/java/io/quarkus/cache/infinispan/runtime/InfinispanCacheImpl.java +++ b/extensions/infinispan-cache/runtime/src/main/java/io/quarkus/cache/infinispan/runtime/InfinispanCacheImpl.java @@ -5,6 +5,7 @@ import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executor; import java.util.concurrent.Flow; import java.util.concurrent.TimeUnit; import java.util.function.Function; @@ -24,6 +25,10 @@ import io.quarkus.infinispan.client.runtime.InfinispanClientUtil; import io.smallrye.mutiny.Multi; import io.smallrye.mutiny.Uni; +import io.vertx.core.Context; +import io.vertx.core.Handler; +import io.vertx.core.Vertx; +import io.vertx.core.impl.ContextInternal; /** * This class is an internal Quarkus cache implementation using Infinispan. @@ -111,6 +116,8 @@ public Uni get(K key, Function valueLoader) { @Override public Uni getAsync(K key, Function> valueLoader) { + Context context = Vertx.currentContext(); + return Uni.createFrom().completionStage(CompletionStages.handleAndCompose(remoteCache.getAsync(key), (v1, ex1) -> { if (ex1 != null) { return CompletableFuture.failedFuture(ex1); @@ -145,7 +152,49 @@ public Uni getAsync(K key, Function> valueLoader) { } }); return resultAsync; - })); + })).emitOn(new Executor() { + // We need make sure we go back to the original context when the cache value is computed. + // Otherwise, we would always emit on the context having computed the value, which could + // break the duplicated context isolation. + @Override + public void execute(Runnable command) { + Context ctx = Vertx.currentContext(); + if (context == null) { + // We didn't capture a context + if (ctx == null) { + // We are not on a context => we can execute immediately. + command.run(); + } else { + // We are on a context. + // We cannot continue on the current context as we may share a duplicated context. + // We need a new one. Note that duplicate() does not duplicate the duplicated context, + // but the root context. + ((ContextInternal) ctx).duplicate() + .runOnContext(new Handler() { + @Override + public void handle(Void ignored) { + command.run(); + } + }); + } + } else { + // We captured a context. + if (ctx == context) { + // We are on the same context => we can execute immediately + command.run(); + } else { + // 1) We are not on a context (ctx == null) => we need to switch to the captured context. + // 2) We are on a different context (ctx != null) => we need to switch to the captured context. + context.runOnContext(new Handler() { + @Override + public void handle(Void ignored) { + command.run(); + } + }); + } + } + } + }); } @Override diff --git a/extensions/infinispan-client/runtime/src/main/java/io/quarkus/infinispan/client/runtime/InfinispanDevServicesConfig.java b/extensions/infinispan-client/runtime/src/main/java/io/quarkus/infinispan/client/runtime/InfinispanDevServicesConfig.java index 1a2a55c4a637e..5296d468953d6 100644 --- a/extensions/infinispan-client/runtime/src/main/java/io/quarkus/infinispan/client/runtime/InfinispanDevServicesConfig.java +++ b/extensions/infinispan-client/runtime/src/main/java/io/quarkus/infinispan/client/runtime/InfinispanDevServicesConfig.java @@ -148,7 +148,7 @@ public boolean equals(Object o) { Objects.equals(shared, that.shared) && Objects.equals(serviceName, that.serviceName) && Objects.equals(imageName, that.imageName) && - Objects.equals(artifacts, this.artifacts) && + Objects.equals(artifacts, that.artifacts) && Objects.equals(containerEnv, that.containerEnv); } diff --git a/extensions/jackson/deployment/src/main/java/io/quarkus/jackson/deployment/JacksonProcessor.java b/extensions/jackson/deployment/src/main/java/io/quarkus/jackson/deployment/JacksonProcessor.java index d7e1b79843231..5460754feb9cf 100644 --- a/extensions/jackson/deployment/src/main/java/io/quarkus/jackson/deployment/JacksonProcessor.java +++ b/extensions/jackson/deployment/src/main/java/io/quarkus/jackson/deployment/JacksonProcessor.java @@ -34,6 +34,7 @@ import com.fasterxml.jackson.databind.PropertyNamingStrategies; import com.fasterxml.jackson.databind.PropertyNamingStrategy; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonNaming; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.annotation.JsonTypeIdResolver; import com.fasterxml.jackson.databind.module.SimpleModule; @@ -83,6 +84,7 @@ public class JacksonProcessor { private static final DotName JSON_TYPE_ID_RESOLVER = DotName.createSimple(JsonTypeIdResolver.class.getName()); private static final DotName JSON_SUBTYPES = DotName.createSimple(JsonSubTypes.class.getName()); + private static final DotName JACKSON_NAMING = DotName.createSimple(JsonNaming.class.getName()); private static final DotName JSON_CREATOR = DotName.createSimple("com.fasterxml.jackson.annotation.JsonCreator"); private static final DotName JSON_NAMING = DotName.createSimple("com.fasterxml.jackson.databind.annotation.JsonNaming"); @@ -298,6 +300,18 @@ void register( .methods().fields().build()); } + // register @JsonNaming for reflection + Set namingTypesNames = new HashSet<>(); + for (AnnotationInstance namingInstance : index.getAnnotations(JSON_NAMING)) { + AnnotationValue namingValue = namingInstance.value(); + if (namingValue != null) { + namingTypesNames.add(namingValue.asClass().name().toString()); + } + } + if (!namingTypesNames.isEmpty()) { + reflectiveClass.produce(ReflectiveClassBuildItem.builder(namingTypesNames.toArray(EMPTY_STRING)).build()); + } + // this needs to be registered manually since the runtime module is not indexed by Jandex additionalBeans.produce(new AdditionalBeanBuildItem(ObjectMapperProducer.class)); } diff --git a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/AddPortToKnativeConfig.java b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/AddPortToKnativeConfig.java index bb89510d27d3a..6a5cd38ce4d8e 100644 --- a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/AddPortToKnativeConfig.java +++ b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/AddPortToKnativeConfig.java @@ -29,7 +29,7 @@ public void visit(KnativeConfigFluent config) { */ private boolean hasPort(KnativeConfigFluent config) { for (Port p : config.buildPorts()) { - if (p.getContainerPort() == port.getContainerPort()) { + if (Objects.equals(p.getContainerPort(), port.getContainerPort())) { return true; } } diff --git a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/AddPortToKubernetesConfig.java b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/AddPortToKubernetesConfig.java index c2305c8227fc6..13ac4c240335c 100644 --- a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/AddPortToKubernetesConfig.java +++ b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/AddPortToKubernetesConfig.java @@ -29,7 +29,7 @@ public void visit(KubernetesConfigFluent config) { */ private boolean hasPort(KubernetesConfigFluent config) { for (Port p : config.buildPorts()) { - if (p.getContainerPort() == port.getContainerPort()) { + if (Objects.equals(p.getContainerPort(), port.getContainerPort())) { return true; } } diff --git a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/AddPortToOpenshiftConfig.java b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/AddPortToOpenshiftConfig.java index 6235424c3a43c..e8077aed4ebd4 100644 --- a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/AddPortToOpenshiftConfig.java +++ b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/AddPortToOpenshiftConfig.java @@ -29,7 +29,7 @@ public void visit(OpenshiftConfigFluent config) { */ private boolean hasPort(OpenshiftConfigFluent config) { for (Port p : config.buildPorts()) { - if (p.getContainerPort() == port.getContainerPort()) { + if (Objects.equals(p.getContainerPort(), port.getContainerPort())) { return true; } } diff --git a/extensions/liquibase/deployment/src/main/java/io/quarkus/liquibase/deployment/LiquibaseProcessor.java b/extensions/liquibase/deployment/src/main/java/io/quarkus/liquibase/deployment/LiquibaseProcessor.java index 66e45af582ff9..8b415d41106e4 100644 --- a/extensions/liquibase/deployment/src/main/java/io/quarkus/liquibase/deployment/LiquibaseProcessor.java +++ b/extensions/liquibase/deployment/src/main/java/io/quarkus/liquibase/deployment/LiquibaseProcessor.java @@ -3,6 +3,7 @@ import static io.quarkus.deployment.annotations.ExecutionTime.STATIC_INIT; import static java.util.function.Predicate.not; +import java.io.FileNotFoundException; import java.io.IOException; import java.nio.file.Paths; import java.util.ArrayList; @@ -61,8 +62,10 @@ import io.quarkus.liquibase.LiquibaseDataSource; import io.quarkus.liquibase.LiquibaseFactory; import io.quarkus.liquibase.runtime.LiquibaseBuildTimeConfig; +import io.quarkus.liquibase.runtime.LiquibaseDataSourceBuildTimeConfig; import io.quarkus.liquibase.runtime.LiquibaseFactoryProducer; import io.quarkus.liquibase.runtime.LiquibaseRecorder; +import io.quarkus.runtime.util.StringUtil; import liquibase.change.Change; import liquibase.change.DatabaseChangeProperty; import liquibase.change.core.CreateProcedureChange; @@ -77,6 +80,9 @@ import liquibase.parser.ChangeLogParserFactory; import liquibase.plugin.AbstractPluginFactory; import liquibase.resource.ClassLoaderResourceAccessor; +import liquibase.resource.CompositeResourceAccessor; +import liquibase.resource.DirectoryResourceAccessor; +import liquibase.resource.ResourceAccessor; class LiquibaseProcessor { @@ -360,57 +366,89 @@ private List getChangeLogs(Collection dataSourceNames, Liquibase return Collections.emptyList(); } - ChangeLogParameters changeLogParameters = new ChangeLogParameters(); + List liquibaseDataSources = new ArrayList<>(); - ChangeLogParserFactory changeLogParserFactory = ChangeLogParserFactory.getInstance(); + if (DataSourceUtil.hasDefault(dataSourceNames)) { + liquibaseDataSources.add(liquibaseBuildConfig.defaultDataSource); + } + + for (String dataSourceName : dataSourceNames) { + if (!DataSourceUtil.isDefault(dataSourceName)) { + liquibaseDataSources.add(liquibaseBuildConfig.getConfigForDataSourceName(dataSourceName)); + } + } + ChangeLogParameters changeLogParameters = new ChangeLogParameters(); + ChangeLogParserFactory changeLogParserFactory = ChangeLogParserFactory.getInstance(); Set resources = new LinkedHashSet<>(); + for (LiquibaseDataSourceBuildTimeConfig liquibaseDataSourceConfig : liquibaseDataSources) { - ClassLoaderResourceAccessor classLoaderResourceAccessor = new ClassLoaderResourceAccessor( - Thread.currentThread().getContextClassLoader()); + Optional> oSearchPaths = liquibaseDataSourceConfig.searchPath; + String changeLog = liquibaseDataSourceConfig.changeLog; + String parsedChangeLog = parseChangeLog(oSearchPaths, changeLog); - try { - // default datasource - if (DataSourceUtil.hasDefault(dataSourceNames)) { - resources.addAll(findAllChangeLogFiles(liquibaseBuildConfig.defaultDataSource.changeLog, changeLogParserFactory, - classLoaderResourceAccessor, changeLogParameters)); + try (ResourceAccessor resourceAccessor = resolveResourceAccessor(oSearchPaths, changeLog)) { + resources.addAll(findAllChangeLogFiles(parsedChangeLog, changeLogParserFactory, + resourceAccessor, changeLogParameters)); + } catch (Exception ex) { + throw new IllegalStateException(ex); } + } - // named datasources - Collection namedDataSourceChangeLogs = dataSourceNames.stream() - .filter(n -> !DataSourceUtil.isDefault(n)) - .map(liquibaseBuildConfig::getConfigForDataSourceName) - .map(c -> c.changeLog) - .collect(Collectors.toCollection(LinkedHashSet::new)); - - for (String namedDataSourceChangeLog : namedDataSourceChangeLogs) { - resources.addAll( - findAllChangeLogFiles(namedDataSourceChangeLog, changeLogParserFactory, classLoaderResourceAccessor, - changeLogParameters)); - } + LOGGER.debugf("Liquibase changeLogs: %s", resources); + return new ArrayList<>(resources); + } - LOGGER.debugf("Liquibase changeLogs: %s", resources); + private ResourceAccessor resolveResourceAccessor(Optional> oSearchPaths, String changeLog) + throws FileNotFoundException { - return new ArrayList<>(resources); + CompositeResourceAccessor compositeResourceAccessor = new CompositeResourceAccessor(); + compositeResourceAccessor + .addResourceAccessor(new ClassLoaderResourceAccessor(Thread.currentThread().getContextClassLoader())); - } finally { - try { - classLoaderResourceAccessor.close(); - } catch (Exception ignored) { - // close() really shouldn't declare that exception, see also https://github.com/liquibase/liquibase/pull/2576 - } + if (!changeLog.startsWith("filesystem:") && oSearchPaths.isEmpty()) { + return compositeResourceAccessor; } + + if (oSearchPaths.isEmpty()) { + compositeResourceAccessor.addResourceAccessor( + new DirectoryResourceAccessor( + Paths.get(StringUtil.changePrefix(changeLog, "filesystem:", "")).getParent())); + return compositeResourceAccessor; + } + + for (String searchPath : oSearchPaths.get()) { + compositeResourceAccessor.addResourceAccessor(new DirectoryResourceAccessor(Paths.get(searchPath))); + } + + return compositeResourceAccessor; + } + + private String parseChangeLog(Optional> oSearchPaths, String changeLog) { + + if (changeLog.startsWith("filesystem:") && oSearchPaths.isEmpty()) { + return Paths.get(StringUtil.changePrefix(changeLog, "filesystem:", "")).getFileName().toString(); + } + + if (changeLog.startsWith("filesystem:")) { + return StringUtil.changePrefix(changeLog, "filesystem:", ""); + } + + if (changeLog.startsWith("classpath:")) { + return StringUtil.changePrefix(changeLog, "classpath:", ""); + } + + return changeLog; } /** * Finds all resource files for the given change log file */ private Set findAllChangeLogFiles(String file, ChangeLogParserFactory changeLogParserFactory, - ClassLoaderResourceAccessor classLoaderResourceAccessor, - ChangeLogParameters changeLogParameters) { + ResourceAccessor resourceAccessor, ChangeLogParameters changeLogParameters) { try { - ChangeLogParser parser = changeLogParserFactory.getParser(file, classLoaderResourceAccessor); - DatabaseChangeLog changelog = parser.parse(file, changeLogParameters, classLoaderResourceAccessor); + ChangeLogParser parser = changeLogParserFactory.getParser(file, resourceAccessor); + DatabaseChangeLog changelog = parser.parse(file, changeLogParameters, resourceAccessor); if (changelog != null) { Set result = new LinkedHashSet<>(); diff --git a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/OidcTenantConfig.java b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/OidcTenantConfig.java index 84290b257abb7..899c6f454fc4d 100644 --- a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/OidcTenantConfig.java +++ b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/OidcTenantConfig.java @@ -94,8 +94,7 @@ public class OidcTenantConfig extends OidcCommonConfig { /** * The paths which must be secured by this tenant. Tenant with the most specific path wins. - * Please see the xref:security-openid-connect-multitenancy.adoc#configuration-based-tenant-resolver[Resolve with - * configuration] + * Please see the xref:security-openid-connect-multitenancy.adoc#configure-tenant-paths[Configure tenant paths] * section of the OIDC multitenancy guide for explanation of allowed path patterns. * * @asciidoclet diff --git a/extensions/resteasy-reactive/rest-client/deployment/src/main/java/io/quarkus/rest/client/reactive/deployment/RestClientReactiveProcessor.java b/extensions/resteasy-reactive/rest-client/deployment/src/main/java/io/quarkus/rest/client/reactive/deployment/RestClientReactiveProcessor.java index 07d3e0cebed69..3ccb72cce6088 100644 --- a/extensions/resteasy-reactive/rest-client/deployment/src/main/java/io/quarkus/rest/client/reactive/deployment/RestClientReactiveProcessor.java +++ b/extensions/resteasy-reactive/rest-client/deployment/src/main/java/io/quarkus/rest/client/reactive/deployment/RestClientReactiveProcessor.java @@ -311,6 +311,10 @@ void registerProvidersFromAnnotations(CombinedIndexBuildItem indexBuildItem, int.class), constructor.getThis(), constructor.loadClassFromTCCL(providerDotName.toString()), constructor.load(priority)); + + // when the server is not included, providers are not automatically registered for reflection, + // so we need to always do it for the client to be on the safe side + reflectiveClassesProducer.produce(ReflectiveClassBuildItem.builder(providerDotName.toString()).build()); } } diff --git a/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/resource/basic/InheritanceTest.java b/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/resource/basic/InheritanceTest.java index cda6508920086..2e7b03c59807b 100644 --- a/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/resource/basic/InheritanceTest.java +++ b/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/resource/basic/InheritanceTest.java @@ -16,6 +16,8 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; +import io.quarkus.resteasy.reactive.server.test.resource.basic.resource.InheritanceAbstractParentImplResource; +import io.quarkus.resteasy.reactive.server.test.resource.basic.resource.InheritanceAbstractParentResource; import io.quarkus.resteasy.reactive.server.test.resource.basic.resource.InheritanceParentResource; import io.quarkus.resteasy.reactive.server.test.resource.basic.resource.InheritanceParentResourceImpl; import io.quarkus.resteasy.reactive.server.test.simple.PortProviderUtil; @@ -39,6 +41,8 @@ public class InheritanceTest { public JavaArchive get() { JavaArchive war = ShrinkWrap.create(JavaArchive.class); war.addClass(InheritanceParentResource.class); + war.addClass(InheritanceAbstractParentResource.class); + war.addClass(InheritanceAbstractParentImplResource.class); war.addClasses(PortProviderUtil.class, InheritanceParentResourceImpl.class); return war; } @@ -67,4 +71,13 @@ public void Test1() throws Exception { Assertions.assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); Assertions.assertEquals(response.readEntity(String.class), "First"); } + + @Test + public void testAbstractParent() { + Builder builder = client.target(generateURL("/inheritance-abstract-parent-test")).request(); + builder.header("Accept", "text/plain"); + Response response = builder.get(); + Assertions.assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); + Assertions.assertEquals(response.readEntity(String.class), "works"); + } } diff --git a/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/resource/basic/resource/InheritanceAbstractParentImplResource.java b/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/resource/basic/resource/InheritanceAbstractParentImplResource.java new file mode 100644 index 0000000000000..4b740f37a38fc --- /dev/null +++ b/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/resource/basic/resource/InheritanceAbstractParentImplResource.java @@ -0,0 +1,10 @@ +package io.quarkus.resteasy.reactive.server.test.resource.basic.resource; + +public class InheritanceAbstractParentImplResource extends InheritanceAbstractParentResource { + + @Override + public String get() { + return "works"; + } + +} diff --git a/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/resource/basic/resource/InheritanceAbstractParentResource.java b/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/resource/basic/resource/InheritanceAbstractParentResource.java new file mode 100644 index 0000000000000..26560c777eb26 --- /dev/null +++ b/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/resource/basic/resource/InheritanceAbstractParentResource.java @@ -0,0 +1,12 @@ +package io.quarkus.resteasy.reactive.server.test.resource.basic.resource; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; + +@Path("/inheritance-abstract-parent-test") +public abstract class InheritanceAbstractParentResource { + + @GET + public abstract String get(); + +} diff --git a/extensions/smallrye-graphql/runtime/src/main/java/io/quarkus/smallrye/graphql/runtime/SmallRyeGraphQLExecutionHandler.java b/extensions/smallrye-graphql/runtime/src/main/java/io/quarkus/smallrye/graphql/runtime/SmallRyeGraphQLExecutionHandler.java index d0ffbc1901c95..7d97c18bd090c 100644 --- a/extensions/smallrye-graphql/runtime/src/main/java/io/quarkus/smallrye/graphql/runtime/SmallRyeGraphQLExecutionHandler.java +++ b/extensions/smallrye-graphql/runtime/src/main/java/io/quarkus/smallrye/graphql/runtime/SmallRyeGraphQLExecutionHandler.java @@ -309,7 +309,7 @@ private String readQueryParameter(RoutingContext ctx, String parameterName) { return null; } - private static final Pattern PATTERN_NEWLINE_OR_TAB = Pattern.compile("\\n|\\t"); + private static final Pattern PATTERN_NEWLINE_OR_TAB = Pattern.compile("\\n|\\t|\\r"); /** * Strip away unescaped tabs and line breaks from the incoming JSON document so that it can be diff --git a/extensions/vertx/deployment/src/main/java/io/quarkus/vertx/core/deployment/VertxCoreProcessor.java b/extensions/vertx/deployment/src/main/java/io/quarkus/vertx/core/deployment/VertxCoreProcessor.java index d376eb44e13ef..ab09839b74d15 100644 --- a/extensions/vertx/deployment/src/main/java/io/quarkus/vertx/core/deployment/VertxCoreProcessor.java +++ b/extensions/vertx/deployment/src/main/java/io/quarkus/vertx/core/deployment/VertxCoreProcessor.java @@ -369,7 +369,7 @@ private Filter createDebuggerFilter() { debugPort = Integer.parseInt(m.group(2)); String host = m.group(1); if (host.equals("*")) { - host.equals("localhost"); + host = "localhost"; } bindAddress = InetAddress.getByName(host); } diff --git a/extensions/websockets-next/deployment/src/main/java/io/quarkus/websockets/next/deployment/devui/WebSocketServerDevUIProcessor.java b/extensions/websockets-next/deployment/src/main/java/io/quarkus/websockets/next/deployment/devui/WebSocketServerDevUIProcessor.java index 5f89d5cfd0482..2785efe1fbdd4 100644 --- a/extensions/websockets-next/deployment/src/main/java/io/quarkus/websockets/next/deployment/devui/WebSocketServerDevUIProcessor.java +++ b/extensions/websockets-next/deployment/src/main/java/io/quarkus/websockets/next/deployment/devui/WebSocketServerDevUIProcessor.java @@ -40,7 +40,7 @@ public void pages(List endpoints, List root + .addClass(MyBean.class)); + + @Test + public void testConnectorIsInjected() { + assertEquals("1", RestAssured.get("mybeantest").then().statusCode(200).extract().body().asString()); + } + + @Singleton + public static class MyBean { + + @Inject + BasicWebSocketConnector connector; + + void addRoute(@Observes Router router) { + router.get("/mybeantest").handler(rc -> { + rc.end(connector != null ? "1" : "0"); + }); + } + + } + +} diff --git a/extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/runtime/BasicWebSocketConnectorImpl.java b/extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/runtime/BasicWebSocketConnectorImpl.java index fb33732ca6c47..7d2487783ccf1 100644 --- a/extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/runtime/BasicWebSocketConnectorImpl.java +++ b/extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/runtime/BasicWebSocketConnectorImpl.java @@ -117,10 +117,7 @@ public Uni connect() { // TODO would it make sense to share clients? WebSocketClient client = vertx.createWebSocketClient(populateClientOptions()); - WebSocketConnectOptions connectOptions = new WebSocketConnectOptions() - .setSsl(baseUri.getScheme().equals("https")) - .setHost(baseUri.getHost()) - .setPort(baseUri.getPort()); + WebSocketConnectOptions connectOptions = newConnectOptions(baseUri); StringBuilder requestUri = new StringBuilder(); String mergedPath = mergePath(baseUri.getPath(), replacePathParameters(path)); requestUri.append(mergedPath); diff --git a/extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/runtime/WebSocketConnectorBase.java b/extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/runtime/WebSocketConnectorBase.java index ee098d6a43d16..1556899636c9f 100644 --- a/extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/runtime/WebSocketConnectorBase.java +++ b/extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/runtime/WebSocketConnectorBase.java @@ -21,6 +21,7 @@ import io.vertx.core.Vertx; import io.vertx.core.buffer.Buffer; import io.vertx.core.http.WebSocketClientOptions; +import io.vertx.core.http.WebSocketConnectOptions; import io.vertx.core.net.SSLOptions; abstract class WebSocketConnectorBase> { @@ -191,4 +192,21 @@ protected WebSocketClientOptions populateClientOptions() { } return clientOptions; } + + protected WebSocketConnectOptions newConnectOptions(URI serverEndpointUri) { + WebSocketConnectOptions connectOptions = new WebSocketConnectOptions() + .setSsl(isHttps(serverEndpointUri)) + .setHost(serverEndpointUri.getHost()); + if (serverEndpointUri.getPort() != -1) { + connectOptions.setPort(serverEndpointUri.getPort()); + } else if (isHttps(serverEndpointUri)) { + // If port is undefined and https is used then use 443 by default + connectOptions.setPort(443); + } + return connectOptions; + } + + protected boolean isHttps(URI uri) { + return "https".equals(uri.getScheme()); + } } diff --git a/extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/runtime/WebSocketConnectorImpl.java b/extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/runtime/WebSocketConnectorImpl.java index 359a400f5160a..1b6d9a6af32ec 100644 --- a/extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/runtime/WebSocketConnectorImpl.java +++ b/extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/runtime/WebSocketConnectorImpl.java @@ -73,10 +73,7 @@ public Uni connect() { throw new WebSocketClientException(e); } - WebSocketConnectOptions connectOptions = new WebSocketConnectOptions() - .setSsl(serverEndpointUri.getScheme().equals("https")) - .setHost(serverEndpointUri.getHost()) - .setPort(serverEndpointUri.getPort()); + WebSocketConnectOptions connectOptions = newConnectOptions(serverEndpointUri); StringBuilder uri = new StringBuilder(); if (serverEndpointUri.getPath() != null) { uri.append(serverEndpointUri.getRawPath()); diff --git a/extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/runtime/devui/WebSocketNextJsonRPCService.java b/extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/runtime/devui/WebSocketNextJsonRPCService.java index 5df2e1d395b28..b54992fae08bd 100644 --- a/extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/runtime/devui/WebSocketNextJsonRPCService.java +++ b/extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/runtime/devui/WebSocketNextJsonRPCService.java @@ -12,6 +12,7 @@ import java.util.concurrent.ConcurrentMap; import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Instance; import org.jboss.logging.Logger; @@ -53,16 +54,18 @@ public class WebSocketNextJsonRPCService implements ConnectionListener { private final WebSocketsServerRuntimeConfig.DevMode devModeConfig; - WebSocketNextJsonRPCService(ConnectionManager connectionManager, Vertx vertx, HttpConfiguration httpConfig, + WebSocketNextJsonRPCService(Instance connectionManager, Vertx vertx, HttpConfiguration httpConfig, WebSocketsServerRuntimeConfig config) { this.connectionStatus = BroadcastProcessor.create(); this.connectionMessages = BroadcastProcessor.create(); - this.connectionManager = connectionManager; + this.connectionManager = connectionManager.isResolvable() ? connectionManager.get() : null; this.vertx = vertx; this.httpConfig = httpConfig; this.devModeConfig = config.devMode(); this.sockets = new ConcurrentHashMap<>(); - connectionManager.addListener(this); + if (this.connectionManager != null) { + this.connectionManager.addListener(this); + } } public Multi connectionStatus() { @@ -75,14 +78,16 @@ public Multi connectionMessages() { public JsonObject getConnections(List endpoints) { JsonObject json = new JsonObject(); - for (String endpoint : endpoints) { - List connections = new ArrayList<>(connectionManager.getConnections(endpoint)); - connections.sort(Comparator.comparing(WebSocketConnection::creationTime)); - JsonArray array = new JsonArray(); - for (WebSocketConnection c : connections) { - array.add(toJsonObject(endpoint, c)); + if (connectionManager != null) { + for (String endpoint : endpoints) { + List connections = new ArrayList<>(connectionManager.getConnections(endpoint)); + connections.sort(Comparator.comparing(WebSocketConnection::creationTime)); + JsonArray array = new JsonArray(); + for (WebSocketConnection c : connections) { + array.add(toJsonObject(endpoint, c)); + } + json.put(endpoint, array); } - json.put(endpoint, array); } json.put("connectionMessagesLimit", devModeConfig.connectionMessagesLimit()); return json; @@ -104,6 +109,9 @@ public JsonArray getMessages(String connectionKey) { } public Uni openDevConnection(String path, String endpointPath) { + if (connectionManager == null) { + return failureUni(); + } if (isInvalidPath(path, endpointPath)) { LOG.errorf("Invalid path %s; original endpoint path %s", path, endpointPath); return failureUni(); @@ -179,6 +187,9 @@ private static String normalize(String path) { } public Uni closeDevConnection(String connectionKey) { + if (connectionManager == null) { + return failureUni(); + } DevWebSocket socket = sockets.remove(connectionKey); if (socket != null) { Uni uni = UniHelper.toUni(socket.socket.close()); diff --git a/independent-projects/extension-maven-plugin/pom.xml b/independent-projects/extension-maven-plugin/pom.xml index 58e411d44e4c9..d311962a02a9b 100644 --- a/independent-projects/extension-maven-plugin/pom.xml +++ b/independent-projects/extension-maven-plugin/pom.xml @@ -38,7 +38,7 @@ 11 11 3.9.8 - 2.17.1 + 2.17.2 1.5.2 5.10.2 diff --git a/independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/scanning/ResteasyReactiveScanner.java b/independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/scanning/ResteasyReactiveScanner.java index cbb3f8f91dbad..e97bacc60b9a9 100644 --- a/independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/scanning/ResteasyReactiveScanner.java +++ b/independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/scanning/ResteasyReactiveScanner.java @@ -262,6 +262,22 @@ public static ResourceScanningResult scanResources( } } + // handle abstract classes + var abstractClasses = scannedResources.values().stream().filter(ClassInfo::isAbstract).toList(); + abstractClasses.forEach(abstractScannedResource -> { + Collection allSubclasses = index.getAllKnownSubclasses(abstractScannedResource.name()); + if (allSubclasses.size() != 1) { + return; // don't do anything with this case as it's not evident how it's supposed to be handled + } + ClassInfo subclass = allSubclasses.iterator().next(); + if (!scannedResources.containsKey(subclass.name())) { + scannedResources.put(subclass.name(), subclass); + scannedResources.remove(abstractScannedResource.name()); + scannedResourcePaths.put(subclass.name(), scannedResourcePaths.get(abstractScannedResource.name())); + scannedResourcePaths.remove(abstractScannedResource.name()); + } + }); + Map clientInterfaces = new HashMap<>(pathInterfaces); // for clients it is enough to have @PATH annotations on methods only for (DotName interfaceName : interfacesWithPathOnMethods) { diff --git a/independent-projects/resteasy-reactive/pom.xml b/independent-projects/resteasy-reactive/pom.xml index e835ae4c528b3..a0c6c5cb6097a 100644 --- a/independent-projects/resteasy-reactive/pom.xml +++ b/independent-projects/resteasy-reactive/pom.xml @@ -61,7 +61,7 @@ 4.5.7 5.4.0 1.0.0.Final - 2.17.1 + 2.17.2 2.6.0 3.0.2 3.0.3 diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/jaxrs/AsyncResponseImpl.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/jaxrs/AsyncResponseImpl.java index 23f4964be8ea0..1e307e0349cbb 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/jaxrs/AsyncResponseImpl.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/jaxrs/AsyncResponseImpl.java @@ -153,7 +153,7 @@ public Map, Collection>> register(Class callback, Class. Objects.requireNonNull(callback); Objects.requireNonNull(callbacks); Map, Collection>> ret = new HashMap<>(); - ret.put(callback.getClass(), register(callback)); + ret.put(callback, register(callback)); for (Class cb : callbacks) { ret.put(cb, register(cb)); } diff --git a/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus/buildtool/gradle-kotlin-dsl/base/gradle.tpl.qute.properties b/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus/buildtool/gradle-kotlin-dsl/base/gradle.tpl.qute.properties index d3160667382c5..80d94672c2262 100644 --- a/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus/buildtool/gradle-kotlin-dsl/base/gradle.tpl.qute.properties +++ b/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus/buildtool/gradle-kotlin-dsl/base/gradle.tpl.qute.properties @@ -1,6 +1,7 @@ -#Gradle properties +# Gradle properties + quarkusPluginId={quarkus.gradle-plugin.id} quarkusPluginVersion={quarkus.gradle-plugin.version} quarkusPlatformGroupId={quarkus.platform.group-id} quarkusPlatformArtifactId={quarkus.platform.artifact-id} -quarkusPlatformVersion={quarkus.platform.version} \ No newline at end of file +quarkusPlatformVersion={quarkus.platform.version} diff --git a/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus/buildtool/gradle/base/gradle.tpl.qute.properties b/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus/buildtool/gradle/base/gradle.tpl.qute.properties index d3160667382c5..80d94672c2262 100644 --- a/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus/buildtool/gradle/base/gradle.tpl.qute.properties +++ b/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus/buildtool/gradle/base/gradle.tpl.qute.properties @@ -1,6 +1,7 @@ -#Gradle properties +# Gradle properties + quarkusPluginId={quarkus.gradle-plugin.id} quarkusPluginVersion={quarkus.gradle-plugin.version} quarkusPlatformGroupId={quarkus.platform.group-id} quarkusPlatformArtifactId={quarkus.platform.artifact-id} -quarkusPlatformVersion={quarkus.platform.version} \ No newline at end of file +quarkusPlatformVersion={quarkus.platform.version} diff --git a/independent-projects/tools/devtools-common/pom.xml b/independent-projects/tools/devtools-common/pom.xml index 2e5832fddb6af..e7b70a29daea2 100644 --- a/independent-projects/tools/devtools-common/pom.xml +++ b/independent-projects/tools/devtools-common/pom.xml @@ -106,6 +106,10 @@ jakarta.enterprise jakarta.enterprise.cdi-api + + org.codejive + java-properties + org.junit.jupiter junit-jupiter diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/AbstractGradleBuildFile.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/AbstractGradleBuildFile.java index dd5ea2931ce1e..d9ad8bdb7eb79 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/AbstractGradleBuildFile.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/AbstractGradleBuildFile.java @@ -1,18 +1,19 @@ package io.quarkus.devtools.project.buildfile; import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.StringWriter; import java.io.UncheckedIOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; -import java.util.Properties; import java.util.Scanner; import java.util.concurrent.atomic.AtomicReference; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.codejive.properties.Properties; + import io.quarkus.maven.dependency.ArtifactCoords; import io.quarkus.maven.dependency.ArtifactKey; import io.quarkus.registry.catalog.ExtensionCatalog; @@ -47,22 +48,22 @@ public void writeToDisk() throws IOException { if (rootProjectPath != null) { Files.write(rootProjectPath.resolve(getSettingsGradlePath()), getModel().getRootSettingsContent().getBytes()); if (hasRootProjectFile(GRADLE_PROPERTIES_PATH)) { - try (ByteArrayOutputStream out = new ByteArrayOutputStream()) { - getModel().getRootPropertiesContent().store(out, "Gradle properties"); - Files.write(rootProjectPath.resolve(GRADLE_PROPERTIES_PATH), - out.toByteArray()); + try (StringWriter sw = new StringWriter()) { + getModel().getRootPropertiesContent().store(sw, "Gradle properties"); + Files.writeString(rootProjectPath.resolve(GRADLE_PROPERTIES_PATH), + sw.toString()); } } } else { writeToProjectFile(getSettingsGradlePath(), getModel().getSettingsContent().getBytes()); if (hasProjectFile(GRADLE_PROPERTIES_PATH)) { - try (ByteArrayOutputStream out = new ByteArrayOutputStream()) { - getModel().getPropertiesContent().store(out, "Gradle properties"); - writeToProjectFile(GRADLE_PROPERTIES_PATH, out.toByteArray()); + try (StringWriter sw = new StringWriter()) { + getModel().getPropertiesContent().store(sw, "Gradle properties"); + writeToProjectFile(GRADLE_PROPERTIES_PATH, sw.toString()); } } } - writeToProjectFile(getBuildGradlePath(), getModel().getBuildContent().getBytes()); + writeToProjectFile(getBuildGradlePath(), getModel().getBuildContent()); } static boolean containsProperty(ArtifactCoords coords) { diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/AbstractGradleBuildFilesCreator.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/AbstractGradleBuildFilesCreator.java index 5d6ad5618536f..e3c8f24cf8069 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/AbstractGradleBuildFilesCreator.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/AbstractGradleBuildFilesCreator.java @@ -8,9 +8,10 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.List; -import java.util.Properties; import java.util.concurrent.atomic.AtomicReference; +import org.codejive.properties.Properties; + import io.quarkus.devtools.project.QuarkusProject; import io.quarkus.devtools.project.buildfile.AbstractGradleBuildFile.Model; import io.quarkus.maven.dependency.ArtifactCoords; @@ -122,6 +123,10 @@ protected void writeToProjectFile(final String fileName, final byte[] content) t Files.write(quarkusProject.getProjectDirPath().resolve(fileName), content); } + protected void writeToProjectFile(final String fileName, final String content) throws IOException { + Files.writeString(quarkusProject.getProjectDirPath().resolve(fileName), content); + } + private void createProperties() throws IOException { final ExtensionCatalog platform = quarkusProject.getExtensionsCatalog(); Properties props = getModel().getPropertiesContent(); diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/BuildFile.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/BuildFile.java index a05d32b9e103a..ce9cb33e71f3f 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/BuildFile.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/BuildFile.java @@ -155,6 +155,10 @@ protected void writeToProjectFile(final String fileName, final byte[] content) t Files.write(projectDirPath.resolve(fileName), content); } + protected void writeToProjectFile(final String fileName, final String content) throws IOException { + Files.writeString(projectDirPath.resolve(fileName), content); + } + private Set getDependenciesKeys() throws IOException { return getDependencies().stream().map(ArtifactCoords::getKey).collect(Collectors.toSet()); } diff --git a/independent-projects/tools/pom.xml b/independent-projects/tools/pom.xml index ba3d735485840..9432bc380b5fe 100644 --- a/independent-projects/tools/pom.xml +++ b/independent-projects/tools/pom.xml @@ -49,7 +49,7 @@ 3.26.0 - 2.17.1 + 2.17.2 4.1.0 5.10.2 1.26.2 @@ -60,6 +60,7 @@ 3.2.0 2.0.2 4.2.1 + 0.0.7 registry-client @@ -175,6 +176,11 @@ jboss-logging ${jboss-logging.version} + + org.codejive + java-properties + ${java-properties.version} + org.junit.jupiter junit-jupiter diff --git a/integration-tests/gradle/src/main/resources/compile-only-lombok/gradle.properties b/integration-tests/gradle/src/main/resources/compile-only-lombok/gradle.properties index cac35f5608ec1..542d9cf933db7 100644 --- a/integration-tests/gradle/src/main/resources/compile-only-lombok/gradle.properties +++ b/integration-tests/gradle/src/main/resources/compile-only-lombok/gradle.properties @@ -1,6 +1,6 @@ -#Gradle properties -#Tue Aug 04 17:04:55 CEST 2020 +# Gradle properties + quarkusPlatformArtifactId=quarkus-bom quarkusPlatformGroupId=io.quarkus org.gradle.logging.level=INFO -lombokVersion=1.18.12 \ No newline at end of file +lombokVersion=1.18.12 diff --git a/integration-tests/gradle/src/main/resources/multi-module-included-build/gradle.properties b/integration-tests/gradle/src/main/resources/multi-module-included-build/gradle.properties index a0bb7cd4da3b4..0b9b349582ac3 100644 --- a/integration-tests/gradle/src/main/resources/multi-module-included-build/gradle.properties +++ b/integration-tests/gradle/src/main/resources/multi-module-included-build/gradle.properties @@ -1,4 +1,4 @@ -#Gradle properties -#Tue Aug 25 06:41:36 GMT 2020 +# Gradle properties + quarkusPlatformArtifactId=quarkus-bom quarkusPlatformGroupId=io.quarkus diff --git a/integration-tests/gradle/src/main/resources/multi-module-kotlin-project/gradle.properties b/integration-tests/gradle/src/main/resources/multi-module-kotlin-project/gradle.properties index b8ff81712a497..d54b9c8a6b92b 100644 --- a/integration-tests/gradle/src/main/resources/multi-module-kotlin-project/gradle.properties +++ b/integration-tests/gradle/src/main/resources/multi-module-kotlin-project/gradle.properties @@ -1,5 +1,5 @@ -#Gradle properties -#Wed May 06 08:31:08 UTC 2020 +# Gradle properties + quarkusPlatformArtifactId=quarkus-bom quarkusPlatformGroupId=io.quarkus diff --git a/integration-tests/gradle/src/main/resources/multi-module-with-empty-module/gradle.properties b/integration-tests/gradle/src/main/resources/multi-module-with-empty-module/gradle.properties index e6b64c6a56957..0b9b349582ac3 100644 --- a/integration-tests/gradle/src/main/resources/multi-module-with-empty-module/gradle.properties +++ b/integration-tests/gradle/src/main/resources/multi-module-with-empty-module/gradle.properties @@ -1,3 +1,4 @@ -#Gradle properties +# Gradle properties + quarkusPlatformArtifactId=quarkus-bom -quarkusPlatformGroupId=io.quarkus \ No newline at end of file +quarkusPlatformGroupId=io.quarkus diff --git a/integration-tests/jackson/src/main/java/io/quarkus/it/jackson/model/Mammal.java b/integration-tests/jackson/src/main/java/io/quarkus/it/jackson/model/Mammal.java index dc622346349f2..3fd7ff7f5f5ca 100644 --- a/integration-tests/jackson/src/main/java/io/quarkus/it/jackson/model/Mammal.java +++ b/integration-tests/jackson/src/main/java/io/quarkus/it/jackson/model/Mammal.java @@ -5,11 +5,14 @@ import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.databind.PropertyNamingStrategies; +import com.fasterxml.jackson.databind.annotation.JsonNaming; @JsonTypeInfo(use = NAME, include = PROPERTY) @JsonSubTypes({ @JsonSubTypes.Type(value = Elephant.class, name = "Elephant"), @JsonSubTypes.Type(value = Whale.class, name = "Whale"), }) +@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) public interface Mammal { } diff --git a/integration-tests/jackson/src/test/java/io/quarkus/it/jackson/JsonSubTypesResourceTest.java b/integration-tests/jackson/src/test/java/io/quarkus/it/jackson/JsonSubTypesResourceTest.java index fe1979b72db7a..16f25157b5976 100644 --- a/integration-tests/jackson/src/test/java/io/quarkus/it/jackson/JsonSubTypesResourceTest.java +++ b/integration-tests/jackson/src/test/java/io/quarkus/it/jackson/JsonSubTypesResourceTest.java @@ -23,5 +23,6 @@ void test() { .extract().response(); assertThat(response.jsonPath().getString("mammals[0].color")).isEqualTo("white"); assertThat(response.jsonPath().getString("mammals[1].continent")).isEqualTo("africa"); + assertThat(response.jsonPath().getString("mammals[1].horn_length")).isEqualTo("10"); } } diff --git a/integration-tests/opentelemetry-vertx-exporter/src/test/java/io/quarkus/it/opentelemetry/vertx/exporter/OtelCollectorLifecycleManager.java b/integration-tests/opentelemetry-vertx-exporter/src/test/java/io/quarkus/it/opentelemetry/vertx/exporter/OtelCollectorLifecycleManager.java index 1c2df7c6a0df1..bcb6bd7eda002 100644 --- a/integration-tests/opentelemetry-vertx-exporter/src/test/java/io/quarkus/it/opentelemetry/vertx/exporter/OtelCollectorLifecycleManager.java +++ b/integration-tests/opentelemetry-vertx-exporter/src/test/java/io/quarkus/it/opentelemetry/vertx/exporter/OtelCollectorLifecycleManager.java @@ -33,7 +33,8 @@ public class OtelCollectorLifecycleManager implements QuarkusTestResourceLifecycleManager { - private static final String COLLECTOR_IMAGE = "ghcr.io/open-telemetry/opentelemetry-java/otel-collector"; + private static final String COLLECTOR_IMAGE = "ghcr.io/open-telemetry/opentelemetry-java/" + + "otel-collector@sha256:0d928e02b0ef5abbba775da205eb102f58b29aa75ea623465ec42445dfc5c443"; private static final Integer COLLECTOR_OTLP_GRPC_PORT = 4317; private static final Integer COLLECTOR_OTLP_HTTP_PORT = 4318; private static final Integer COLLECTOR_OTLP_GRPC_MTLS_PORT = 5317; diff --git a/integration-tests/test-extension/extension/deployment/src/main/java/io/quarkus/extest/deployment/ControllerConfigurationBuildStep.java b/integration-tests/test-extension/extension/deployment/src/main/java/io/quarkus/extest/deployment/ControllerConfigurationBuildStep.java new file mode 100644 index 0000000000000..8e89f1256de0b --- /dev/null +++ b/integration-tests/test-extension/extension/deployment/src/main/java/io/quarkus/extest/deployment/ControllerConfigurationBuildStep.java @@ -0,0 +1,20 @@ +package io.quarkus.extest.deployment; + +import io.quarkus.arc.deployment.AdditionalBeanBuildItem; +import io.quarkus.deployment.annotations.BuildProducer; +import io.quarkus.deployment.annotations.BuildStep; +import io.quarkus.deployment.annotations.ExecutionTime; +import io.quarkus.deployment.annotations.Record; +import io.quarkus.extest.runtime.def.ControllerConfigurationProducer; +import io.quarkus.extest.runtime.def.ControllerConfigurationRecorder; +import io.quarkus.extest.runtime.def.QuarkusControllerConfiguration; + +public class ControllerConfigurationBuildStep { + + @BuildStep + @Record(ExecutionTime.RUNTIME_INIT) + public void record(ControllerConfigurationRecorder recorder, BuildProducer producer) { + producer.produce(AdditionalBeanBuildItem.builder().addBeanClasses(ControllerConfigurationProducer.class).build()); + recorder.setControllerConfiguration(new QuarkusControllerConfiguration("test1", "test2")); + } +} diff --git a/integration-tests/test-extension/extension/deployment/src/test/java/io/quarkus/def/ControllerConfigurationTest.java b/integration-tests/test-extension/extension/deployment/src/test/java/io/quarkus/def/ControllerConfigurationTest.java new file mode 100644 index 0000000000000..8538a8d2c859d --- /dev/null +++ b/integration-tests/test-extension/extension/deployment/src/test/java/io/quarkus/def/ControllerConfigurationTest.java @@ -0,0 +1,35 @@ +package io.quarkus.def; + +import static org.assertj.core.api.Assertions.assertThat; + +import jakarta.inject.Inject; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.extest.runtime.def.ControllerConfiguration; +import io.quarkus.extest.runtime.def.QuarkusControllerConfiguration; +import io.quarkus.test.QuarkusUnitTest; + +public class ControllerConfigurationTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .withEmptyApplication(); + + @Inject + ControllerConfiguration controllerConfiguration; + + @Test + public void test() { + assertThat(controllerConfiguration).isInstanceOfSatisfying(QuarkusControllerConfiguration.class, + quarkusControllerConfiguration -> { + assertThat(quarkusControllerConfiguration.getName()).isEqualTo("test1"); + assertThat(quarkusControllerConfiguration.getResourceTypeName()).isEqualTo("test2"); + assertThat(controllerConfiguration.getNamespaces()).containsOnly("foo", "bar"); + assertThat(controllerConfiguration.getInformerListLimit()).isEmpty(); + }); + + } + +} diff --git a/integration-tests/test-extension/extension/runtime/src/main/java/io/quarkus/extest/runtime/def/ControllerConfiguration.java b/integration-tests/test-extension/extension/runtime/src/main/java/io/quarkus/extest/runtime/def/ControllerConfiguration.java new file mode 100644 index 0000000000000..3c95427b9c1b5 --- /dev/null +++ b/integration-tests/test-extension/extension/runtime/src/main/java/io/quarkus/extest/runtime/def/ControllerConfiguration.java @@ -0,0 +1,8 @@ +package io.quarkus.extest.runtime.def; + +public interface ControllerConfiguration extends ResourceConfiguration { + + default String getName() { + return "name"; + } +} diff --git a/integration-tests/test-extension/extension/runtime/src/main/java/io/quarkus/extest/runtime/def/ControllerConfigurationProducer.java b/integration-tests/test-extension/extension/runtime/src/main/java/io/quarkus/extest/runtime/def/ControllerConfigurationProducer.java new file mode 100644 index 0000000000000..4cf319b5c24c8 --- /dev/null +++ b/integration-tests/test-extension/extension/runtime/src/main/java/io/quarkus/extest/runtime/def/ControllerConfigurationProducer.java @@ -0,0 +1,11 @@ +package io.quarkus.extest.runtime.def; + +import jakarta.inject.Singleton; + +public class ControllerConfigurationProducer { + + @Singleton + public ControllerConfiguration produce() { + return ControllerConfigurationRecorder.controllerConfiguration; + } +} diff --git a/integration-tests/test-extension/extension/runtime/src/main/java/io/quarkus/extest/runtime/def/ControllerConfigurationRecorder.java b/integration-tests/test-extension/extension/runtime/src/main/java/io/quarkus/extest/runtime/def/ControllerConfigurationRecorder.java new file mode 100644 index 0000000000000..00b9ce1e760e2 --- /dev/null +++ b/integration-tests/test-extension/extension/runtime/src/main/java/io/quarkus/extest/runtime/def/ControllerConfigurationRecorder.java @@ -0,0 +1,13 @@ +package io.quarkus.extest.runtime.def; + +import io.quarkus.runtime.annotations.Recorder; + +@Recorder +public class ControllerConfigurationRecorder { + + public static volatile ControllerConfiguration controllerConfiguration; + + public void setControllerConfiguration(QuarkusControllerConfiguration controllerConfiguration) { + ControllerConfigurationRecorder.controllerConfiguration = controllerConfiguration; + } +} diff --git a/integration-tests/test-extension/extension/runtime/src/main/java/io/quarkus/extest/runtime/def/QuarkusControllerConfiguration.java b/integration-tests/test-extension/extension/runtime/src/main/java/io/quarkus/extest/runtime/def/QuarkusControllerConfiguration.java new file mode 100644 index 0000000000000..55eb7689b14bc --- /dev/null +++ b/integration-tests/test-extension/extension/runtime/src/main/java/io/quarkus/extest/runtime/def/QuarkusControllerConfiguration.java @@ -0,0 +1,24 @@ +package io.quarkus.extest.runtime.def; + +import io.quarkus.runtime.annotations.RecordableConstructor; + +public class QuarkusControllerConfiguration implements ControllerConfiguration { + + private final String name; + private final String resourceTypeName; + + @RecordableConstructor + public QuarkusControllerConfiguration(String name, String resourceTypeName) { + this.name = name; + this.resourceTypeName = resourceTypeName; + } + + @Override + public String getName() { + return name; + } + + public String getResourceTypeName() { + return resourceTypeName; + } +} diff --git a/integration-tests/test-extension/extension/runtime/src/main/java/io/quarkus/extest/runtime/def/ResourceConfiguration.java b/integration-tests/test-extension/extension/runtime/src/main/java/io/quarkus/extest/runtime/def/ResourceConfiguration.java new file mode 100644 index 0000000000000..8244e21e124e1 --- /dev/null +++ b/integration-tests/test-extension/extension/runtime/src/main/java/io/quarkus/extest/runtime/def/ResourceConfiguration.java @@ -0,0 +1,19 @@ +package io.quarkus.extest.runtime.def; + +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; + +public interface ResourceConfiguration { + + default Set getNamespaces() { + HashSet set = new HashSet<>(); + set.add("foo"); + set.add("bar"); + return set; + } + + default Optional getInformerListLimit() { + return Optional.empty(); + } +} diff --git a/pom.xml b/pom.xml index 38d0eecf473a4..a20c1b2742848 100644 --- a/pom.xml +++ b/pom.xml @@ -69,7 +69,7 @@ 0.8.12 - 6.13.0 + 6.13.1 5.4.0 6.5.2.Final 4.13.0 diff --git a/test-framework/common/src/main/java/io/quarkus/test/common/DefaultDockerContainerLauncher.java b/test-framework/common/src/main/java/io/quarkus/test/common/DefaultDockerContainerLauncher.java index 2d01ef727fd4a..533048d795934 100644 --- a/test-framework/common/src/main/java/io/quarkus/test/common/DefaultDockerContainerLauncher.java +++ b/test-framework/common/src/main/java/io/quarkus/test/common/DefaultDockerContainerLauncher.java @@ -118,7 +118,9 @@ public void start() throws IOException { args.add("-i"); // Interactive, write logs to stdout args.add("--rm"); - args.addAll(NativeImageBuildLocalContainerRunner.getVolumeAccessArguments(containerRuntime)); + if (!volumeMounts.isEmpty()) { + args.addAll(NativeImageBuildLocalContainerRunner.getVolumeAccessArguments(containerRuntime)); + } args.add("-p"); args.add(httpPort + ":" + httpPort);