Skip to content

Commit

Permalink
Merge pull request #37254 from gsmet/3.6.0-backports-2
Browse files Browse the repository at this point in the history
3.6.0 backports 2
  • Loading branch information
gsmet authored Nov 22, 2023
2 parents a81f4c0 + 6a23739 commit 96fcda4
Show file tree
Hide file tree
Showing 90 changed files with 1,374 additions and 146 deletions.
5 changes: 3 additions & 2 deletions .github/workflows/ci-actions-incremental.yml
Original file line number Diff line number Diff line change
Expand Up @@ -732,6 +732,7 @@ jobs:
path: |
**/target/*-reports/TEST-*.xml
target/build-report.json
**/target/gradle-build-scan-url.txt
LICENSE.txt
retention-days: 2
- name: Save Build Scan
Expand Down Expand Up @@ -926,7 +927,7 @@ jobs:
path: |
**/target/*-reports/TEST-*.xml
target/build-report.json
target/gradle-build-scan-url.txt
**/target/gradle-build-scan-url.txt
LICENSE.txt
retention-days: 2
- name: Save Build Scan
Expand Down Expand Up @@ -1023,7 +1024,7 @@ jobs:
**/target/*-reports/TEST-*.xml
**/build/test-results/test/TEST-*.xml
target/build-report.json
target/gradle-build-scan-url.txt
**/target/gradle-build-scan-url.txt
LICENSE.txt
retention-days: 2
- name: Save Build Scan
Expand Down
17 changes: 8 additions & 9 deletions .github/workflows/develocity-publish-build-scans.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,12 @@ jobs:
develocity-url: 'https://ge.quarkus.io'
develocity-access-key: ${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }}
skip-comment: true
- name: Push to summary
if: ${{ contains(fromJson(steps.extract-preapproved-developers.outputs.preapproved-developpers).preapproved-developers, github.event.workflow_run.actor.login) }}
- name: Inject build scans in reports
uses: quarkusio/action-helpers@main
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
action: inject-build-scans
workflow-run-id: ${{ github.event.workflow_run.id }}
- name: Output JSON file
run: |
echo -n "Pull request: " >> ${GITHUB_STEP_SUMMARY}
cat pr-number.out >> ${GITHUB_STEP_SUMMARY}
echo >> ${GITHUB_STEP_SUMMARY}
echo >> ${GITHUB_STEP_SUMMARY}
echo "| Job | Status | Build scan |" >> ${GITHUB_STEP_SUMMARY}
echo "|---|---|---|" >> ${GITHUB_STEP_SUMMARY}
cat publication.out >> ${GITHUB_STEP_SUMMARY}
if [ -f build-metadata.json ]; then jq '.' build-metadata.json >> $GITHUB_STEP_SUMMARY; fi
2 changes: 1 addition & 1 deletion .mvn/gradle-enterprise.xml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
</local>
<remote>
<enabled>true</enabled>
<storeEnabled>#{env['CI'] != null}</storeEnabled>
<storeEnabled>#{env['CI'] != null and env['GRADLE_ENTERPRISE_ACCESS_KEY'] != null and env['GRADLE_ENTERPRISE_ACCESS_KEY'] != ''}</storeEnabled>
</remote>
</buildCache>
</gradleEnterprise>
2 changes: 1 addition & 1 deletion bom/application/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@
<hamcrest.version>2.2</hamcrest.version><!-- The version needs to be compatible with both REST Assured and Awaitility -->
<junit.jupiter.version>5.10.0</junit.jupiter.version>
<junit-pioneer.version>1.5.0</junit-pioneer.version>
<infinispan.version>14.0.20.Final</infinispan.version>
<infinispan.version>14.0.21.Final</infinispan.version>
<infinispan.protostream.version>4.6.5.Final</infinispan.protostream.version>
<caffeine.version>3.1.5</caffeine.version>
<netty.version>4.1.100.Final</netty.version>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ public interface JavaVersion {

Status isJava17OrHigher();

Status isJava21OrHigher();

Status isJava19OrHigher();

enum Status {
Expand Down Expand Up @@ -58,6 +60,11 @@ public Status isJava17OrHigher() {
return Status.UNKNOWN;
}

@Override
public Status isJava21OrHigher() {
return Status.UNKNOWN;
}

@Override
public Status isJava19OrHigher() {
return Status.UNKNOWN;
Expand All @@ -69,6 +76,7 @@ final class Known implements JavaVersion {
private static final int JAVA_11_MAJOR = 55;
private static final int JAVA_17_MAJOR = 61;
private static final int JAVA_19_MAJOR = 63;
private static final int JAVA_21_MAJOR = 66;

private final int determinedMajor;

Expand Down Expand Up @@ -96,6 +104,11 @@ public Status isJava19OrHigher() {
return higherOrEqualStatus(JAVA_19_MAJOR);
}

@Override
public Status isJava21OrHigher() {
return higherOrEqualStatus(JAVA_21_MAJOR);
}

private Status higherOrEqualStatus(int javaMajor) {
return determinedMajor >= javaMajor ? Status.TRUE : Status.FALSE;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,13 +78,5 @@ protected void assertAppModel(ApplicationModel model) throws Exception {
expected.add(new ArtifactDependency(ArtifactCoords.jar("io.quarkus.bootstrap.test", "dep-g", "1"),
DependencyFlags.RUNTIME_CP, DependencyFlags.DEPLOYMENT_CP));
assertEquals(expected, getDependenciesWithFlag(model, DependencyFlags.RUNTIME_CP));

expected = new HashSet<>();
expected.add(new ArtifactDependency(ArtifactCoords.jar("io.quarkus.bootstrap.test", "ext-a-dep", "1"),
DependencyFlags.REMOVED));
expected.add(new ArtifactDependency(ArtifactCoords.jar("org.banned", "dep-e", "1"), DependencyFlags.REMOVED));
expected.add(new ArtifactDependency(ArtifactCoords.jar("org.banned.too", "dep-d", "1"), DependencyFlags.REMOVED));
expected.add(new ArtifactDependency(ArtifactCoords.jar("org.banned", "dep-f", "1"), DependencyFlags.REMOVED));
assertEquals(expected, getDependenciesWithFlag(model, DependencyFlags.REMOVED));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,10 @@ private static boolean getRootlessStateFor(ContainerRuntime containerRuntime) {
final Predicate<String> stringPredicate;
// Docker includes just "rootless" under SecurityOptions, while podman includes "rootless: <boolean>"
if (containerRuntime == ContainerRuntime.DOCKER) {
stringPredicate = line -> line.trim().equals("rootless");
// We also treat Docker Desktop as "rootless" since the way it binds mounts does not
// transparently map the host user ID and GID
// see https://docs.docker.com/desktop/faqs/linuxfaqs/#how-do-i-enable-file-sharing
stringPredicate = line -> line.trim().equals("rootless") || line.contains("desktop-linux");
} else {
stringPredicate = line -> line.trim().equals("rootless: true");
}
Expand Down
2 changes: 1 addition & 1 deletion docs/src/main/asciidoc/building-native-image.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -532,7 +532,7 @@ The project generation has also provided a `Dockerfile.native` in the `src/main/

[source,dockerfile]
----
FROM registry.access.redhat.com/ubi8/ubi-minimal:8.8
FROM registry.access.redhat.com/ubi8/ubi-minimal:8.9
WORKDIR /work/
RUN chown 1001 /work \
&& chmod "g+rwX" /work \
Expand Down
6 changes: 3 additions & 3 deletions docs/src/main/asciidoc/container-image.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ For example, the presence of `src/main/jib/foo/bar` would result in `/foo/bar`

There are cases where the built container image may need to have Java debugging conditionally enabled at runtime.

When the base image has not been changed (and therefore `ubi8/openjdk-11-runtime` or `ubi8/openjdk-17-runtime` is used), then the `quarkus.jib.jvm-arguments` configuration property can be used in order to
When the base image has not been changed (and therefore `ubi8/openjdk-11-runtime`, `ubi8/openjdk-17-runtime`, or `ubi8/openjdk-21-runtime` is used), then the `quarkus.jib.jvm-arguments` configuration property can be used in order to
make the JVM listen on the debug port at startup.

The exact configuration is:
Expand All @@ -63,7 +63,7 @@ Other base images might provide launch scripts that enable debugging when an env

The `quarkus.jib.jvm-entrypoint` configuration property can be used to completely override the container entry point and can thus be used to either hard code the JVM debug configuration or point to a script that handles the details.

For example, if the base images `ubi8/openjdk-11-runtime` or `ubi8/openjdk-17-runtime` are used to build the container, the entry point can be hard-coded on the application properties file.
For example, if the base images `ubi8/openjdk-11-runtime`, `ubi8/openjdk-17-runtime` or `ubi8/openjdk-21-runtime` are used to build the container, the entry point can be hard-coded on the application properties file.

.Example application.properties
[source,properties]
Expand All @@ -88,7 +88,7 @@ java \
-jar quarkus-run.jar
----

NOTE: `/home/jboss` is the WORKDIR for all quarkus binaries in the base images `ubi8/openjdk-11-runtime` and `ubi8/openjdk-17-runtime` (https://catalog.redhat.com/software/containers/ubi8/openjdk-17/618bdbf34ae3739687568813?container-tabs=dockerfile[Dockerfile for ubi8/openjdk-17-runtime, window="_blank"])
NOTE: `/home/jboss` is the WORKDIR for all quarkus binaries in the base images `ubi8/openjdk-11-runtime`, `ubi8/openjdk-17-runtime` and `ubi8/openjdk-21-runtime` (https://catalog.redhat.com/software/containers/ubi8/openjdk-17/618bdbf34ae3739687568813?container-tabs=dockerfile[Dockerfile for ubi8/openjdk-17-runtime, window="_blank"])

==== Multi-module projects and layering

Expand Down
6 changes: 3 additions & 3 deletions docs/src/main/asciidoc/kotlin.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -470,9 +470,9 @@ import io.fabric8.kubernetes.client.utils.Serialization
import com.fasterxml.jackson.module.kotlin.KotlinModule
...
Serialization.jsonMapper().registerModule(KotlinModule())
Serialization.yamlMapper().registerModule(KotlinModule())
val kotlinModule = KotlinModule.Builder().build()
Serialization.jsonMapper().registerModule(kotlinModule)
Serialization.yamlMapper().registerModule(kotlinModule)
----

_Please test this carefully on compilation to native images and fallback to Java-compatible Jackson bindings if you experience problems._
Expand Down
6 changes: 3 additions & 3 deletions docs/src/main/asciidoc/quarkus-runtime-base-image.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ In this case, you need to use a multi-stage `dockerfile` to copy the required li
[source, dockerfile]
----
# First stage - install the dependencies in an intermediate container
FROM registry.access.redhat.com/ubi8/ubi-minimal:8.8 as BUILD
FROM registry.access.redhat.com/ubi8/ubi-minimal:8.9 as BUILD
RUN microdnf install freetype
# Second stage - copy the dependencies
Expand All @@ -62,7 +62,7 @@ If you need to have access to the full AWT support, you need more than just `lib
[source, dockerfile]
----
# First stage - install the dependencies in an intermediate container
FROM registry.access.redhat.com/ubi8/ubi-minimal:8.8 as BUILD
FROM registry.access.redhat.com/ubi8/ubi-minimal:8.9 as BUILD
RUN microdnf install freetype fontconfig
# Second stage - copy the dependencies
Expand Down Expand Up @@ -112,7 +112,7 @@ To use this base image, use the following `Dockerfile`:

[source, dockerfile]
----
FROM registry.access.redhat.com/ubi8/ubi-minimal:8.8
FROM registry.access.redhat.com/ubi8/ubi-minimal:8.9
WORKDIR /work/
RUN chown 1001 /work \
&& chmod "g+rwX" /work \
Expand Down
101 changes: 101 additions & 0 deletions docs/src/main/asciidoc/rest-client-reactive.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -883,6 +883,107 @@ If you use a `CompletionStage`, you would need to call the service's method to r
This difference comes from the laziness aspect of Mutiny and its subscription protocol.
More details about this can be found in https://smallrye.io/smallrye-mutiny/latest/reference/uni-and-multi/[the Mutiny documentation].

=== Server-Sent Event (SSE) support

Consuming SSE events is possible simply by declaring the result type as a `io.smallrye.mutiny.Multi`.

The simplest example is:

[source, java]
----
package org.acme.rest.client;
import io.smallrye.mutiny.Multi;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
@Path("/sse")
@RegisterRestClient(configKey = "some-api")
public interface SseClient {
@GET
@Produces(MediaType.SERVER_SENT_EVENTS)
Multi<String> get();
}
----

[NOTE]
====
All the IO involved in streaming the SSE results is done in a non-blocking manner.
====

Results are not limited to strings - for example when the server returns JSON payload for each event, Quarkus automatically deserializes it into the generic type used in the `Multi`.

[TIP]
====
Users can also access the entire SSE event by using the `org.jboss.resteasy.reactive.client.SseEvent` type.
A simple example where the event payloads are `Long` values is the following:
[source, java]
----
package org.acme.rest.client;
import io.smallrye.mutiny.Uni;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import org.jboss.resteasy.reactive.client.SseEvent;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.QueryParam;
@Path("/sse")
@RegisterRestClient(configKey = "some-api")
public interface SseClient {
@GET
@Produces(MediaType.SERVER_SENT_EVENTS)
Multi<SseEvent<Long>> get();
}
----
====

==== Filtering out events

On occasion, the stream of SSE events may contain some events that should not be returned by the client - an example of this is having the server send heartbeat events in order to keep the underlying TCP connection open.
The REST Client supports filtering out such events by providing the `@org.jboss.resteasy.reactive.client.SseEventFilter`.

Here is an example of filtering out heartbeat events:

[source,java]
----
package org.acme.rest.client;
import io.smallrye.mutiny.Uni;
import java.util.function.Predicate;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import org.jboss.resteasy.reactive.client.SseEvent;
import org.jboss.resteasy.reactive.client.SseEventFilter;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.QueryParam;
@Path("/sse")
@RegisterRestClient(configKey = "some-api")
public interface SseClient {
@GET
@Produces(MediaType.SERVER_SENT_EVENTS)
@SseEventFilter(HeartbeatFilter.class)
Multi<SseEvent<Long>> get();
class HeartbeatFilter implements Predicate<SessionEvent<String>> {
@Override
public boolean test(SseEvent<String> event) {
return !"heartbeat".equals(event.id());
}
}
}
----

== Custom headers support

There are a few ways in which you can specify custom headers for your REST calls:
Expand Down
25 changes: 23 additions & 2 deletions docs/src/main/asciidoc/resteasy-reactive.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -1301,6 +1301,8 @@ public class Person {
private final Long id;
private final String first;
private final String last;
@SecureField(rolesAllowed = ${role:admin}") <1>
private String address;
public Person(Long id, String first, String last) {
this.id = id;
Expand All @@ -1319,8 +1321,20 @@ public class Person {
public String getLast() {
return last;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
----
<1> The `io.quarkus.resteasy.reactive.jackson.SecureField.rolesAllowed` property supports xref:config-reference.adoc#property-expressions[property expressions]
exactly in the same fashion the `jakarta.annotation.security.RolesAllowed` annotation does. For more information, please
refer to the xref:security-authorize-web-endpoints-reference.adoc#standard-security-annotations[Standard security annotations]
section of the Authorization of web endpoints guide.

A very simple Jakarta REST Resource that uses `Person` could be:

Expand All @@ -1337,7 +1351,7 @@ public class Person {
@Path("{id}")
@GET
public Person getPerson(Long id) {
return new Person(id, "foo", "bar");
return new Person(id, "foo", "bar", "Brick Lane");
}
}
----
Expand All @@ -1350,7 +1364,8 @@ performs an HTTP GET on `/person/1` they will receive:
{
"id": 1,
"first": "foo",
"last": "bar"
"last": "bar",
"address", "Brick Lane"
}
----

Expand All @@ -1369,6 +1384,8 @@ Any user however that does not have the `admin` role will receive:
NOTE: No additional configuration needs to be applied for this secure serialization to take place. However, users can use the `@io.quarkus.resteasy.reactive.jackson.EnableSecureSerialization` and `@io.quarkus.resteasy.reactive.jackson.DisableSecureSerialization`
annotation to opt in or out for specific Jakarta REST Resource classes or methods.

WARNING: Configuration expressions set with the `SecureField.rolesAllowed` property are validated during application startup even when the `@io.quarkus.resteasy.reactive.jackson.DisableSecureSerialization` annotation is used.

===== @JsonView support

Jakarta REST methods can be annotated with https://fasterxml.github.io/jackson-annotations/javadoc/2.10/com/fasterxml/jackson/annotation/JsonView.html[@JsonView]
Expand Down Expand Up @@ -2989,6 +3006,10 @@ public class RuntimeResource {
}
}
----
[IMPORTANT]
====
This feature does not work when using native build.
====


== RESTEasy Reactive client
Expand Down
4 changes: 2 additions & 2 deletions docs/src/main/asciidoc/virtual-threads.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -349,10 +349,10 @@ To containerize your Quarkus application that use `@RunOnVirtualThread`, add the
quarkus.container-image.build=true
quarkus.container-image.group=<your-group-name>
quarkus.container-image.name=<you-container-name>
quarkus.jib.base-jvm-image=eclipse-temurin:21-ubi9-minimal <1>
quarkus.jib.base-jvm-image=registry.access.redhat.com/ubi8/openjdk-21-runtime <1>
quarkus.jib.platforms=linux/amd64,linux/arm64 <2>
----
<1> Make sure you use a base image supporting virtual threads. Here we use an image providing Java 21.
<1> Make sure you use a base image supporting virtual threads. Here we use an image providing Java 21. Quarkus picks an image providing Java 21+ automatically if you do not set one.
<2> Select the target architecture. You can select more than one to build multi-archs images.

Then, build your container as you would do usually.
Expand Down
Loading

0 comments on commit 96fcda4

Please sign in to comment.