Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

3.6.4 backports 1 #37815

Merged
merged 13 commits into from
Dec 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/ci-actions-incremental.yml
Original file line number Diff line number Diff line change
Expand Up @@ -835,7 +835,9 @@ jobs:
# We do this so we can get better analytics for the downloaded version of the build images
- name: Update Docker Client User Agent
run: |
cat <<< $(jq '.HttpHeaders += {"User-Agent": "Quarkus-CI-Docker-Client"}' ~/.docker/config.json) > ~/.docker/config.json
if [ -f ~/.docker/config.json ]; then
cat <<< $(jq '.HttpHeaders += {"User-Agent": "Quarkus-CI-Docker-Client"}' ~/.docker/config.json) > ~/.docker/config.json
fi
- name: Build
env:
TEST_MODULES: ${{matrix.test-modules}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1309,12 +1309,14 @@ boolean isRestartNeeded(String changedFile) {
}
}
// Then try to match a new file that was added to a resource root
Boolean ret = watchedFilePaths.get(changedFile);
Boolean ret = watchedFilePaths != null ? watchedFilePaths.get(changedFile) : null;
if (ret == null) {
ret = false;
for (Entry<Predicate<String>, Boolean> e : watchedFilePredicates) {
if (e.getKey().test(changedFile)) {
ret = ret || e.getValue();
ret = Boolean.FALSE;
if (watchedFilePredicates != null) {
for (Entry<Predicate<String>, Boolean> e : watchedFilePredicates) {
if (e.getKey().test(changedFile)) {
ret = ret || e.getValue();
}
}
}
}
Expand Down
45 changes: 29 additions & 16 deletions devtools/cli/src/main/java/io/quarkus/cli/QuarkusCli.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import java.util.Optional;
import java.util.concurrent.Callable;
import java.util.function.Supplier;
import java.util.stream.Collectors;

import jakarta.inject.Inject;

Expand Down Expand Up @@ -96,7 +97,9 @@ public int run(String... args) throws Exception {
boolean pluginCommand = args.length >= 1 && (args[0].equals("plug") || args[0].equals("plugin"));

try {
boolean existingCommand = checkMissingCommand(cmd, args).isEmpty();
Optional<String> missingCommand = checkMissingCommand(cmd, args);

boolean existingCommand = missingCommand.isEmpty();
// If the command already exists and is not a help command (that lists subcommands) or plugin command, then just execute
// without dealing with plugins.
// The reason that we check if its a plugin command is that plugin commands need PluginManager initialization.
Expand All @@ -108,8 +111,7 @@ public int run(String... args) throws Exception {
pluginManager.syncIfNeeded();
Map<String, Plugin> plugins = new HashMap<>(pluginManager.getInstalledPlugins());
pluginCommandFactory.populateCommands(cmd, plugins);
Optional<String> missing = checkMissingCommand(cmd, args);
missing.ifPresent(m -> {
missingCommand.ifPresent(m -> {
try {
Map<String, Plugin> installable = pluginManager.getInstallablePlugins();
if (installable.containsKey(m)) {
Expand All @@ -119,11 +121,13 @@ public int run(String... args) throws Exception {
output.info("Command %s not installed but the following plugin is available:\n%s", m,
table.getContent());
if (interactiveMode && Prompt.yesOrNo(true,
"Would you like to install it now ?",
"Would you like to install it now?",
args)) {
pluginManager.addPlugin(m).ifPresent(added -> plugins.put(added.getName(), added));
pluginCommandFactory.populateCommands(cmd, plugins);
}
} else {
output.error("Command %s is missing and can't be installed.", m);
}
} catch (Exception e) {
output.error("Command %s is missing and can't be installed.", m);
Expand All @@ -136,7 +140,7 @@ public int run(String... args) throws Exception {
}

/**
* Recursivelly processes the arguments passed to the command and checks wether a subcommand is missing.
* Process the arguments passed and return an identifier of the potentially missing subcommand if any.
*
* @param root the root command
* @param args the arguments passed to the root command
Expand All @@ -148,17 +152,26 @@ public Optional<String> checkMissingCommand(CommandLine root, String[] args) {
}

try {
ParseResult result = root.parseArgs(args);
if (args.length == 1) {
return Optional.empty();
}
CommandLine next = root.getSubcommands().get(args[0]);
if (next == null) {
return Optional.of(args[0]);
}
String[] remaining = new String[args.length - 1];
System.arraycopy(args, 1, remaining, 0, remaining.length);
return checkMissingCommand(next, remaining).map(nextMissing -> root.getCommandName() + "-" + nextMissing);
ParseResult currentParseResult = root.parseArgs(args);
StringBuilder missingCommand = new StringBuilder();

do {
if (missingCommand.length() > 0) {
missingCommand.append("-");
}
missingCommand.append(currentParseResult.commandSpec().name());

List<String> unmatchedSubcommands = currentParseResult.unmatched().stream()
.filter(u -> !u.startsWith("-")).collect(Collectors.toList());
if (!unmatchedSubcommands.isEmpty()) {
missingCommand.append("-").append(unmatchedSubcommands.get(0));
return Optional.of(missingCommand.toString());
}

currentParseResult = currentParseResult.subcommand();
} while (currentParseResult != null);

return Optional.empty();
} catch (UnmatchedArgumentException e) {
return Optional.of(args[0]);
}
Expand Down
1 change: 0 additions & 1 deletion docs/src/main/asciidoc/deploying-to-google-cloud.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,6 @@ Finally, you need to configure your datasource specifically to use the socket fa
----
quarkus.datasource.db-kind=postgresql
quarkus.datasource.jdbc.url=jdbc:postgresql:///mydatabase <1>
quarkus.datasource.jdbc.driver=org.postgresql.Driver
quarkus.datasource.username=quarkus
quarkus.datasource.password=quarkus
quarkus.datasource.jdbc.additional-jdbc-properties.cloudSqlInstance=project-id:gcp-region:instance <2>
Expand Down
2 changes: 1 addition & 1 deletion docs/src/main/asciidoc/mongodb-panache.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -746,10 +746,10 @@

[source,properties]
----
quarkus.log.category."io.quarkus.mongodb.panache.runtime".level=DEBUG
quarkus.log.category."io.quarkus.mongodb.panache.common.runtime".level=DEBUG

Check warning on line 749 in docs/src/main/asciidoc/mongodb-panache.adoc

View workflow job for this annotation

GitHub Actions / Linting with Vale

[vale] reported by reviewdog 🐶 [Quarkus.Headings] Use sentence-style capitalization in 'The PojoCodecProvider: easy object to BSON document conversion.'. Raw Output: {"message": "[Quarkus.Headings] Use sentence-style capitalization in 'The PojoCodecProvider: easy object to BSON document conversion.'.", "location": {"path": "docs/src/main/asciidoc/mongodb-panache.adoc", "range": {"start": {"line": 749, "column": 65}}}, "severity": "INFO"}
----

== The PojoCodecProvider: easy object to BSON document conversion.

Check warning on line 752 in docs/src/main/asciidoc/mongodb-panache.adoc

View workflow job for this annotation

GitHub Actions / Linting with Vale

[vale] reported by reviewdog 🐶 [Quarkus.HeadingPunctuation] Do not use end punctuation in headings. Raw Output: {"message": "[Quarkus.HeadingPunctuation] Do not use end punctuation in headings.", "location": {"path": "docs/src/main/asciidoc/mongodb-panache.adoc", "range": {"start": {"line": 752, "column": 43}}}, "severity": "INFO"}

MongoDB with Panache uses the link:{mongodb-doc-root-url}/fundamentals/data-formats/document-data-format-pojo/[PojoCodecProvider], with link:{mongodb-doc-root-url}/fundamentals/data-formats/document-data-format-pojo/#configure-the-driver-for-pojos[automatic POJO support],
to automatically convert your object to a BSON document.
Expand Down
2 changes: 1 addition & 1 deletion docs/src/main/asciidoc/rabbitmq-reference.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -714,7 +714,7 @@ Type: _boolean_ | false | `false`

Type: _string_ | false | `#`

| [.no-hyphens]#*content-type-override*# | Override the content_type attribute of the incoming message, should be a valid MINE type
| [.no-hyphens]#*content-type-override*# | Override the content_type attribute of the incoming message, should be a valid MIME type

Type: _string_ | false |

Expand Down
3 changes: 2 additions & 1 deletion docs/src/main/asciidoc/security-csrf-prevention.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@
:topics: security,csrf,http
:extensions: io.quarkus:quarkus-csrf-reactive

https://owasp.org/www-community/attacks/csrf[Cross-Site Request Forgery (CSRF)] is an attack that forces an end user to execute unwanted actions on a web application in which they are currently authenticated.

Check warning on line 12 in docs/src/main/asciidoc/security-csrf-prevention.adoc

View workflow job for this annotation

GitHub Actions / Linting with Vale

[vale] reported by reviewdog 🐶 [Quarkus.TermsSuggestions] Depending on the context, consider using ', which (non restrictive clause preceded by a comma)' or 'that (restrictive clause without a comma)' rather than 'which'. Raw Output: {"message": "[Quarkus.TermsSuggestions] Depending on the context, consider using ', which (non restrictive clause preceded by a comma)' or 'that (restrictive clause without a comma)' rather than 'which'.", "location": {"path": "docs/src/main/asciidoc/security-csrf-prevention.adoc", "range": {"start": {"line": 12, "column": 169}}}, "severity": "INFO"}

Quarkus Security provides a CSRF prevention feature which implements https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#double-submit-cookie[Double Submit Cookie] and [CSRF Request Header] techniques.
Quarkus Security provides a CSRF prevention feature which implements https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#double-submit-cookie[Double Submit Cookie] and <<csrf-request-header>> techniques.

Check warning on line 14 in docs/src/main/asciidoc/security-csrf-prevention.adoc

View workflow job for this annotation

GitHub Actions / Linting with Vale

[vale] reported by reviewdog 🐶 [Quarkus.TermsSuggestions] Depending on the context, consider using ', which (non restrictive clause preceded by a comma)' or 'that (restrictive clause without a comma)' rather than 'which'. Raw Output: {"message": "[Quarkus.TermsSuggestions] Depending on the context, consider using ', which (non restrictive clause preceded by a comma)' or 'that (restrictive clause without a comma)' rather than 'which'.", "location": {"path": "docs/src/main/asciidoc/security-csrf-prevention.adoc", "range": {"start": {"line": 14, "column": 52}}}, "severity": "INFO"}

`Double Submit Cookie` technique requires that the CSRF token sent as `HTTPOnly`, optionally signed, cookie to the client, and

Check warning on line 16 in docs/src/main/asciidoc/security-csrf-prevention.adoc

View workflow job for this annotation

GitHub Actions / Linting with Vale

[vale] reported by reviewdog 🐶 [Quarkus.SentenceLength] Try to keep sentences to an average of 32 words or fewer. Raw Output: {"message": "[Quarkus.SentenceLength] Try to keep sentences to an average of 32 words or fewer.", "location": {"path": "docs/src/main/asciidoc/security-csrf-prevention.adoc", "range": {"start": {"line": 16, "column": 24}}}, "severity": "INFO"}
directly embedded in a hidden form input of server-side rendered HTML forms, or submitted as a request header value.

Check warning on line 17 in docs/src/main/asciidoc/security-csrf-prevention.adoc

View workflow job for this annotation

GitHub Actions / Linting with Vale

[vale] reported by reviewdog 🐶 [Quarkus.TermsSuggestions] Depending on the context, consider using 'because' or 'while' rather than 'as'. Raw Output: {"message": "[Quarkus.TermsSuggestions] Depending on the context, consider using 'because' or 'while' rather than 'as'.", "location": {"path": "docs/src/main/asciidoc/security-csrf-prevention.adoc", "range": {"start": {"line": 17, "column": 91}}}, "severity": "INFO"}

The extension consists of a xref:resteasy-reactive.adoc[RESTEasy Reactive] server filter which creates and verifies CSRF tokens in `application/x-www-form-urlencoded` and `multipart/form-data` forms and a Qute HTML form parameter provider which supports the xref:qute-reference.adoc#injecting-beans-directly-in-templates[injection of CSRF tokens in Qute templates].

Expand Down Expand Up @@ -139,9 +139,10 @@
quarkus.csrf-reactive.token-signature-key=AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow
----

[[csrf-request-header]]
== CSRF Request Header

If HTML `form` tags are not used and you need to pass CSRF token as a header, then inject the header name and token, for example, into HTMX:

Check warning on line 145 in docs/src/main/asciidoc/security-csrf-prevention.adoc

View workflow job for this annotation

GitHub Actions / Linting with Vale

[vale] reported by reviewdog 🐶 [Quarkus.Fluff] Depending on the context, consider using 'Rewrite the sentence, or use 'must', instead of' rather than 'need to'. Raw Output: {"message": "[Quarkus.Fluff] Depending on the context, consider using 'Rewrite the sentence, or use 'must', instead of' rather than 'need to'.", "location": {"path": "docs/src/main/asciidoc/security-csrf-prevention.adoc", "range": {"start": {"line": 145, "column": 42}}}, "severity": "INFO"}

Check warning on line 145 in docs/src/main/asciidoc/security-csrf-prevention.adoc

View workflow job for this annotation

GitHub Actions / Linting with Vale

[vale] reported by reviewdog 🐶 [Quarkus.TermsSuggestions] Depending on the context, consider using 'because' or 'while' rather than 'as'. Raw Output: {"message": "[Quarkus.TermsSuggestions] Depending on the context, consider using 'because' or 'while' rather than 'as'.", "location": {"path": "docs/src/main/asciidoc/security-csrf-prevention.adoc", "range": {"start": {"line": 145, "column": 66}}}, "severity": "INFO"}

[source,html]
----
Expand Down
4 changes: 2 additions & 2 deletions docs/src/main/asciidoc/security-getting-started-tutorial.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -462,9 +462,9 @@ As you can see in this code sample, you do not need to start the test container

[NOTE]
====
When you start your application in dev mode, `Dev Services for PostgreSQL` launches a `PostgreSQL` `devmode` container so that you can start developing your application.
When you start your application in dev mode, Dev Services for PostgreSQL launches a PostgreSQL dev mode container so that you can start developing your application.
While developing your application, you can add tests one by one and run them using the xref:continuous-testing.adoc[Continuous Testing] feature.
`Dev Services for PostgreSQL` supports testing while you develop by providing a separate `PostgreSQL` test container that does not conflict with the `devmode` container.
Dev Services for PostgreSQL supports testing while you develop by providing a separate PostgreSQL test container that does not conflict with the dev mode container.
====

=== Use Curl or a browser to test your application
Expand Down
4 changes: 2 additions & 2 deletions docs/src/main/asciidoc/security-oidc-auth0-tutorial.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -914,7 +914,7 @@
}
----

If you recall, when the application was started in devmode, the following could be seen in the CLI window:
If you recall, when the application was started in dev mode, the following could be seen in the CLI window:

image::auth0-devmode-started.png[Auth0 DevMode started]

Expand Down Expand Up @@ -1075,7 +1075,7 @@

== Troubleshooting

The steps described in this tutorial should work exactly as the tutorial describes. You might have to clear the browser cookies when accessing the updated Quarkus endpoint if you have already completed the authentication. You might need to restart the Quarkus application manually in devmode but it is not expected. If you need help completing this tutorial, you can get in touch with the Quarkus team.
The steps described in this tutorial should work exactly as the tutorial describes. You might have to clear the browser cookies when accessing the updated Quarkus endpoint if you have already completed the authentication. You might need to restart the Quarkus application manually in dev mode but it is not expected. If you need help completing this tutorial, you can get in touch with the Quarkus team.

Check warning on line 1078 in docs/src/main/asciidoc/security-oidc-auth0-tutorial.adoc

View workflow job for this annotation

GitHub Actions / Linting with Vale

[vale] reported by reviewdog 🐶 [Quarkus.TermsSuggestions] Depending on the context, consider using 'because' or 'while' rather than 'as'. Raw Output: {"message": "[Quarkus.TermsSuggestions] Depending on the context, consider using 'because' or 'while' rather than 'as'.", "location": {"path": "docs/src/main/asciidoc/security-oidc-auth0-tutorial.adoc", "range": {"start": {"line": 1078, "column": 58}}}, "severity": "INFO"}

Check warning on line 1078 in docs/src/main/asciidoc/security-oidc-auth0-tutorial.adoc

View workflow job for this annotation

GitHub Actions / Linting with Vale

[vale] reported by reviewdog 🐶 [Quarkus.Fluff] Depending on the context, consider using 'Rewrite the sentence, or use 'must', instead of' rather than 'need to'. Raw Output: {"message": "[Quarkus.Fluff] Depending on the context, consider using 'Rewrite the sentence, or use 'must', instead of' rather than 'need to'.", "location": {"path": "docs/src/main/asciidoc/security-oidc-auth0-tutorial.adoc", "range": {"start": {"line": 1078, "column": 233}}}, "severity": "INFO"}

== Summary

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ To make Dev UI more useful for supporting the development of OIDC `web-app` appl
It will ensure that all Dev UI options described in <<develop-service-applications,Developing OpenID Connect Service Applications>> will be available when your `web-app` application is run in dev mode. The limitation of this approach is that both access and ID tokens returned with the code flow and acquired with Dev UI will be sent to the endpoint as HTTP `Bearer` tokens - which will not work well if your endpoint requires the injection of `IdToken`.
However, it will work as expected if your `web-app` application only uses the access token, for example, as a source of roles or to get `UserInfo`, even if it is assumed to be a `service` application in dev mode.

Even a better option is to use a `hybrid` application type in devmode:
Even a better option is to use a `hybrid` application type in dev mode:

[source,properties]
----
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ public class CustomTenantResolver implements TenantResolver {

You can define multiple tenants in your configuration file, just make sure they have a unique alias so that you can map them properly when resolving a tenant from your `TenantResolver` implementation.

However, using a static tenant resolution (configuring tenants in `application.properties` and resolving them with `TenantResolver`) prevents testing the endpoint with `Dev Services for Keycloak` since `Dev Services for Keycloak` has no knowledge of how the requests will be mapped to individual tenants and can not dynamically provide tenant-specific `quarkus.oidc.<tenant-id>.auth-server-url` values and therefore using `%prod` prefixes with the tenant-specific URLs in `application.properties` will not work in tests or devmode.
However, using a static tenant resolution (configuring tenants in `application.properties` and resolving them with `TenantResolver`) prevents testing the endpoint with `Dev Services for Keycloak` since `Dev Services for Keycloak` has no knowledge of how the requests will be mapped to individual tenants and can not dynamically provide tenant-specific `quarkus.oidc.<tenant-id>.auth-server-url` values and therefore using `%prod` prefixes with the tenant-specific URLs in `application.properties` will not work in test or dev mode.

[NOTE]
====
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -662,7 +662,7 @@ The pattern of authenticating with a given provider, where the endpoint uses eit

== HTTPS Redirect URL

Some providers will only accept HTTPS-based redirect URLs. Tools such as https://ngrok.com/[ngrok] https://linuxhint.com/set-up-use-ngrok/[can be set up] to help testing such providers with Quarkus endpoints running on localhost in devmode.
Some providers will only accept HTTPS-based redirect URLs. Tools such as https://ngrok.com/[ngrok] https://linuxhint.com/set-up-use-ngrok/[can be set up] to help testing such providers with Quarkus endpoints running on localhost in dev mode.

== Rate Limiting

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,6 @@ public void filter(ResteasyReactiveContainerRequestContext requestContext, Routi

String cookieToken = getCookieToken(routing, config);
if (cookieToken != null) {
routing.put(CSRF_TOKEN_KEY, cookieToken);

try {
int cookieTokenSize = Base64.getUrlDecoder().decode(cookieToken).length;
// HMAC SHA256 output is 32 bytes long
Expand Down Expand Up @@ -98,10 +96,10 @@ public void filter(ResteasyReactiveContainerRequestContext requestContext, Routi
// unsafe HTTP method, token is required

// Check the header first
String csrfTokenInHeader = requestContext.getHeaderString(config.tokenHeaderName);
if (csrfTokenInHeader != null) {
String csrfTokenHeaderParam = requestContext.getHeaderString(config.tokenHeaderName);
if (csrfTokenHeaderParam != null) {
LOG.debugf("CSRF token found in the token header");
verifyCsrfToken(requestContext, routing, config, cookieToken, csrfTokenInHeader);
verifyCsrfToken(requestContext, routing, config, cookieToken, csrfTokenHeaderParam);
return;
}

Expand All @@ -128,9 +126,9 @@ public void filter(ResteasyReactiveContainerRequestContext requestContext, Routi

ResteasyReactiveRequestContext rrContext = (ResteasyReactiveRequestContext) requestContext
.getServerRequestContext();
String csrfToken = (String) rrContext.getFormParameter(config.formFieldName, true, false);
String csrfTokenFormParam = (String) rrContext.getFormParameter(config.formFieldName, true, false);
LOG.debugf("CSRF token found in the form parameter");
verifyCsrfToken(requestContext, routing, config, cookieToken, csrfToken);
verifyCsrfToken(requestContext, routing, config, cookieToken, csrfTokenFormParam);
return;

} else if (cookieToken == null) {
Expand Down Expand Up @@ -159,6 +157,7 @@ private void verifyCsrfToken(ResteasyReactiveContainerRequestContext requestCont
requestContext.abortWith(badClientRequest());
return;
} else {
routing.put(CSRF_TOKEN_KEY, csrfToken);
routing.put(CSRF_TOKEN_VERIFIED, true);
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import io.vertx.core.datagram.DatagramSocketOptions;
import io.vertx.core.http.HttpClientOptions;
import io.vertx.core.http.HttpServerOptions;
import io.vertx.core.impl.NoStackTraceException;
import io.vertx.core.metrics.MetricsOptions;
import io.vertx.core.net.NetClientOptions;
import io.vertx.core.net.NetServerOptions;
Expand Down Expand Up @@ -60,7 +61,7 @@ public MetricsOptions newOptions() {
@Override
public HttpServerMetrics<?, ?, ?> createHttpServerMetrics(HttpServerOptions options, SocketAddress localAddress) {
if (httpBinderConfiguration == null) {
throw new IllegalStateException("HttpBinderConfiguration was not found");
throw new NoStackTraceException("HttpBinderConfiguration was not found");
}
if (httpBinderConfiguration.isServerEnabled()) {
log.debugf("Create HttpServerMetrics with options %s and address %s", options, localAddress);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
import static java.lang.String.format;
import static org.assertj.core.api.Assertions.assertThat;

import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.net.URI;
import java.util.List;
import java.util.Map;
Expand All @@ -13,17 +17,24 @@
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Priorities;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.WebApplicationException;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.HttpHeaders;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.MultivaluedHashMap;
import jakarta.ws.rs.core.MultivaluedMap;
import jakarta.ws.rs.ext.ContextResolver;

import org.eclipse.microprofile.rest.client.annotation.RegisterProvider;
import org.eclipse.microprofile.rest.client.ext.ClientHeadersFactory;
import org.jboss.resteasy.reactive.server.jackson.JacksonBasicMessageBodyReader;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import com.fasterxml.jackson.databind.ObjectMapper;

import io.quarkus.rest.client.reactive.QuarkusRestClientBuilder;
import io.quarkus.rest.client.reactive.TestJacksonBasicMessageBodyReader;
import io.quarkus.test.QuarkusUnitTest;
Expand Down Expand Up @@ -78,6 +89,7 @@ public Map<String, List<String>> callClient(String uri) {
}
}

@RegisterProvider(ErroneousJacksonBasicMessageBodyReader.class)
public interface Client {
@GET
Map<String, List<String>> get();
Expand All @@ -101,6 +113,20 @@ public ClientHeadersFactory getContext(Class<?> aClass) {
}
}

@Priority(Priorities.USER + 100)
public static class ErroneousJacksonBasicMessageBodyReader extends JacksonBasicMessageBodyReader {
public ErroneousJacksonBasicMessageBodyReader() {
super(new ObjectMapper());
}

@Override
public Object readFrom(Class<Object> type, Type genericType, Annotation[] annotations, MediaType mediaType,
MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
throws IOException, WebApplicationException {
throw new IllegalStateException("should never be called");
}
}

public static class CustomClientHeadersFactory implements ClientHeadersFactory {

private final String value;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ public final class Types {
// TODO: add a extensible banning mechanism based on predicates if we find that this set needs to grow...
private static final Set<DotName> BANNED_INTERFACE_TYPES = new HashSet<>(
Arrays.asList(DotName.createSimple("java.lang.constant.ConstantDesc"),
DotName.createSimple("java.lang.constant.Constable")));
DotName.createSimple("java.lang.constant.Constable"),
DotName.createSimple("java.util.SequencedCollection")));

private Types() {
}
Expand Down
Loading
Loading