diff --git a/.github/workflows/jakarta-rewrite.yml b/.github/workflows/jakarta-rewrite.yml index 1ed7e6bd1e668..15dd7060ac114 100644 --- a/.github/workflows/jakarta-rewrite.yml +++ b/.github/workflows/jakarta-rewrite.yml @@ -37,7 +37,7 @@ jobs: - name: Push changes to jakarta-rewrite uses: ad-m/github-push-action@v0.6.0 with: - github_token: ${{ secrets.GITHUB_TOKEN }} + github_token: ${{ secrets.JAKARTA_PUSH_PAT }} force: true branch: jakarta-rewrite - name: Report status diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 51d9e75518606..9e5c941822792 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -50,7 +50,7 @@ 1.2.2 1.0.13 2.7.0 - 2.21.0 + 2.22.0 3.16.0 1.1.2 1.2.1 @@ -134,7 +134,7 @@ 4.1.74.Final 1.0.3 3.5.0.Final - 1.4.0 + 1.5.0 3.1.0 1.8.0 1.1.8.4 @@ -159,7 +159,7 @@ 1.30 6.0.0 4.3.4 - 1.4.0 + 1.2.1 0.33.10 3.14.9 0.1.1 diff --git a/core/deployment/src/main/java/io/quarkus/deployment/index/IndexingUtil.java b/core/deployment/src/main/java/io/quarkus/deployment/index/IndexingUtil.java index a6f2246150d5e..210d3cd3a0b24 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/index/IndexingUtil.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/index/IndexingUtil.java @@ -254,7 +254,7 @@ public Index apply(PathVisit visit) { "Can't read Jandex index from " + visit.getPath() + ": " + e.getMessage()); } } catch (IOException e) { - throw new UncheckedIOException(e); + throw new UncheckedIOException("Can't read Jandex index from " + visit.getPath(), e); } } } diff --git a/docs/src/main/asciidoc/deploying-to-openshift.adoc b/docs/src/main/asciidoc/deploying-to-openshift.adoc index b9f7033128284..a96b5fe5f0274 100644 --- a/docs/src/main/asciidoc/deploying-to-openshift.adoc +++ b/docs/src/main/asciidoc/deploying-to-openshift.adoc @@ -361,7 +361,7 @@ quarkus.openshift.deployment-kind=Deployment ---- Since `Deployment` is a Kubernetes resource and not Openshift specific, it can't possibly leverage `ImageStream` resources, as is the case with `DeploymentConfig`. This means that the image references need to include the container image registry that hosts the image. -When the image is built, using Openshift builds (s2i binary and docker strategy) the Openshift internral image registry `image-registry.openshift-image-registry.svc:5000` will be used, unless an other registry has been explicitly specified by the user. Please note, that in the internal registry the project/namespace name is added as part of the image repository: `image-registry.openshift-image-registry.svc:5000//:`, so users will need to make sure that the target project/namespace name is aligned with the `quarkus.container-image.group`. +When the image is built, using Openshift builds (s2i binary and docker strategy) the Openshift internal image registry `image-registry.openshift-image-registry.svc:5000` will be used, unless an other registry has been explicitly specified by the user. Please note, that in the internal registry the project/namespace name is added as part of the image repository: `image-registry.openshift-image-registry.svc:5000//:`, so users will need to make sure that the target project/namespace name is aligned with the `quarkus.container-image.group`. [source,properties] ---- diff --git a/docs/src/main/asciidoc/includes/devtools/prerequisites.adoc b/docs/src/main/asciidoc/includes/devtools/prerequisites.adoc index c64c71b5f951d..d49cc9236379c 100644 --- a/docs/src/main/asciidoc/includes/devtools/prerequisites.adoc +++ b/docs/src/main/asciidoc/includes/devtools/prerequisites.adoc @@ -16,7 +16,7 @@ ifdef::prerequisites-docker[] * A working container runtime (Docker or Podman) endif::[] ifdef::prerequisites-docker-compose[] -* Docker and Docker Compose +* Docker and Docker Compose or xref:podman.adoc[Podman], and Docker Compose endif::[] ifndef::prerequisites-no-cli[] * Optionally the xref:cli-tooling.adoc[Quarkus CLI] if you want to use it diff --git a/docs/src/main/asciidoc/opentelemetry.adoc b/docs/src/main/asciidoc/opentelemetry.adoc index e1425fecb6d57..15bd64498b475 100644 --- a/docs/src/main/asciidoc/opentelemetry.adoc +++ b/docs/src/main/asciidoc/opentelemetry.adoc @@ -107,13 +107,15 @@ quarkus.opentelemetry.enabled=true // <2> quarkus.opentelemetry.tracer.exporter.otlp.endpoint=http://localhost:4317 // <3> quarkus.opentelemetry.tracer.exporter.otlp.headers=Authorization=Bearer my_secret // <4> + +quarkus.log.console.format=%d{HH:mm:ss} %-5p traceId=%X{traceId}, parentId=%X{parentId}, spanId=%X{spanId}, sampled=%X{sampled} [%c{2.}] (%t) %s%e%n // <5> ---- <1> All spans created from the application will include an OpenTelemetry `Resource` indicating the span was created by the `myservice` application. If not set, it will default to the artifact id. <2> Whether OpenTelemetry is enabled or not. The default is `true`, but shown here to indicate how it can be disabled <3> gRPC endpoint for sending spans <4> Optional gRPC headers commonly used for authentication - +<5> Add tracing information into log message. == Run the application The first step is to configure and start the https://opentelemetry.io/docs/collector/[OpenTelemetry Collector] to receive, process and export telemetry data to https://www.jaegertracing.io/[Jaeger] that will display the captured traces. @@ -199,6 +201,16 @@ $ curl http://localhost:8080/hello hello ---- +When the first request has been submitted, you will be able to see the tracing information in the logs: + +[source] +---- +10:49:02 INFO traceId=, parentId=, spanId=, sampled= [io.quarkus] (main) Installed features: [cdi, opentelemetry, opentelemetry-otlp-exporter, rest-client, resteasy, smallrye-context-propagation, vertx] +10:49:03 INFO traceId=17ceb8429b9f25b0b879fa1503259456, parentId=3125c8bee75b7ad6, spanId=58ce77c86dd23457, sampled=true [or.ac.op.TracedResource] (executor-thread-1) hello +10:49:03 INFO traceId=ad23acd6d9a4ed3d1de07866a52fa2df, parentId=, spanId=df13f5b45cf4d1e2, sampled=true [or.ac.op.TracedResource] (executor-thread-0) hello +---- + + Then visit the http://localhost:16686[Jaeger UI] to see the tracing information. Hit `CTRL+C` to stop the application. diff --git a/docs/src/main/asciidoc/podman.adoc b/docs/src/main/asciidoc/podman.adoc new file mode 100644 index 0000000000000..ca8268f6ed5bb --- /dev/null +++ b/docs/src/main/asciidoc/podman.adoc @@ -0,0 +1,77 @@ +//// +This guide is maintained in the main Quarkus repository +and pull requests should be submitted there: +https://github.com/quarkusio/quarkus/tree/main/docs/src/main/asciidoc +//// += Using Podman with Quarkus + +https://podman.io/[Podman] is a daemonless and rootless container engine for developing, managing, and running OCI Containers on your Linux system or other OS. +Podman can be used the same way as Docker with the `podman-docker` package. + +== Installing Podman on Linux + +The Podman package is available in several Linux distributions. To install it for your OS, please refer to the https://podman.io/getting-started/installation[Podman installation guide]. +Below is the short installation instruction for popular Linux distributions: + +.Fedora +[source,bash] +---- +sudo dnf install podman podman-docker docker-compose +---- +.Ubuntu (21.04 and later) +[source,bash] +---- +sudo apt install podman podman-docker docker-compose +---- + +=== After installation + +Podman is a daemonless container engine. Most Quarkus Dev Services and Testcontainers expect a running Docker daemon listening at a Unix socket. +That's why the following steps are required. +[source,bash] +---- +# Enable the podman socket with Docker REST API +systemctl --user enable podman.socket --now +# Set the required envvars +export DOCKER_HOST=unix:///run/user/${UID}/podman/podman.sock +export TESTCONTAINERS_RYUK_DISABLED=true +---- +For a detailed explanation, see this https://quarkus.io/blog/quarkus-devservices-testcontainers-podman/[blog article]. + +To make changes permanent, add the exported environment variables to the "init" file from your shell. For example, the `bash` shell uses the `~/.bashrc` file: +[source,bash] +---- +echo "export DOCKER_HOST=unix:///run/user/${UID}/podman/podman.sock" >> ~/.bashrc +echo "export TESTCONTAINERS_RYUK_DISABLED=true" >> ~/.bashrc +---- + +=== Short names of images + +Testcontainers and Quarkus Dev Services also expect the container service they make requests against to be non-interactive. +In case you have multiple registries configured in your Docker or Podman configuration, and when using short image names, Podman responds with a prompt asking which registry should be used to pull images. + +While we recommend you to avoid short names and always use fully specified names including the registry, +Testcontainers unfortunately relies on short names internally for the time being. +If you are using Testcontainers, either directly or through Dev Services, +you need to disable this prompt by setting the `short-name-mode="disabled"` configuration property of Podman in `/etc/containers/registries.conf`. + +== Other operating systems + +Containers are really Linux. As such, Linux containers cannot run natively on macOS or Windows. +Therefore, the containers must run in a Linux virtual machine (VM), and a Podman client interacts with that VM. +So a native hypervisor subsystem and virtualization software is used to run the Linux VM on the OS, and then containers are run within this VM. + +.macOS +macOS users can install Podman through https://brew.sh/[Homebrew]. Once you have set up `brew`, you can use the `brew install` command to install Podman and `docker-compose`: +[source,bash] +---- +brew install podman +brew install docker-compose +podman machine init +podman machine start +alias docker='podman' +---- +For more details, please see the https://podman.io/getting-started/installation#macos[official Podman documentation] and this https://www.redhat.com/sysadmin/replace-docker-podman-macos[article]. + +.Windows +Please see the https://github.com/containers/podman/blob/main/docs/tutorials/podman-for-windows.md[Podman for Windows guide] for setup and usage instructions. diff --git a/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/PersistenceUnitUtil.java b/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/PersistenceUnitUtil.java index 8c0d3306e4711..d106f3be75d20 100644 --- a/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/PersistenceUnitUtil.java +++ b/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/PersistenceUnitUtil.java @@ -1,5 +1,6 @@ package io.quarkus.hibernate.orm.runtime; +import java.util.Comparator; import java.util.Locale; import javax.enterprise.inject.Default; @@ -37,6 +38,19 @@ public static InjectableInstance extensionInstanceForPersistenceUnit(Clas new PersistenceUnitExtension.Literal(persistenceUnitName)); } + public static class PersistenceUnitNameComparator implements Comparator { + @Override + public int compare(String o1, String o2) { + if (DEFAULT_PERSISTENCE_UNIT_NAME.equals(o1)) { + return -1; + } else if (DEFAULT_PERSISTENCE_UNIT_NAME.equals(o2)) { + return +1; + } else { + return o1.compareTo(o2); + } + } + } + @Deprecated public static InjectableInstance legacySingleExtensionInstanceForPersistenceUnit(Class beanType, String persistenceUnitName) { diff --git a/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/devconsole/HibernateOrmDevConsoleInfoSupplier.java b/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/devconsole/HibernateOrmDevConsoleInfoSupplier.java index 70592fc418bf3..d50a1ab2c8d30 100644 --- a/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/devconsole/HibernateOrmDevConsoleInfoSupplier.java +++ b/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/devconsole/HibernateOrmDevConsoleInfoSupplier.java @@ -5,7 +5,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.Comparator; import java.util.EnumSet; import java.util.List; import java.util.Map; @@ -24,9 +23,9 @@ import org.hibernate.tool.schema.spi.ScriptTargetOutput; import org.hibernate.tool.schema.spi.TargetDescriptor; -public class HibernateOrmDevConsoleInfoSupplier implements Supplier { +import io.quarkus.hibernate.orm.runtime.PersistenceUnitUtil; - private static final String DEFAULT = ""; +public class HibernateOrmDevConsoleInfoSupplier implements Supplier { public static final PersistenceUnitsInfo INSTANCE = new PersistenceUnitsInfo(); @@ -99,7 +98,7 @@ public PersistenceUnitsInfo get() { public static class PersistenceUnitsInfo { private final Map persistenceUnits = Collections - .synchronizedMap(new TreeMap<>(new PersistenceUnitNameComparator())); + .synchronizedMap(new TreeMap<>(new PersistenceUnitUtil.PersistenceUnitNameComparator())); public Collection getPersistenceUnits() { return persistenceUnits.values(); @@ -229,17 +228,4 @@ public String getType() { } } - - static class PersistenceUnitNameComparator implements Comparator { - @Override - public int compare(String o1, String o2) { - if (DEFAULT.equals(o1)) { - return -1; - } else if (DEFAULT.equals(o2)) { - return +1; - } else { - return o1.compareTo(o2); - } - } - } } diff --git a/extensions/hibernate-orm/runtime/src/test/java/io/quarkus/hibernate/orm/runtime/devconsole/PersistenceUnitNameComparatorTestCase.java b/extensions/hibernate-orm/runtime/src/test/java/io/quarkus/hibernate/orm/runtime/devconsole/PersistenceUnitNameComparatorTestCase.java index 00a0b9b651826..7dfbe219d7978 100644 --- a/extensions/hibernate-orm/runtime/src/test/java/io/quarkus/hibernate/orm/runtime/devconsole/PersistenceUnitNameComparatorTestCase.java +++ b/extensions/hibernate-orm/runtime/src/test/java/io/quarkus/hibernate/orm/runtime/devconsole/PersistenceUnitNameComparatorTestCase.java @@ -7,6 +7,8 @@ import org.junit.jupiter.api.Test; +import io.quarkus.hibernate.orm.runtime.PersistenceUnitUtil; + public class PersistenceUnitNameComparatorTestCase { @Test @@ -16,7 +18,7 @@ public void puNameComparatorTest() { names.add("alpha"); names.add(""); names.add("beta"); - names.sort(new HibernateOrmDevConsoleInfoSupplier.PersistenceUnitNameComparator()); + names.sort(new PersistenceUnitUtil.PersistenceUnitNameComparator()); assertThat(names.get(0)).isEqualTo(""); assertThat(names.get(1)).isEqualTo("alpha"); diff --git a/extensions/hibernate-search-orm-elasticsearch/deployment/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/devconsole/HibernateSearchElasticsearchDevConsoleProcessor.java b/extensions/hibernate-search-orm-elasticsearch/deployment/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/devconsole/HibernateSearchElasticsearchDevConsoleProcessor.java index 416d65953587a..92246810a801d 100644 --- a/extensions/hibernate-search-orm-elasticsearch/deployment/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/devconsole/HibernateSearchElasticsearchDevConsoleProcessor.java +++ b/extensions/hibernate-search-orm-elasticsearch/deployment/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/devconsole/HibernateSearchElasticsearchDevConsoleProcessor.java @@ -3,12 +3,17 @@ import static io.quarkus.deployment.annotations.ExecutionTime.RUNTIME_INIT; import static io.quarkus.deployment.annotations.ExecutionTime.STATIC_INIT; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + import io.quarkus.deployment.IsDevelopment; import io.quarkus.deployment.annotations.BuildStep; import io.quarkus.deployment.annotations.Record; import io.quarkus.deployment.pkg.builditem.CurateOutcomeBuildItem; import io.quarkus.devconsole.spi.DevConsoleRouteBuildItem; import io.quarkus.devconsole.spi.DevConsoleRuntimeTemplateInfoBuildItem; +import io.quarkus.hibernate.search.orm.elasticsearch.HibernateSearchElasticsearchPersistenceUnitConfiguredBuildItem; import io.quarkus.hibernate.search.orm.elasticsearch.runtime.HibernateSearchElasticsearchRuntimeConfig; import io.quarkus.hibernate.search.orm.elasticsearch.runtime.devconsole.HibernateSearchDevConsoleRecorder; @@ -18,9 +23,13 @@ public class HibernateSearchElasticsearchDevConsoleProcessor { @Record(RUNTIME_INIT) public DevConsoleRuntimeTemplateInfoBuildItem collectBeanInfo(HibernateSearchDevConsoleRecorder recorder, HibernateSearchElasticsearchRuntimeConfig runtimeConfig, - CurateOutcomeBuildItem curateOutcomeBuildItem) { - return new DevConsoleRuntimeTemplateInfoBuildItem("indexedEntityTypes", - recorder.infoSupplier(runtimeConfig), this.getClass(), curateOutcomeBuildItem); + CurateOutcomeBuildItem curateOutcomeBuildItem, + List peristenceUnitBuildItems) { + Set persistenceUnitNames = peristenceUnitBuildItems.stream() + .map(HibernateSearchElasticsearchPersistenceUnitConfiguredBuildItem::getPersistenceUnitName) + .collect(Collectors.toSet()); + return new DevConsoleRuntimeTemplateInfoBuildItem("indexedPersistenceUnits", + recorder.infoSupplier(runtimeConfig, persistenceUnitNames), this.getClass(), curateOutcomeBuildItem); } @BuildStep diff --git a/extensions/hibernate-search-orm-elasticsearch/deployment/src/main/resources/dev-templates/embedded.html b/extensions/hibernate-search-orm-elasticsearch/deployment/src/main/resources/dev-templates/embedded.html index 10c92d629e123..9cc1a072f0350 100644 --- a/extensions/hibernate-search-orm-elasticsearch/deployment/src/main/resources/dev-templates/embedded.html +++ b/extensions/hibernate-search-orm-elasticsearch/deployment/src/main/resources/dev-templates/embedded.html @@ -1,4 +1,7 @@ + + + Persistence units {info:indexedPersistenceUnits.persistenceUnits.size} - Indexed entity types {info:indexedEntityTypes.size()} + Indexed Entities {info:indexedPersistenceUnits.numberOfIndexedEntities}
diff --git a/extensions/hibernate-search-orm-elasticsearch/deployment/src/main/resources/dev-templates/entity-types.html b/extensions/hibernate-search-orm-elasticsearch/deployment/src/main/resources/dev-templates/entity-types.html index 079f27d7783c2..fd6cdcbffbff0 100644 --- a/extensions/hibernate-search-orm-elasticsearch/deployment/src/main/resources/dev-templates/entity-types.html +++ b/extensions/hibernate-search-orm-elasticsearch/deployment/src/main/resources/dev-templates/entity-types.html @@ -1,11 +1,14 @@ {#include main} {#title}Indexed Entities{/title} {#body} -{#if info:indexedEntityTypes.isEmpty} +{#if info:indexedPersistenceUnits.persistenceUnits.isEmpty}

No indexed entities were found.

{#else}
- + +
+ {#for indexedPersistenceUnit in info:indexedPersistenceUnits.persistenceUnits} +

Persistence Unit {indexedPersistenceUnit.persistenceUnitName}

@@ -16,7 +19,7 @@ @@ -24,11 +27,12 @@ - {#for indexedEntityType in info:indexedEntityTypes} + {#for indexedEntityType in indexedPersistenceUnit.indexedEntities} @@ -37,15 +41,13 @@ {/for}
- +
Entity name
- +
{indexedEntityType.jpaName}
+ {/for}
{/if} {/body} diff --git a/extensions/hibernate-search-orm-elasticsearch/runtime/pom.xml b/extensions/hibernate-search-orm-elasticsearch/runtime/pom.xml index 1f48eef3c9b0b..e166cddc4de24 100644 --- a/extensions/hibernate-search-orm-elasticsearch/runtime/pom.xml +++ b/extensions/hibernate-search-orm-elasticsearch/runtime/pom.xml @@ -38,6 +38,14 @@ javax.persistence javax.persistence-api + + + jakarta.activation + jakarta.activation-api + diff --git a/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/devconsole/HibernateSearchDevConsoleRecorder.java b/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/devconsole/HibernateSearchDevConsoleRecorder.java index 1a7d66cd2554b..deff448a12de3 100644 --- a/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/devconsole/HibernateSearchDevConsoleRecorder.java +++ b/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/devconsole/HibernateSearchDevConsoleRecorder.java @@ -2,6 +2,8 @@ import java.time.Duration; import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -19,9 +21,9 @@ @Recorder public class HibernateSearchDevConsoleRecorder { - public Supplier> infoSupplier( - HibernateSearchElasticsearchRuntimeConfig runtimeConfig) { - return new HibernateSearchSupplier(runtimeConfig); + public Supplier infoSupplier( + HibernateSearchElasticsearchRuntimeConfig runtimeConfig, Set persistenceUnitNames) { + return new HibernateSearchSupplier(runtimeConfig, persistenceUnitNames); } public Handler indexEntity() { @@ -31,19 +33,25 @@ protected void handlePostAsync(RoutingContext event, MultiMap form) throws Excep if (form.isEmpty()) { return; } - SearchMapping mapping = HibernateSearchSupplier.searchMapping(); - if (mapping == null) { + Set persitenceUnitNames = form.entries().stream().map(Map.Entry::getValue) + .collect(Collectors.toSet()); + Map mappings = HibernateSearchSupplier.searchMapping(persitenceUnitNames); + if (mappings.isEmpty()) { flashMessage(event, "There are no indexed entity types.", FlashScopeUtil.FlashMessageStatus.ERROR); return; } - mapping.scope(Object.class, - mapping.allIndexedEntities().stream() - .map(SearchIndexedEntity::jpaName) - .filter(form::contains) - .collect(Collectors.toList())) - .massIndexer() - .startAndWait(); - flashMessage(event, "Entities successfully reindexed", Duration.ofSeconds(10)); + for (Map.Entry entry : mappings.entrySet()) { + SearchMapping mapping = entry.getValue(); + List entityNames = mapping.allIndexedEntities().stream() + .map(SearchIndexedEntity::jpaName) + .filter(jpaName -> form.contains(jpaName, entry.getKey(), false)) + .collect(Collectors.toList()); + if (!entityNames.isEmpty()) { + mapping.scope(Object.class, entityNames).massIndexer() + .startAndWait(); + flashMessage(event, "Entities successfully reindexed", Duration.ofSeconds(10)); + } + } } }; } diff --git a/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/devconsole/HibernateSearchSupplier.java b/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/devconsole/HibernateSearchSupplier.java index 2460e905887c6..ef2b842263692 100644 --- a/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/devconsole/HibernateSearchSupplier.java +++ b/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/devconsole/HibernateSearchSupplier.java @@ -1,44 +1,125 @@ package io.quarkus.hibernate.search.orm.elasticsearch.runtime.devconsole; -import java.util.Collections; +import java.lang.annotation.Annotation; +import java.util.Arrays; +import java.util.Comparator; import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; import java.util.function.Supplier; +import java.util.stream.Collector; import java.util.stream.Collectors; +import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.search.mapper.orm.entity.SearchIndexedEntity; import org.hibernate.search.mapper.orm.mapping.SearchMapping; import io.quarkus.arc.Arc; +import io.quarkus.hibernate.orm.PersistenceUnit; +import io.quarkus.hibernate.orm.runtime.PersistenceUnitUtil; import io.quarkus.hibernate.search.orm.elasticsearch.runtime.HibernateSearchElasticsearchRuntimeConfig; -import io.quarkus.hibernate.search.orm.elasticsearch.runtime.devconsole.HibernateSearchSupplier.DevUiIndexedEntity; -public class HibernateSearchSupplier implements Supplier> { +public class HibernateSearchSupplier implements Supplier { private final HibernateSearchElasticsearchRuntimeConfig runtimeConfig; + private final Set persistenceUnitNames; - HibernateSearchSupplier(HibernateSearchElasticsearchRuntimeConfig runtimeConfig) { + HibernateSearchSupplier(HibernateSearchElasticsearchRuntimeConfig runtimeConfig, Set persistenceUnitNames) { this.runtimeConfig = runtimeConfig; + this.persistenceUnitNames = persistenceUnitNames; } @Override - public List get() { + public IndexedPersistenceUnits get() { if (!isEnabled()) { - return Collections.emptyList(); + return new IndexedPersistenceUnits(); } - SearchMapping mapping = searchMapping(); - if (mapping == null) { - return Collections.emptyList(); + Map mappings = searchMapping(persistenceUnitNames); + if (mappings.isEmpty()) { + return new IndexedPersistenceUnits(); } - return mapping.allIndexedEntities().stream().map(DevUiIndexedEntity::new).sorted() - .collect(Collectors.toList()); + return mappings.entrySet().stream() + .map(mapping -> new IndexedPersistenceUnit(mapping.getKey(), + mapping.getValue().allIndexedEntities().stream().map(DevUiIndexedEntity::new).sorted() + .collect(Collectors.toList()))) + .collect(Collector.of(IndexedPersistenceUnits::new, IndexedPersistenceUnits::add, + (left, right) -> { + left.addAll(right); + return left; + })); } private boolean isEnabled() { return runtimeConfig.defaultPersistenceUnit.enabled; } - public static SearchMapping searchMapping() { - return Arc.container().instance(SearchMapping.class).get(); + public static Map searchMapping(Set persistenceUnitNames) { + return Arrays.stream(getPersistenceUnitQualifiers(persistenceUnitNames)).map( + qualifier -> Arc.container().select(SearchMapping.class, qualifier).get()) + .collect(Collectors.toMap(HibernateSearchSupplier::getPersistenceUnitName, mapping -> mapping)); + } + + private static Annotation[] getPersistenceUnitQualifiers(Set persistenceUnitNames) { + return persistenceUnitNames.stream().map(PersistenceUnit.PersistenceUnitLiteral::new).toArray(Annotation[]::new); + } + + private static String getPersistenceUnitName(SearchMapping searchMapping) { + SessionFactoryImplementor sessionFactory = searchMapping.toOrmSessionFactory().unwrap(SessionFactoryImplementor.class); + String name = sessionFactory.getName(); + if (name != null) { + return name; + } + Object persistenceUnitName = sessionFactory.getProperties().get("hibernate.ejb.persistenceUnitName"); + if (persistenceUnitName != null) { + return persistenceUnitName.toString(); + } + return PersistenceUnitUtil.DEFAULT_PERSISTENCE_UNIT_NAME; + } + + static class IndexedPersistenceUnits { + private final Set persistenceUnits = new TreeSet<>(new PersistenceUnitComparator()); + + public Set getPersistenceUnits() { + return persistenceUnits; + } + + public void add(IndexedPersistenceUnit indexedPersistenceUnit) { + persistenceUnits.add(indexedPersistenceUnit); + } + + public void addAll(IndexedPersistenceUnits right) { + persistenceUnits.addAll(right.persistenceUnits); + } + + public int getNumberOfIndexedEntities() { + return persistenceUnits.stream().mapToInt(pu -> pu.indexedEntities.size()).sum(); + } + } + + static class PersistenceUnitComparator implements Comparator { + Comparator persistenceUnitNameComparator = new PersistenceUnitUtil.PersistenceUnitNameComparator(); + + @Override + public int compare(IndexedPersistenceUnit o1, IndexedPersistenceUnit o2) { + return persistenceUnitNameComparator.compare(o1.persistenceUnitName, o2.persistenceUnitName); + } + } + + static class IndexedPersistenceUnit implements Comparable { + public final String persistenceUnitName; + + public final List indexedEntities; + + public IndexedPersistenceUnit(String persistenceUnitName, List indexedEntities) { + this.persistenceUnitName = persistenceUnitName; + this.indexedEntities = indexedEntities; + } + + @Override + public int compareTo(IndexedPersistenceUnit o) { + return this.persistenceUnitName.compareTo(o.persistenceUnitName); + } } public static class DevUiIndexedEntity implements Comparable { diff --git a/extensions/opentelemetry/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/OpenTelemetryMDCTest.java b/extensions/opentelemetry/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/OpenTelemetryMDCTest.java new file mode 100644 index 0000000000000..30b114d42cacd --- /dev/null +++ b/extensions/opentelemetry/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/OpenTelemetryMDCTest.java @@ -0,0 +1,187 @@ +package io.quarkus.opentelemetry.deployment; + +import static org.hamcrest.Matchers.is; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Inject; +import javax.ws.rs.GET; +import javax.ws.rs.Path; + +import org.jboss.logging.MDC; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.context.Scope; +import io.opentelemetry.sdk.trace.data.SpanData; +import io.quarkus.arc.Unremovable; +import io.quarkus.test.QuarkusUnitTest; +import io.restassured.RestAssured; + +public class OpenTelemetryMDCTest { + @RegisterExtension + static final QuarkusUnitTest unitTest = new QuarkusUnitTest() + .withApplicationRoot((jar) -> jar + .addClass(MdcEntry.class) + .addClass(TestMdcCapturer.class) + .addClass(TestSpanExporter.class) + .addClass(TestResource.class)); + + @Inject + TestSpanExporter spanExporter; + @Inject + TestMdcCapturer testMdcCapturer; + @Inject + Tracer tracer; + + @AfterEach + void tearDown() { + spanExporter.reset(); + testMdcCapturer.reset(); + } + + @Test + void vertx() { + RestAssured.when() + .get("/hello").then() + .statusCode(200) + .body(is("hello")); + + List spans = spanExporter.getFinishedSpanItems(2); + + List mdcEntries = testMdcCapturer.getCapturedMdcEntries(); + + List expectedMdcEntries = getExpectedMDCEntries(spans); + + assertEquals("something", spans.get(0).getName()); + assertEquals("/hello", spans.get(1).getName()); + assertEquals(expectedMdcEntries, mdcEntries); + } + + @Test + void nonVertx() { + Span parentSpan = tracer.spanBuilder("parent").startSpan(); + try (Scope ignored = parentSpan.makeCurrent()) { + testMdcCapturer.captureMdc(); + Span childSpan = tracer.spanBuilder("child").startSpan(); + try (Scope ignored1 = childSpan.makeCurrent()) { + testMdcCapturer.captureMdc(); + } finally { + childSpan.end(); + } + } finally { + parentSpan.end(); + } + + List spans = spanExporter.getFinishedSpanItems(2); + + List mdcEntries = testMdcCapturer.getCapturedMdcEntries(); + + List expectedMdcEntries = getExpectedMDCEntries(spans); + + assertEquals("child", spans.get(0).getName()); + assertEquals("parent", spans.get(1).getName()); + assertEquals(expectedMdcEntries, mdcEntries); + } + + private List getExpectedMDCEntries(List spans) { + return spans.stream() + .map(spanData -> new MdcEntry(spanData.getSpanContext().isSampled(), + spanData.getParentSpanContext().isValid() ? spanData.getParentSpanId() : "null", + spanData.getSpanId(), + spanData.getTraceId())) + .collect(Collectors.collectingAndThen(Collectors.toList(), l -> { + Collections.reverse(l); + return l; + })); + } + + @ApplicationScoped + @Path("/") + public static class TestResource { + + @Inject + TestMdcCapturer testMdcCapturer; + + @Inject + Tracer tracer; + + @GET + @Path("/hello") + public String hello() { + testMdcCapturer.captureMdc(); + Span span = tracer.spanBuilder("something").startSpan(); + try (Scope ignored = span.makeCurrent()) { + testMdcCapturer.captureMdc(); + } finally { + span.end(); + } + return "hello"; + } + } + + @Unremovable + @ApplicationScoped + public static class TestMdcCapturer { + private final List mdcEntries = Collections.synchronizedList(new ArrayList<>()); + + public void reset() { + mdcEntries.clear(); + } + + public void captureMdc() { + mdcEntries.add(new MdcEntry( + Boolean.parseBoolean(String.valueOf(MDC.get("sampled"))), + String.valueOf(MDC.get("parentId")), + String.valueOf(MDC.get("spanId")), + String.valueOf(MDC.get("traceId")))); + } + + public List getCapturedMdcEntries() { + return List.copyOf(mdcEntries); + } + } + + public static class MdcEntry { + public final boolean isSampled; + public final String parentId; + public final String spanId; + public final String traceId; + + public MdcEntry(boolean isSampled, String parentId, String spanId, String traceId) { + this.isSampled = isSampled; + this.parentId = parentId; + this.spanId = spanId; + this.traceId = traceId; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof MdcEntry)) { + return false; + } + MdcEntry mdcEntry = (MdcEntry) o; + return isSampled == mdcEntry.isSampled && + Objects.equals(parentId, mdcEntry.parentId) && + Objects.equals(spanId, mdcEntry.spanId) && + Objects.equals(traceId, mdcEntry.traceId); + } + + @Override + public int hashCode() { + return Objects.hash(isSampled, parentId, spanId, traceId); + } + } +} diff --git a/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/MDCEnabledContextStorage.java b/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/MDCEnabledContextStorage.java new file mode 100644 index 0000000000000..c3d357e24fc6d --- /dev/null +++ b/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/MDCEnabledContextStorage.java @@ -0,0 +1,38 @@ +package io.quarkus.opentelemetry.runtime; + +import io.opentelemetry.context.Context; +import io.opentelemetry.context.ContextStorage; +import io.opentelemetry.context.Scope; + +/** + * A Context Storage that wraps the default OpenTelemetry ContextStorage and + * adds MDC functionality. + */ +enum MDCEnabledContextStorage implements ContextStorage { + INSTANCE; + + private static final ContextStorage DEFAULT_CONTEXT_STORAGE = ContextStorage.defaultStorage(); + + @Override + public Scope attach(Context toAttach) { + Context beforeAttach = current(); + + OpenTelemetryUtil.setMDCData(toAttach, null); + + Scope scope = DEFAULT_CONTEXT_STORAGE.attach(toAttach); + + return () -> { + if (beforeAttach == null) { + OpenTelemetryUtil.clearMDCData(null); + } else { + OpenTelemetryUtil.setMDCData(beforeAttach, null); + } + scope.close(); + }; + } + + @Override + public Context current() { + return DEFAULT_CONTEXT_STORAGE.current(); + } +} diff --git a/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/OpenTelemetryUtil.java b/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/OpenTelemetryUtil.java index a4eb7b180f8e4..c406794ba449d 100644 --- a/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/OpenTelemetryUtil.java +++ b/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/OpenTelemetryUtil.java @@ -11,12 +11,22 @@ import java.util.stream.StreamSupport; import io.opentelemetry.api.baggage.propagation.W3CBaggagePropagator; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanContext; import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; +import io.opentelemetry.context.Context; import io.opentelemetry.context.propagation.ContextPropagators; import io.opentelemetry.context.propagation.TextMapPropagator; import io.opentelemetry.sdk.autoconfigure.spi.ConfigurablePropagatorProvider; +import io.opentelemetry.sdk.trace.ReadableSpan; +import io.quarkus.vertx.core.runtime.VertxMDC; public final class OpenTelemetryUtil { + public static final String TRACE_ID = "traceId"; + public static final String SPAN_ID = "spanId"; + public static final String SAMPLED = "sampled"; + public static final String PARENT_ID = "parentId"; + private OpenTelemetryUtil() { } @@ -74,4 +84,42 @@ public static Map convertKeyValueListToMap(List headers) .map(keyValuePair -> new AbstractMap.SimpleImmutableEntry<>(keyValuePair[0].trim(), keyValuePair[1].trim())) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (first, next) -> next, LinkedHashMap::new)); } + + /** + * Sets MDC data by using the current span from the context. + * + * @param context opentelemetry context + * @param vertxContext vertx context + */ + public static void setMDCData(Context context, io.vertx.core.Context vertxContext) { + Span span = Span.fromContextOrNull(context); + if (span != null) { + SpanContext spanContext = span.getSpanContext(); + VertxMDC vertxMDC = VertxMDC.INSTANCE; + vertxMDC.put(SPAN_ID, spanContext.getSpanId(), vertxContext); + vertxMDC.put(TRACE_ID, spanContext.getTraceId(), vertxContext); + vertxMDC.put(SAMPLED, Boolean.toString(spanContext.isSampled()), vertxContext); + if (span instanceof ReadableSpan) { + SpanContext parentSpanContext = ((ReadableSpan) span).getParentSpanContext(); + if (parentSpanContext.isValid()) { + vertxMDC.put(PARENT_ID, parentSpanContext.getSpanId(), vertxContext); + } else { + vertxMDC.remove(PARENT_ID, vertxContext); + } + } + } + } + + /** + * Clears MDC data related to OpenTelemetry + * + * @param vertxContext vertx context + */ + public static void clearMDCData(io.vertx.core.Context vertxContext) { + VertxMDC vertxMDC = VertxMDC.INSTANCE; + vertxMDC.remove(TRACE_ID, vertxContext); + vertxMDC.remove(SPAN_ID, vertxContext); + vertxMDC.remove(PARENT_ID, vertxContext); + vertxMDC.remove(SAMPLED, vertxContext); + } } diff --git a/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/QuarkusContextStorage.java b/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/QuarkusContextStorage.java index fb8b1d0ad1adb..7452f6dcfcf8a 100644 --- a/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/QuarkusContextStorage.java +++ b/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/QuarkusContextStorage.java @@ -14,7 +14,8 @@ /** * Bridges the OpenTelemetry ContextStorage with the Vert.x Context. The default OpenTelemetry ContextStorage (based in * ThreadLocals) is not suitable for Vert.x. In this case, the OpenTelemetry Context piggybacks on top of the Vert.x - * Context. If the Vert.x Context is not available, fallbacks to the default OpenTelemetry ContextStorage. + * Context. If the Vert.x Context is not available, fallbacks to an MDC enabled context storage that wraps the default + * OpenTelemetry ContextStorage. */ public enum QuarkusContextStorage implements ContextStorage { INSTANCE; @@ -22,7 +23,7 @@ public enum QuarkusContextStorage implements ContextStorage { private static final Logger log = Logger.getLogger(QuarkusContextStorage.class); private static final String OTEL_CONTEXT = QuarkusContextStorage.class.getName() + ".otelContext"; - private static final ContextStorage DEFAULT_CONTEXT_STORAGE = ContextStorage.defaultStorage(); + private static final ContextStorage FALLBACK_CONTEXT_STORAGE = MDCEnabledContextStorage.INSTANCE; static Vertx vertx; /** @@ -37,7 +38,7 @@ public enum QuarkusContextStorage implements ContextStorage { public Scope attach(Context toAttach) { io.vertx.core.Context vertxContext = getVertxContext(); return vertxContext != null && isDuplicatedContext(vertxContext) ? attach(vertxContext, toAttach) - : DEFAULT_CONTEXT_STORAGE.attach(toAttach); + : FALLBACK_CONTEXT_STORAGE.attach(toAttach); } /** @@ -64,6 +65,7 @@ public Scope attach(io.vertx.core.Context vertxContext, Context toAttach) { } vertxContext.putLocal(OTEL_CONTEXT, toAttach); + OpenTelemetryUtil.setMDCData(toAttach, vertxContext); return () -> { if (getContext(vertxContext) != toAttach) { @@ -72,8 +74,10 @@ public Scope attach(io.vertx.core.Context vertxContext, Context toAttach) { if (beforeAttach == null) { vertxContext.removeLocal(OTEL_CONTEXT); + OpenTelemetryUtil.clearMDCData(vertxContext); } else { vertxContext.putLocal(OTEL_CONTEXT, beforeAttach); + OpenTelemetryUtil.setMDCData(beforeAttach, vertxContext); } }; } @@ -90,7 +94,7 @@ public Context current() { if (current != null) { return current.getLocal(OTEL_CONTEXT); } else { - return DEFAULT_CONTEXT_STORAGE.current(); + return FALLBACK_CONTEXT_STORAGE.current(); } } diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/resource/basic/MediaTypesWithSuffixHandlingTest.java b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/resource/basic/MediaTypesWithSuffixHandlingTest.java new file mode 100644 index 0000000000000..4b741ca17e064 --- /dev/null +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/resource/basic/MediaTypesWithSuffixHandlingTest.java @@ -0,0 +1,216 @@ +package io.quarkus.resteasy.reactive.server.test.resource.basic; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; +import java.nio.charset.StandardCharsets; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.ext.Provider; + +import org.hamcrest.Matchers; +import org.jboss.resteasy.reactive.server.spi.ResteasyReactiveResourceInfo; +import org.jboss.resteasy.reactive.server.spi.ServerMessageBodyReader; +import org.jboss.resteasy.reactive.server.spi.ServerMessageBodyWriter; +import org.jboss.resteasy.reactive.server.spi.ServerRequestContext; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; +import io.restassured.RestAssured; + +public class MediaTypesWithSuffixHandlingTest { + + @RegisterExtension + static QuarkusUnitTest testExtension = new QuarkusUnitTest() + .setArchiveProducer(() -> { + JavaArchive archive = ShrinkWrap.create(JavaArchive.class); + archive.addClasses(TestResource.class, NoSuffixMessageBodyWriter.class, SuffixMessageBodyWriter.class); + return archive; + }); + + @Test + public void testWriterWithoutSuffix() { + RestAssured.get("/test/writer/with-no-suffix") + .then() + .statusCode(200) + .body(Matchers.equalTo("result - no suffix writer")); + } + + @Test + public void testReaderWithoutSuffix() { + RestAssured.get("/test/reader/with-no-suffix") + .then() + .statusCode(200) + .body(Matchers.equalTo("from reader - result")); + } + + @Test + public void testWriterWithSuffix() { + RestAssured.get("/test/writer/with-suffix") + .then() + .statusCode(200) + .body(Matchers.equalTo("result - suffix writer")); + } + + @Test + public void testReaderWithSuffix() { + RestAssured.get("/test/reader/with-suffix") + .then() + .statusCode(200) + .body(Matchers.equalTo("from reader suffix - result")); + } + + @Path("/test") + public static class TestResource { + + @GET + @Path("/writer/with-no-suffix") + @Produces("text/test") + public String writerSimple() { + return "result"; + } + + @GET + @Path("/writer/with-suffix") + @Produces("text/test+suffix") + public String writerSuffix() { + return "result"; + } + + @GET + @Path("/reader/with-no-suffix") + @Consumes("text/test") + public String readerSimple(Object fromReader) { + return fromReader + " - result"; + } + + @GET + @Path("/reader/with-suffix") + @Consumes("text/test+suffix") + public String readerSuffix(Object fromReader) { + return fromReader + " - result"; + } + } + + @Provider + @Consumes("text/test") + @Produces("text/test") + public static class NoSuffixMessageBodyWriter implements ServerMessageBodyWriter, ServerMessageBodyReader { + + @Override + public boolean isWriteable(Class type, Type genericType, ResteasyReactiveResourceInfo target, MediaType mediaType) { + return true; + } + + @Override + public void writeResponse(Object o, Type genericType, ServerRequestContext context) + throws WebApplicationException, IOException { + String response = (String) o; + response += " - no suffix writer"; + context.getOrCreateOutputStream().write(response.getBytes(StandardCharsets.UTF_8)); + } + + @Override + public boolean isWriteable(Class type, Type genericType, Annotation[] annotations, MediaType mediaType) { + throw new IllegalStateException("should never have been called"); + } + + @Override + public void writeTo(Object o, Class type, Type genericType, Annotation[] annotations, MediaType mediaType, + MultivaluedMap httpHeaders, OutputStream entityStream) + throws IOException, WebApplicationException { + throw new IllegalStateException("should never have been called"); + } + + @Override + public boolean isReadable(Class type, Type genericType, ResteasyReactiveResourceInfo lazyMethod, + MediaType mediaType) { + return true; + } + + @Override + public Object readFrom(Class type, Type genericType, MediaType mediaType, + ServerRequestContext context) throws WebApplicationException { + return "from reader"; + } + + @Override + public boolean isReadable(Class aClass, Type type, Annotation[] annotations, MediaType mediaType) { + throw new IllegalStateException("should never have been called"); + } + + @Override + public Object readFrom(Class aClass, Type type, Annotation[] annotations, MediaType mediaType, + MultivaluedMap multivaluedMap, InputStream inputStream) + throws WebApplicationException { + throw new IllegalStateException("should never have been called"); + } + } + + @Provider + @Consumes("text/test+suffix") + @Produces("text/test+suffix") + public static class SuffixMessageBodyWriter implements ServerMessageBodyWriter, ServerMessageBodyReader { + + @Override + public boolean isWriteable(Class type, Type genericType, ResteasyReactiveResourceInfo target, MediaType mediaType) { + return true; + } + + @Override + public void writeResponse(Object o, Type genericType, ServerRequestContext context) + throws WebApplicationException, IOException { + String response = (String) o; + response += " - suffix writer"; + context.getOrCreateOutputStream().write(response.getBytes(StandardCharsets.UTF_8)); + } + + @Override + public boolean isWriteable(Class type, Type genericType, Annotation[] annotations, MediaType mediaType) { + throw new IllegalStateException("should never have been called"); + } + + @Override + public void writeTo(Object o, Class type, Type genericType, Annotation[] annotations, MediaType mediaType, + MultivaluedMap httpHeaders, OutputStream entityStream) + throws IOException, WebApplicationException { + throw new IllegalStateException("should never have been called"); + } + + @Override + public boolean isReadable(Class type, Type genericType, ResteasyReactiveResourceInfo lazyMethod, + MediaType mediaType) { + return true; + } + + @Override + public Object readFrom(Class type, Type genericType, MediaType mediaType, + ServerRequestContext context) throws WebApplicationException { + return "from reader suffix"; + } + + @Override + public boolean isReadable(Class aClass, Type type, Annotation[] annotations, MediaType mediaType) { + throw new IllegalStateException("should never have been called"); + } + + @Override + public Object readFrom(Class aClass, Type type, Annotation[] annotations, MediaType mediaType, + MultivaluedMap multivaluedMap, InputStream inputStream) + throws WebApplicationException { + throw new IllegalStateException("should never have been called"); + } + } + +} diff --git a/independent-projects/qute/pom.xml b/independent-projects/qute/pom.xml index d6917d25cf73a..ff0459518cc24 100644 --- a/independent-projects/qute/pom.xml +++ b/independent-projects/qute/pom.xml @@ -46,7 +46,7 @@ 3.5.0.Final 3.0.0-M5 1.6.8 - 1.4.0 + 1.5.0 diff --git a/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/ClientReaderInterceptorContextImpl.java b/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/ClientReaderInterceptorContextImpl.java index c73f288f0c87a..55815186fa959 100644 --- a/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/ClientReaderInterceptorContextImpl.java +++ b/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/ClientReaderInterceptorContextImpl.java @@ -17,7 +17,6 @@ import org.jboss.resteasy.reactive.common.core.Serialisers; import org.jboss.resteasy.reactive.common.jaxrs.ConfigurationImpl; import org.jboss.resteasy.reactive.common.util.CaseInsensitiveMap; -import org.jboss.resteasy.reactive.common.util.MediaTypeHelper; public class ClientReaderInterceptorContextImpl extends AbstractClientInterceptorContextImpl implements ReaderInterceptorContext { @@ -35,7 +34,7 @@ public ClientReaderInterceptorContextImpl(Annotation[] annotations, Class ent Map properties, MultivaluedMap headers, ConfigurationImpl configuration, Serialisers serialisers, InputStream inputStream, ReaderInterceptor[] interceptors) { - super(annotations, entityClass, entityType, MediaTypeHelper.withSuffixAsSubtype(mediaType), properties); + super(annotations, entityClass, entityType, mediaType, properties); this.configuration = configuration; this.serialisers = serialisers; this.inputStream = inputStream; diff --git a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/core/Serialisers.java b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/core/Serialisers.java index 9a1c82d1795ba..e543e7cf976cb 100644 --- a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/core/Serialisers.java +++ b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/core/Serialisers.java @@ -43,7 +43,7 @@ public List> findReaders(ConfigurationImpl configuration, C public List> findReaders(ConfigurationImpl configuration, Class entityType, MediaType mediaType, RuntimeType runtimeType) { - List mt = Collections.singletonList(mediaType); + List desired = MediaTypeHelper.getUngroupedMediaTypes(mediaType); List> ret = new ArrayList<>(); Deque> toProcess = new LinkedList<>(); Class klass = entityType; @@ -66,7 +66,7 @@ public List> findReaders(ConfigurationImpl configuration, C while (!toProcess.isEmpty()) { Class iface = toProcess.poll(); List goodTypeReaders = readers.get(iface); - readerLookup(mediaType, runtimeType, mt, ret, goodTypeReaders); + readerLookup(mediaType, runtimeType, desired, ret, goodTypeReaders); for (Class i : iface.getInterfaces()) { if (!seen.contains(i)) { seen.add(i); @@ -76,7 +76,7 @@ public List> findReaders(ConfigurationImpl configuration, C } } List goodTypeReaders = readers.get(klass); - readerLookup(mediaType, runtimeType, mt, ret, goodTypeReaders); + readerLookup(mediaType, runtimeType, desired, ret, goodTypeReaders); if (klass.isInterface()) { klass = Object.class; } else { @@ -87,7 +87,8 @@ public List> findReaders(ConfigurationImpl configuration, C return ret; } - private void readerLookup(MediaType mediaType, RuntimeType runtimeType, List mt, List> ret, + private void readerLookup(MediaType mediaType, RuntimeType runtimeType, List desired, + List> ret, List goodTypeReaders) { if (goodTypeReaders != null && !goodTypeReaders.isEmpty()) { List mediaTypeMatchingReaders = new ArrayList<>(goodTypeReaders.size()); @@ -96,13 +97,15 @@ private void readerLookup(MediaType mediaType, RuntimeType runtimeType, List> findBuildTimeWriters(Class entityType, Runt protected List findResourceWriters(QuarkusMultivaluedMap, ResourceWriter> writers, Class klass, List produces, RuntimeType runtimeType) { + Class currentClass = klass; + List desired = MediaTypeHelper.getUngroupedMediaTypes(produces); List ret = new ArrayList<>(); Deque> toProcess = new LinkedList<>(); do { - if (klass == Object.class) { + if (currentClass == Object.class) { //spec extension, look for interfaces as well //we match interfaces before Object Set> seen = new HashSet<>(toProcess); while (!toProcess.isEmpty()) { Class iface = toProcess.poll(); List goodTypeWriters = writers.get(iface); - writerLookup(runtimeType, produces, ret, goodTypeWriters); + writerLookup(runtimeType, produces, desired, ret, goodTypeWriters); for (Class i : iface.getInterfaces()) { if (!seen.contains(i)) { seen.add(i); @@ -170,15 +175,16 @@ protected List findResourceWriters(QuarkusMultivaluedMap goodTypeWriters = writers.get(klass); - writerLookup(runtimeType, produces, ret, goodTypeWriters); - toProcess.addAll(Arrays.asList(klass.getInterfaces())); + List goodTypeWriters = writers.get(currentClass); + writerLookup(runtimeType, produces, desired, ret, goodTypeWriters); + toProcess.addAll(Arrays.asList(currentClass.getInterfaces())); // if we're an interface, pretend our superclass is Object to get us through the same logic as a class - if (klass.isInterface()) - klass = Object.class; - else - klass = klass.getSuperclass(); - } while (klass != null); + if (currentClass.isInterface()) { + currentClass = Object.class; + } else { + currentClass = currentClass.getSuperclass(); + } + } while (currentClass != null); return ret; } @@ -200,22 +206,25 @@ protected List> toMessageBodyWriters(List r return ret; } - private void writerLookup(RuntimeType runtimeType, List mt, List ret, - List goodTypeWriters) { + private void writerLookup(RuntimeType runtimeType, List produces, List desired, + List ret, List goodTypeWriters) { if (goodTypeWriters != null && !goodTypeWriters.isEmpty()) { List mediaTypeMatchingWriters = new ArrayList<>(goodTypeWriters.size()); + for (int i = 0; i < goodTypeWriters.size(); i++) { ResourceWriter goodTypeWriter = goodTypeWriters.get(i); if (!goodTypeWriter.matchesRuntimeType(runtimeType)) { continue; } - MediaType match = MediaTypeHelper.getFirstMatch(mt, goodTypeWriter.mediaTypes()); + MediaType match = MediaTypeHelper.getFirstMatch(desired, goodTypeWriter.mediaTypes()); if (match != null) { mediaTypeMatchingWriters.add(goodTypeWriter); } } + // we sort here because the spec mentions that the writers closer to the requested java type are tried first - mediaTypeMatchingWriters.sort(ResourceWriter.ResourceWriterComparator.INSTANCE); + mediaTypeMatchingWriters.sort(new ResourceWriter.ResourceWriterComparator(produces)); + ret.addAll(mediaTypeMatchingWriters); } } diff --git a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/model/ResourceReader.java b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/model/ResourceReader.java index 69ad09b953e4a..ca73e22378d91 100644 --- a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/model/ResourceReader.java +++ b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/model/ResourceReader.java @@ -114,7 +114,11 @@ public boolean matchesRuntimeType(RuntimeType runtimeType) { */ public static class ResourceReaderComparator implements Comparator { - public static final ResourceReaderComparator INSTANCE = new ResourceReaderComparator(); + private final List produces; + + public ResourceReaderComparator(List produces) { + this.produces = produces; + } @Override public int compare(ResourceReader o1, ResourceReader o2) { @@ -144,6 +148,14 @@ public int compare(ResourceReader o1, ResourceReader o2) { return mediaTypeCompare; } + // try to compare using the number of matching produces media types + if (!produces.isEmpty()) { + mediaTypeCompare = MediaTypeHelper.compareMatchingMediaTypes(produces, mediaTypes1, mediaTypes2); + if (mediaTypeCompare != 0) { + return mediaTypeCompare; + } + } + // done to make the sorting result deterministic return Integer.compare(mediaTypes1.size(), mediaTypes2.size()); } diff --git a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/model/ResourceWriter.java b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/model/ResourceWriter.java index d04c4420c801d..381c363b60667 100644 --- a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/model/ResourceWriter.java +++ b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/model/ResourceWriter.java @@ -99,7 +99,7 @@ public ServerMediaType serverMediaType() { if (serverMediaType == null) { synchronized (this) { // a MessageBodyWriter should always return its configured media type when negotiating, hence the 'false' for 'useSuffix' - serverMediaType = new ServerMediaType(mediaTypes(), StandardCharsets.UTF_8.name(), false, false); + serverMediaType = new ServerMediaType(mediaTypes(), StandardCharsets.UTF_8.name(), false); } } return serverMediaType; @@ -129,7 +129,15 @@ public String toString() { */ public static class ResourceWriterComparator implements Comparator { - public static final ResourceWriterComparator INSTANCE = new ResourceWriterComparator(); + private final List produces; + + public ResourceWriterComparator() { + this(Collections.emptyList()); + } + + public ResourceWriterComparator(List produces) { + this.produces = produces; + } @Override public int compare(ResourceWriter o1, ResourceWriter o2) { @@ -159,6 +167,14 @@ public int compare(ResourceWriter o1, ResourceWriter o2) { return mediaTypeCompare; } + // try to compare using the number of matching produces media types + if (!produces.isEmpty()) { + mediaTypeCompare = MediaTypeHelper.compareMatchingMediaTypes(produces, mediaTypes1, mediaTypes2); + if (mediaTypeCompare != 0) { + return mediaTypeCompare; + } + } + // done to make the sorting result deterministic return Integer.compare(mediaTypes1.size(), mediaTypes2.size()); } diff --git a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/util/MediaTypeHelper.java b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/util/MediaTypeHelper.java index 41b72877f9808..f7e5e84006736 100644 --- a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/util/MediaTypeHelper.java +++ b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/util/MediaTypeHelper.java @@ -2,9 +2,11 @@ import java.io.Serializable; import java.util.ArrayList; +import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; +import java.util.regex.Pattern; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; @@ -16,6 +18,7 @@ public class MediaTypeHelper { public static final MediaTypeComparator Q_COMPARATOR = new MediaTypeComparator("q"); public static final MediaTypeComparator QS_COMPARATOR = new MediaTypeComparator("qs"); + private static final String MEDIA_TYPE_SUFFIX_DELIM = "+"; private static float getQTypeWithParamInfo(MediaType type, String parameterName) { if (type.getParameters() != null) { @@ -138,6 +141,13 @@ public static int compareWeight(MediaType one, MediaType two) { return Q_COMPARATOR.compare(one, two); } + public static int compareMatchingMediaTypes(List produces, List mediaTypes1, + List mediaTypes2) { + int countMediaTypes1 = countMatchingMediaTypes(produces, mediaTypes1); + int countMediaTypes2 = countMatchingMediaTypes(produces, mediaTypes2); + return (countMediaTypes1 < countMediaTypes2) ? 1 : ((countMediaTypes1 == countMediaTypes2) ? 0 : -1); + } + public static void sortByWeight(List types) { if (hasAtMostOneItem(types)) { return; @@ -267,20 +277,77 @@ public static boolean isUnsupportedWildcardSubtype(MediaType mediaType) { return false; } + public static List toListOfMediaType(String[] mediaTypes) { + if (mediaTypes == null || mediaTypes.length == 0) { + return Collections.emptyList(); + } + + List list = new ArrayList<>(mediaTypes.length); + for (String mediaType : mediaTypes) { + list.add(MediaType.valueOf(mediaType)); + } + + return Collections.unmodifiableList(list); + } + + /** + * This method ungroups the media types with suffix in separated media types. For example, having the media type + * "application/one+two" will return a list containing ["application/one+two", "application/one", "application/two"]. + * The Media Types without suffix remain as one media type. + * + * @param mediaTypes the list of media types to separate. + * @return the list of ungrouped media types. + */ + public static List getUngroupedMediaTypes(List mediaTypes) { + List effectiveMediaTypes = new ArrayList<>(); + for (MediaType mediaType : mediaTypes) { + effectiveMediaTypes.addAll(getUngroupedMediaTypes(mediaType)); + } + + return Collections.unmodifiableList(effectiveMediaTypes); + } + /** - * If the supplied media type contains a suffix in the subtype, then this returns a new media type - * that uses the suffix as the subtype + * This method ungroups the media type with suffix in separated media types. For example, having the media type + * "application/one+two" will return a list containing ["application/one+two", "application/one", "application/two"]. + * If the Media Type does not have a suffix, then it's not modified. + * + * @param mediaType the media type to separate. + * @return the list of ungrouped media types. */ - public static MediaType withSuffixAsSubtype(MediaType mediaType) { + public static List getUngroupedMediaTypes(MediaType mediaType) { if (mediaType == null) { - return null; + return Collections.emptyList(); + } + + if (mediaType.getSubtype() == null || !mediaType.getSubtype().contains(MEDIA_TYPE_SUFFIX_DELIM)) { + return Collections.singletonList(mediaType); + } + + String[] subTypes = mediaType.getSubtype().split(Pattern.quote(MEDIA_TYPE_SUFFIX_DELIM)); + + List effectiveMediaTypes = new ArrayList<>(1 + subTypes.length); + effectiveMediaTypes.add(mediaType); + for (String subType : subTypes) { + effectiveMediaTypes.add(new MediaType(mediaType.getType(), subType, mediaType.getParameters())); } - int plusIndex = mediaType.getSubtype().indexOf('+'); - if ((plusIndex > -1) && (plusIndex < mediaType.getSubtype().length() - 1)) { - mediaType = new MediaType(mediaType.getType(), - mediaType.getSubtype().substring(plusIndex + 1), - mediaType.getParameters()); + + return Collections.unmodifiableList(effectiveMediaTypes); + } + + private static int countMatchingMediaTypes(List produces, List mediaTypes) { + int count = 0; + for (int i = 0; i < mediaTypes.size(); i++) { + MediaType mediaType = mediaTypes.get(i); + for (int j = 0; j < produces.size(); j++) { + MediaType produce = produces.get(j); + if (mediaType.isCompatible(produce)) { + count++; + break; + } + } } - return mediaType; + + return count; } } diff --git a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/util/ServerMediaType.java b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/util/ServerMediaType.java index cff31dd2a3200..97ba2d2f174be 100644 --- a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/util/ServerMediaType.java +++ b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/util/ServerMediaType.java @@ -30,14 +30,11 @@ public static List mediaTypesFromArray(String[] mediaTypesStrs) { } /** - * * @param mediaTypes The original media types * @param charset charset to use * @param deprioritizeWildcards whether or not wildcard types should be carry less weight when sorting is performed - * @param useSuffix whether or not a media type whose subtype contains a suffix should swap the entire subtype with the - * suffix */ - public ServerMediaType(List mediaTypes, String charset, boolean deprioritizeWildcards, boolean useSuffix) { + public ServerMediaType(List mediaTypes, String charset, boolean deprioritizeWildcards) { if (mediaTypes.isEmpty()) { this.sortedOriginalMediaTypes = new MediaType[] { MediaType.WILDCARD_TYPE }; } else { @@ -87,12 +84,6 @@ public int compare(MediaType m1, MediaType m2) { MediaType m = new MediaType(existing.getType(), existing.getSubtype(), charset); sortedMediaTypes[i] = m; } - // use the suffix type if it exists when negotiating the type - if (useSuffix) { - for (int i = 0; i < sortedMediaTypes.length; i++) { - sortedMediaTypes[i] = MediaTypeHelper.withSuffixAsSubtype(sortedMediaTypes[i]); - } - } // if there is only one media type, use it if (sortedMediaTypes.length == 1 && !(sortedMediaTypes[0].isWildcardType() || sortedMediaTypes[0].isWildcardSubtype())) { diff --git a/independent-projects/resteasy-reactive/pom.xml b/independent-projects/resteasy-reactive/pom.xml index 999445da14c05..f4cb0c7ac1d75 100644 --- a/independent-projects/resteasy-reactive/pom.xml +++ b/independent-projects/resteasy-reactive/pom.xml @@ -54,7 +54,7 @@ 1.6.8 2.0.1.Final 1.1.6 - 1.4.0 + 1.5.0 1.12.0 4.2.4 4.5.1 @@ -66,7 +66,7 @@ 1.0.11 1.0.2 4.2.0 - 2.19.0 + 2.22.0 diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/serialization/DynamicEntityWriter.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/serialization/DynamicEntityWriter.java index 4109b8e1182a7..929017cdc6bd7 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/serialization/DynamicEntityWriter.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/serialization/DynamicEntityWriter.java @@ -97,8 +97,7 @@ public void write(ResteasyReactiveRequestContext context, Object entity) throws } } else { writers = serialisers - .findWriters(null, entity.getClass(), MediaTypeHelper.withSuffixAsSubtype(producesMediaType.getMediaType()), - RuntimeType.SERVER) + .findWriters(null, entity.getClass(), producesMediaType.getMediaType(), RuntimeType.SERVER) .toArray(ServerSerialisers.NO_WRITER); } for (MessageBodyWriter w : writers) { diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/startup/RuntimeResourceDeployment.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/startup/RuntimeResourceDeployment.java index 15c40b97948ff..1685899412d99 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/startup/RuntimeResourceDeployment.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/startup/RuntimeResourceDeployment.java @@ -379,7 +379,7 @@ public RuntimeResource buildResourceMethod(ResourceClass clazz, // when negotiating a media type, we want to use the proper subtype to locate a ResourceWriter, // hence the 'true' for 'useSuffix' serverMediaType = new ServerMediaType(ServerMediaType.mediaTypesFromArray(method.getProduces()), - StandardCharsets.UTF_8.name(), false, true); + StandardCharsets.UTF_8.name(), false); } if (method.getHttpMethod() == null) { //this is a resource locator method @@ -399,8 +399,7 @@ public RuntimeResource buildResourceMethod(ResourceClass clazz, } else if (rawEffectiveReturnType != Void.class && rawEffectiveReturnType != void.class) { List> buildTimeWriters = serialisers.findBuildTimeWriters(rawEffectiveReturnType, - RuntimeType.SERVER, Collections.singletonList( - MediaTypeHelper.withSuffixAsSubtype(MediaType.valueOf(method.getProduces()[0])))); + RuntimeType.SERVER, MediaTypeHelper.toListOfMediaType(method.getProduces())); if (buildTimeWriters == null) { //if this is null this means that the type cannot be resolved at build time //this happens when the method returns a generic type (e.g. Object), so there diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/MediaTypeMapper.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/MediaTypeMapper.java index 1d2bea0c74983..a77db34a0d847 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/MediaTypeMapper.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/MediaTypeMapper.java @@ -131,8 +131,9 @@ public void setResource(RuntimeResource runtimeResource, MediaType mediaType) { } public void setupServerMediaType() { - MediaTypeHelper.sortByQSWeight(mtsWithParams); // TODO: this isn't completely correct as we are supposed to take q and then qs into account... - serverMediaType = new ServerMediaType(mtsWithParams, StandardCharsets.UTF_8.name(), true, false); + // TODO: this isn't completely correct as we are supposed to take q and then qs into account... + MediaTypeHelper.sortByQSWeight(mtsWithParams); + serverMediaType = new ServerMediaType(mtsWithParams, StandardCharsets.UTF_8.name(), true); } } } diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/RequestDeserializeHandler.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/RequestDeserializeHandler.java index 2a89c7b1f4c1d..d668916b5851d 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/RequestDeserializeHandler.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/RequestDeserializeHandler.java @@ -15,7 +15,6 @@ import javax.ws.rs.ext.MessageBodyReader; import javax.ws.rs.ext.ReaderInterceptor; import org.jboss.logging.Logger; -import org.jboss.resteasy.reactive.common.util.MediaTypeHelper; import org.jboss.resteasy.reactive.server.core.ResteasyReactiveRequestContext; import org.jboss.resteasy.reactive.server.core.ServerSerialisers; import org.jboss.resteasy.reactive.server.jaxrs.ReaderInterceptorContextImpl; @@ -47,7 +46,7 @@ public void handle(ResteasyReactiveRequestContext requestContext) throws Excepti String requestTypeString = requestContext.serverRequest().getRequestHeader(HttpHeaders.CONTENT_TYPE); if (requestTypeString != null) { try { - effectiveRequestType = MediaTypeHelper.withSuffixAsSubtype(MediaType.valueOf(requestTypeString)); + effectiveRequestType = MediaType.valueOf(requestTypeString); } catch (Exception e) { throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST).build()); } diff --git a/integration-tests/devtools/src/test/java/io/quarkus/platform/catalog/RegistrySnapshotCatalogCompatibilityTest.java b/integration-tests/devtools/src/test/java/io/quarkus/platform/catalog/CatalogCompatibilityTest.java similarity index 81% rename from integration-tests/devtools/src/test/java/io/quarkus/platform/catalog/RegistrySnapshotCatalogCompatibilityTest.java rename to integration-tests/devtools/src/test/java/io/quarkus/platform/catalog/CatalogCompatibilityTest.java index a67d1c24f0b72..84149c7f2d24e 100644 --- a/integration-tests/devtools/src/test/java/io/quarkus/platform/catalog/RegistrySnapshotCatalogCompatibilityTest.java +++ b/integration-tests/devtools/src/test/java/io/quarkus/platform/catalog/CatalogCompatibilityTest.java @@ -5,17 +5,16 @@ import java.io.IOException; import java.util.List; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import io.quarkus.devtools.codestarts.quarkus.QuarkusCodestartCatalog; import io.quarkus.devtools.project.CodestartResourceLoadersBuilder; import io.quarkus.devtools.project.QuarkusProjectHelper; +import io.quarkus.devtools.testing.PlatformAwareTestBase; import io.quarkus.platform.catalog.processor.CatalogProcessor; import io.quarkus.platform.catalog.processor.ExtensionProcessor; import io.quarkus.platform.catalog.processor.ProcessedCategory; import io.quarkus.platform.descriptor.loader.json.ResourceLoader; -import io.quarkus.registry.Constants; import io.quarkus.registry.ExtensionCatalogResolver; import io.quarkus.registry.RegistryResolutionException; import io.quarkus.registry.catalog.Extension; @@ -25,20 +24,13 @@ import io.quarkus.registry.catalog.PlatformRelease; import io.quarkus.registry.catalog.PlatformStream; -public class RegistrySnapshotCatalogCompatibilityTest { - - private final ExtensionCatalogResolver catalogResolver = QuarkusProjectHelper.getCatalogResolver(); - - public RegistrySnapshotCatalogCompatibilityTest() throws RegistryResolutionException { - } +public class CatalogCompatibilityTest extends PlatformAwareTestBase { @Test - @Disabled - public void testRegistrySnapshotPlatformCatalog() throws RegistryResolutionException, IOException { - // TODO Use a local snapshot of the registry for testing - final PlatformCatalog platformCatalog = getRegistryPlatformCatalog(); - assertThat(platformCatalog.getMetadata().get(Constants.LAST_UPDATED)).isNotNull(); - testPlatformCatalog(catalogResolver, platformCatalog, "io.quarkus.platform"); + void testCatalog() throws RegistryResolutionException, IOException { + final ExtensionCatalogResolver catalogResolver = QuarkusProjectHelper.getCatalogResolver(); + testPlatformCatalog(catalogResolver, catalogResolver.resolvePlatformCatalog(), + "io.quarkus"); } static void testPlatformCatalog(ExtensionCatalogResolver catalogResolver, PlatformCatalog platformCatalog, @@ -55,7 +47,6 @@ static void testPlatformCatalog(ExtensionCatalogResolver catalogResolver, Platfo for (PlatformRelease r : s.getReleases()) { checkPlatformRelease(catalogResolver, r); } - } } @@ -102,7 +93,4 @@ private static void checkExtensionProcessor(Extension e) { extensionProcessor.getNonQuarkusBomOnly(); } - private PlatformCatalog getRegistryPlatformCatalog() throws RegistryResolutionException { - return catalogResolver.resolvePlatformCatalog(); - } } diff --git a/integration-tests/devtools/src/test/java/io/quarkus/platform/catalog/LocalCatalogCompatibilityTest.java b/integration-tests/devtools/src/test/java/io/quarkus/platform/catalog/LocalCatalogCompatibilityTest.java deleted file mode 100644 index ec7e505654782..0000000000000 --- a/integration-tests/devtools/src/test/java/io/quarkus/platform/catalog/LocalCatalogCompatibilityTest.java +++ /dev/null @@ -1,20 +0,0 @@ -package io.quarkus.platform.catalog; - -import java.io.IOException; - -import org.junit.jupiter.api.Test; - -import io.quarkus.devtools.project.QuarkusProjectHelper; -import io.quarkus.devtools.testing.PlatformAwareTestBase; -import io.quarkus.registry.ExtensionCatalogResolver; -import io.quarkus.registry.RegistryResolutionException; - -public class LocalCatalogCompatibilityTest extends PlatformAwareTestBase { - - @Test - void testCatalog() throws RegistryResolutionException, IOException { - final ExtensionCatalogResolver catalogResolver = QuarkusProjectHelper.getCatalogResolver(); - RegistrySnapshotCatalogCompatibilityTest.testPlatformCatalog(catalogResolver, catalogResolver.resolvePlatformCatalog(), - "io.quarkus"); - } -} diff --git a/integration-tests/gradle/.gradle/gradle.properties b/integration-tests/gradle/.gradle/gradle.properties new file mode 100644 index 0000000000000..5f1ed7bbe024a --- /dev/null +++ b/integration-tests/gradle/.gradle/gradle.properties @@ -0,0 +1 @@ +org.gradle.caching=true \ No newline at end of file diff --git a/integration-tests/gradle/src/test/java/io/quarkus/gradle/AddExtensionToSingleModuleKtsProjectTest.java b/integration-tests/gradle/src/test/java/io/quarkus/gradle/AddExtensionToSingleModuleKtsProjectTest.java index ab7ea55623e5d..b53b9f6b72f83 100644 --- a/integration-tests/gradle/src/test/java/io/quarkus/gradle/AddExtensionToSingleModuleKtsProjectTest.java +++ b/integration-tests/gradle/src/test/java/io/quarkus/gradle/AddExtensionToSingleModuleKtsProjectTest.java @@ -40,7 +40,7 @@ public void testRemoveNonExistentExtension() throws IOException, URISyntaxExcept final File projectDir = getProjectDir("add-remove-extension-single-module-kts"); BuildResult buildResult = runGradleWrapper(projectDir, "clean", "build"); - assertThat(buildResult.getTasks().get(":test")).isEqualTo(BuildResult.SUCCESS_OUTCOME); + assertThat(BuildResult.isSuccessful(buildResult.getTasks().get(":test"))).isTrue(); final Path buildKts = projectDir.toPath().resolve("build.gradle.kts"); assertThat(buildKts).exists(); diff --git a/integration-tests/gradle/src/test/java/io/quarkus/gradle/AddExtensionToSingleModuleProjectTest.java b/integration-tests/gradle/src/test/java/io/quarkus/gradle/AddExtensionToSingleModuleProjectTest.java index 9d6965d4547f6..3a163d5b5af34 100644 --- a/integration-tests/gradle/src/test/java/io/quarkus/gradle/AddExtensionToSingleModuleProjectTest.java +++ b/integration-tests/gradle/src/test/java/io/quarkus/gradle/AddExtensionToSingleModuleProjectTest.java @@ -37,7 +37,7 @@ public void testRemoveNonExistentExtension() throws IOException, URISyntaxExcept final File projectDir = getProjectDir("add-remove-extension-single-module"); BuildResult buildResult = runGradleWrapper(projectDir, "clean", "build"); - assertThat(buildResult.getTasks().get(":test")).isEqualTo(BuildResult.SUCCESS_OUTCOME); + assertThat(BuildResult.isSuccessful(buildResult.getTasks().get(":test"))).isTrue(); final Path build = projectDir.toPath().resolve("build.gradle"); assertThat(build).exists(); diff --git a/integration-tests/gradle/src/test/java/io/quarkus/gradle/AdditionalSourceSetsTest.java b/integration-tests/gradle/src/test/java/io/quarkus/gradle/AdditionalSourceSetsTest.java index e335167b4d681..66c16390f524f 100644 --- a/integration-tests/gradle/src/test/java/io/quarkus/gradle/AdditionalSourceSetsTest.java +++ b/integration-tests/gradle/src/test/java/io/quarkus/gradle/AdditionalSourceSetsTest.java @@ -1,6 +1,6 @@ package io.quarkus.gradle; -import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.assertj.core.api.Assertions.assertThat; import java.io.File; import java.io.IOException; @@ -18,7 +18,6 @@ public class AdditionalSourceSetsTest extends QuarkusGradleWrapperTestBase { public void executeFunctionalTest() throws URISyntaxException, IOException, InterruptedException { final File projectDir = getProjectDir("additional-source-sets"); BuildResult result = runGradleWrapper(projectDir, "functionalTest"); - assertEquals(BuildResult.SUCCESS_OUTCOME, result.getTasks().get(":functionalTest"), - "Failed to run tests defined in an alternate test sources directory"); + assertThat(BuildResult.isSuccessful(result.getTasks().get(":functionalTest"))).isTrue(); } } diff --git a/integration-tests/gradle/src/test/java/io/quarkus/gradle/AnnotationProcessorMultiModuleTest.java b/integration-tests/gradle/src/test/java/io/quarkus/gradle/AnnotationProcessorMultiModuleTest.java index 3a43713c46cb5..156bccf71e914 100644 --- a/integration-tests/gradle/src/test/java/io/quarkus/gradle/AnnotationProcessorMultiModuleTest.java +++ b/integration-tests/gradle/src/test/java/io/quarkus/gradle/AnnotationProcessorMultiModuleTest.java @@ -14,6 +14,6 @@ public void shouldRunTestCorrectly() throws Exception { BuildResult buildResult = runGradleWrapper(projectDir, "clean", "test"); - assertThat(buildResult.getTasks().get(":application:test")).isEqualTo(BuildResult.SUCCESS_OUTCOME); + assertThat(BuildResult.isSuccessful(buildResult.getTasks().get(":application:test"))).isTrue(); } } diff --git a/integration-tests/gradle/src/test/java/io/quarkus/gradle/AnnotationProcessorSimpleModuleTest.java b/integration-tests/gradle/src/test/java/io/quarkus/gradle/AnnotationProcessorSimpleModuleTest.java index 66a61bbc6b048..07445b9415f88 100644 --- a/integration-tests/gradle/src/test/java/io/quarkus/gradle/AnnotationProcessorSimpleModuleTest.java +++ b/integration-tests/gradle/src/test/java/io/quarkus/gradle/AnnotationProcessorSimpleModuleTest.java @@ -15,7 +15,7 @@ public void shouldRunTestCorrectly() throws Exception { BuildResult buildResult = runGradleWrapper(projectDir, "clean", "test"); - assertThat(buildResult.getTasks().get(":test")).isEqualTo(BuildResult.SUCCESS_OUTCOME); + assertThat(BuildResult.isSuccessful(buildResult.getTasks().get(":test"))).isTrue(); } @Test @@ -24,7 +24,7 @@ public void shouldContainsPanacheMarkerFile() throws Exception { BuildResult buildResult = runGradleWrapper(projectDir, "clean", "quarkusBuild"); - assertThat(buildResult.getTasks().get(":quarkusBuild")).isEqualTo(BuildResult.SUCCESS_OUTCOME); + assertThat(BuildResult.isSuccessful(buildResult.getTasks().get(":quarkusBuild"))).isTrue(); File buildDir = new File(projectDir, "build"); Path metaInfDir = buildDir.toPath().resolve("classes").resolve("java").resolve("main").resolve("META-INF"); diff --git a/integration-tests/gradle/src/test/java/io/quarkus/gradle/ApplicationConfigurationTest.java b/integration-tests/gradle/src/test/java/io/quarkus/gradle/ApplicationConfigurationTest.java index f44453718537c..86def66f466ea 100644 --- a/integration-tests/gradle/src/test/java/io/quarkus/gradle/ApplicationConfigurationTest.java +++ b/integration-tests/gradle/src/test/java/io/quarkus/gradle/ApplicationConfigurationTest.java @@ -14,7 +14,7 @@ public void shouldSuccessfullyInjectApplicationConfigInTest() throws Exception { BuildResult testResult = runGradleWrapper(projectDir, "clean", ":application:test"); - assertThat(testResult.getTasks().get(":application:test")).isEqualTo(BuildResult.SUCCESS_OUTCOME); + assertThat(BuildResult.isSuccessful(testResult.getTasks().get(":application:test"))).isTrue(); } } diff --git a/integration-tests/gradle/src/test/java/io/quarkus/gradle/BeanInTestSourcesTest.java b/integration-tests/gradle/src/test/java/io/quarkus/gradle/BeanInTestSourcesTest.java index 374e98927150a..6e68885d1a152 100644 --- a/integration-tests/gradle/src/test/java/io/quarkus/gradle/BeanInTestSourcesTest.java +++ b/integration-tests/gradle/src/test/java/io/quarkus/gradle/BeanInTestSourcesTest.java @@ -12,6 +12,6 @@ public class BeanInTestSourcesTest extends QuarkusGradleWrapperTestBase { public void testBasicMultiModuleBuild() throws Exception { final File projectDir = getProjectDir("bean-in-testsources-project"); final BuildResult build = runGradleWrapper(projectDir, "clean", "test"); - assertThat(build.getTasks().get(":test")).isEqualTo(BuildResult.SUCCESS_OUTCOME); + assertThat(BuildResult.isSuccessful(build.getTasks().get(":test"))).isTrue(); } } diff --git a/integration-tests/gradle/src/test/java/io/quarkus/gradle/BuildResult.java b/integration-tests/gradle/src/test/java/io/quarkus/gradle/BuildResult.java index df3e5e432f49d..c1288e1e04cf3 100644 --- a/integration-tests/gradle/src/test/java/io/quarkus/gradle/BuildResult.java +++ b/integration-tests/gradle/src/test/java/io/quarkus/gradle/BuildResult.java @@ -12,6 +12,7 @@ public class BuildResult { public static final String SUCCESS_OUTCOME = "SUCCESS"; public static final String UPTODATE_OUTCOME = "UP-TO-DATE"; + public static final String FROM_CACHE = "FROM-CACHE"; private static final String TASK_RESULT_PREFIX = "> Task"; private Map tasks; @@ -54,4 +55,8 @@ public Map getTasks() { public String getOutput() { return output; } + + public static boolean isSuccessful(String result) { + return SUCCESS_OUTCOME.equals(result) || FROM_CACHE.equals(result); + } } diff --git a/integration-tests/gradle/src/test/java/io/quarkus/gradle/CustomFileSystemProviderTest.java b/integration-tests/gradle/src/test/java/io/quarkus/gradle/CustomFileSystemProviderTest.java index 983a91b3d7ca0..266da97dce703 100644 --- a/integration-tests/gradle/src/test/java/io/quarkus/gradle/CustomFileSystemProviderTest.java +++ b/integration-tests/gradle/src/test/java/io/quarkus/gradle/CustomFileSystemProviderTest.java @@ -14,6 +14,6 @@ public void test() throws Exception { final File projectDir = getProjectDir("custom-filesystem-provider"); BuildResult build = runGradleWrapper(projectDir, "clean", ":application:test"); - assertThat(build.getTasks().get(":application:test")).isEqualTo(BuildResult.SUCCESS_OUTCOME); + assertThat(BuildResult.isSuccessful(build.getTasks().get(":application:test"))).isTrue(); } } diff --git a/integration-tests/gradle/src/test/java/io/quarkus/gradle/DependencyConstraintsTest.java b/integration-tests/gradle/src/test/java/io/quarkus/gradle/DependencyConstraintsTest.java index a8070a019be23..366d71eaaca94 100644 --- a/integration-tests/gradle/src/test/java/io/quarkus/gradle/DependencyConstraintsTest.java +++ b/integration-tests/gradle/src/test/java/io/quarkus/gradle/DependencyConstraintsTest.java @@ -15,7 +15,7 @@ public void shoudBuildProjectWithDependencyConstraint() throws Exception { BuildResult buildResult = runGradleWrapper(projectDir, "clean", "quarkusBuild", "-Dquarkus.package.type=mutable-jar"); - assertThat(buildResult.getTasks().get(":quarkusBuild")).isEqualTo(BuildResult.SUCCESS_OUTCOME); + assertThat(BuildResult.isSuccessful(buildResult.getTasks().get(":quarkusBuild"))).isTrue(); final File buildDir = new File(projectDir, "build"); final Path mainLib = buildDir.toPath().resolve("quarkus-app").resolve("lib").resolve("main"); diff --git a/integration-tests/gradle/src/test/java/io/quarkus/gradle/DependencyResolutionTest.java b/integration-tests/gradle/src/test/java/io/quarkus/gradle/DependencyResolutionTest.java index 509cfb6d3d0fc..de98f99ff7c94 100644 --- a/integration-tests/gradle/src/test/java/io/quarkus/gradle/DependencyResolutionTest.java +++ b/integration-tests/gradle/src/test/java/io/quarkus/gradle/DependencyResolutionTest.java @@ -16,6 +16,6 @@ public void shouldResolveDependencyVersionFromSuperConfigurationProject() final BuildResult result = runGradleWrapper(projectDir, "clean", "quarkusBuild"); - assertThat(result.getTasks().get(":quarkusBuild")).isEqualTo(BuildResult.SUCCESS_OUTCOME); + assertThat(BuildResult.isSuccessful(result.getTasks().get(":quarkusBuild"))).isTrue(); } } diff --git a/integration-tests/gradle/src/test/java/io/quarkus/gradle/InjectBeanFromTestConfigTest.java b/integration-tests/gradle/src/test/java/io/quarkus/gradle/InjectBeanFromTestConfigTest.java index b052e66a3f05c..69f233f720df1 100644 --- a/integration-tests/gradle/src/test/java/io/quarkus/gradle/InjectBeanFromTestConfigTest.java +++ b/integration-tests/gradle/src/test/java/io/quarkus/gradle/InjectBeanFromTestConfigTest.java @@ -14,6 +14,6 @@ public void testBasicMultiModuleBuild() throws Exception { final File projectDir = getProjectDir("inject-bean-from-test-config"); BuildResult build = runGradleWrapper(projectDir, "clean", ":application:test"); - assertThat(build.getTasks().get(":application:test")).isEqualTo(BuildResult.SUCCESS_OUTCOME); + assertThat(BuildResult.isSuccessful(build.getTasks().get(":application:test"))).isTrue(); } } diff --git a/integration-tests/gradle/src/test/java/io/quarkus/gradle/IntegrationTestBuildTest.java b/integration-tests/gradle/src/test/java/io/quarkus/gradle/IntegrationTestBuildTest.java index 1145c1a07f1c7..60c482b0f68cc 100644 --- a/integration-tests/gradle/src/test/java/io/quarkus/gradle/IntegrationTestBuildTest.java +++ b/integration-tests/gradle/src/test/java/io/quarkus/gradle/IntegrationTestBuildTest.java @@ -14,8 +14,8 @@ public void shouldRunIntegrationTestAsPartOfBuild() throws Exception { BuildResult buildResult = runGradleWrapper(projectDir, "clean", "quarkusIntTest"); - assertThat(buildResult.getTasks().get(":test")).isEqualTo(BuildResult.SUCCESS_OUTCOME); - assertThat(buildResult.getTasks().get(":quarkusIntTest")).isEqualTo(BuildResult.SUCCESS_OUTCOME); + assertThat(BuildResult.isSuccessful(buildResult.getTasks().get(":test"))).isTrue(); + assertThat(BuildResult.isSuccessful(buildResult.getTasks().get(":quarkusIntTest"))).isTrue(); } } diff --git a/integration-tests/gradle/src/test/java/io/quarkus/gradle/JandexMultiModuleTest.java b/integration-tests/gradle/src/test/java/io/quarkus/gradle/JandexMultiModuleTest.java index f27fe605878b6..d05f5530edf70 100644 --- a/integration-tests/gradle/src/test/java/io/quarkus/gradle/JandexMultiModuleTest.java +++ b/integration-tests/gradle/src/test/java/io/quarkus/gradle/JandexMultiModuleTest.java @@ -14,8 +14,8 @@ public void testBasicMultiModuleBuild() throws Exception { final File projectDir = getProjectDir("jandex-basic-multi-module-project"); BuildResult build = runGradleWrapper(projectDir, "clean", ":application:quarkusBuild"); - assertThat(build.getTasks().get(":common:jandex")).isEqualTo(BuildResult.SUCCESS_OUTCOME); - assertThat(build.getTasks().get(":application:quarkusBuild")).isEqualTo(BuildResult.SUCCESS_OUTCOME); + assertThat(BuildResult.isSuccessful(build.getTasks().get(":common:jandex"))).isTrue(); + assertThat(BuildResult.isSuccessful(build.getTasks().get(":application:quarkusBuild"))).isTrue(); } } diff --git a/integration-tests/gradle/src/test/java/io/quarkus/gradle/KotlinGRPCProjectBuildTest.java b/integration-tests/gradle/src/test/java/io/quarkus/gradle/KotlinGRPCProjectBuildTest.java index 1148f70087ca1..7651be57e8496 100644 --- a/integration-tests/gradle/src/test/java/io/quarkus/gradle/KotlinGRPCProjectBuildTest.java +++ b/integration-tests/gradle/src/test/java/io/quarkus/gradle/KotlinGRPCProjectBuildTest.java @@ -12,7 +12,7 @@ public class KotlinGRPCProjectBuildTest extends QuarkusGradleWrapperTestBase { public void testBasicMultiModuleBuild() throws Exception { final File projectDir = getProjectDir("kotlin-grpc-project"); final BuildResult build = runGradleWrapper(projectDir, "clean", "build"); - assertThat(build.getTasks().get(":quarkusGenerateCode")).isEqualTo(BuildResult.SUCCESS_OUTCOME); - assertThat(build.getTasks().get(":compileKotlin")).isEqualTo(BuildResult.SUCCESS_OUTCOME); + assertThat(BuildResult.isSuccessful(build.getTasks().get(":quarkusGenerateCode"))).isTrue(); + assertThat(BuildResult.isSuccessful(build.getTasks().get(":compileKotlin"))).isTrue(); } } diff --git a/integration-tests/gradle/src/test/java/io/quarkus/gradle/MultiModuleKotlinProjectBuildTest.java b/integration-tests/gradle/src/test/java/io/quarkus/gradle/MultiModuleKotlinProjectBuildTest.java index 020037329c481..ecb3fb0cd3d48 100644 --- a/integration-tests/gradle/src/test/java/io/quarkus/gradle/MultiModuleKotlinProjectBuildTest.java +++ b/integration-tests/gradle/src/test/java/io/quarkus/gradle/MultiModuleKotlinProjectBuildTest.java @@ -12,7 +12,7 @@ public class MultiModuleKotlinProjectBuildTest extends QuarkusGradleWrapperTestB public void testBasicMultiModuleBuild() throws Exception { final File projectDir = getProjectDir("multi-module-kotlin-project"); final BuildResult build = runGradleWrapper(projectDir, "clean", "build"); - assertThat(build.getTasks().get(":quarkusGenerateCode")).isEqualTo(BuildResult.SUCCESS_OUTCOME); - assertThat(build.getTasks().get(":compileKotlin")).isEqualTo(BuildResult.SUCCESS_OUTCOME); + assertThat(BuildResult.isSuccessful(build.getTasks().get(":quarkusGenerateCode"))).isTrue(); + assertThat(BuildResult.isSuccessful(build.getTasks().get(":compileKotlin"))).isTrue(); } } diff --git a/integration-tests/gradle/src/test/java/io/quarkus/gradle/MultiSourceProjectTest.java b/integration-tests/gradle/src/test/java/io/quarkus/gradle/MultiSourceProjectTest.java index 640b8569b9abb..bd73097714714 100644 --- a/integration-tests/gradle/src/test/java/io/quarkus/gradle/MultiSourceProjectTest.java +++ b/integration-tests/gradle/src/test/java/io/quarkus/gradle/MultiSourceProjectTest.java @@ -13,7 +13,7 @@ public void shouldRunTest() throws Exception { final File projectDir = getProjectDir("multi-source-project"); final BuildResult buildResult = runGradleWrapper(projectDir, ":clean", ":test"); - assertThat(buildResult.getTasks().get(":test")).isEqualTo(BuildResult.SUCCESS_OUTCOME); + assertThat(BuildResult.isSuccessful(buildResult.getTasks().get(":test"))).isTrue(); } } diff --git a/integration-tests/gradle/src/test/java/io/quarkus/gradle/QuarkusPluginFunctionalTest.java b/integration-tests/gradle/src/test/java/io/quarkus/gradle/QuarkusPluginFunctionalTest.java index fa25471402d78..686a25c1480cd 100644 --- a/integration-tests/gradle/src/test/java/io/quarkus/gradle/QuarkusPluginFunctionalTest.java +++ b/integration-tests/gradle/src/test/java/io/quarkus/gradle/QuarkusPluginFunctionalTest.java @@ -38,7 +38,7 @@ public void canBuild(SourceType sourceType) throws Exception { BuildResult build = runGradleWrapper(projectRoot, "build", "--stacktrace"); - assertThat(build.getTasks().get(":build")).isEqualTo(BuildResult.SUCCESS_OUTCOME); + assertThat(BuildResult.isSuccessful(build.getTasks().get(":build"))).isTrue(); // gradle build should not build the native image assertThat(build.getTasks().get(":buildNative")).isNull(); Path buildDir = projectRoot.toPath().resolve("build"); @@ -51,7 +51,7 @@ public void canDetectUpToDateBuild() throws Exception { createProject(SourceType.JAVA); BuildResult firstBuild = runGradleWrapper(projectRoot, "quarkusBuild", "--stacktrace"); - assertThat(firstBuild.getTasks().get(":quarkusBuild")).isEqualTo(BuildResult.SUCCESS_OUTCOME); + assertThat(BuildResult.isSuccessful(firstBuild.getTasks().get(":quarkusBuild"))).isTrue(); BuildResult secondBuild = runGradleWrapper(projectRoot, "quarkusBuild", "--stacktrace"); assertThat(secondBuild.getTasks().get(":quarkusBuild")).isEqualTo(BuildResult.UPTODATE_OUTCOME); @@ -62,13 +62,13 @@ public void canDetectResourceChangeWhenBuilding() throws Exception { createProject(SourceType.JAVA); BuildResult firstBuild = runGradleWrapper(projectRoot, "quarkusBuild", "--stacktrace"); - assertThat(firstBuild.getTasks().get(":quarkusBuild")).isEqualTo(BuildResult.SUCCESS_OUTCOME); + assertThat(BuildResult.isSuccessful(firstBuild.getTasks().get(":quarkusBuild"))).isTrue(); final File applicationProperties = projectRoot.toPath().resolve("src/main/resources/application.properties").toFile(); Files.write(applicationProperties.toPath(), "quarkus.http.port=8888".getBytes()); BuildResult secondBuild = runGradleWrapper(projectRoot, "quarkusBuild", "--stacktrace"); - assertThat(secondBuild.getTasks().get(":quarkusBuild")).isEqualTo(BuildResult.SUCCESS_OUTCOME); + assertThat(BuildResult.isSuccessful(secondBuild.getTasks().get(":quarkusBuild"))).isTrue(); } @Test @@ -76,14 +76,14 @@ public void canDetectClassChangeWhenBuilding() throws Exception { createProject(SourceType.JAVA); BuildResult firstBuild = runGradleWrapper(projectRoot, "quarkusBuild", "--stacktrace"); - assertThat(firstBuild.getTasks().get(":quarkusBuild")).isEqualTo(BuildResult.SUCCESS_OUTCOME); + assertThat(BuildResult.isSuccessful(firstBuild.getTasks().get(":quarkusBuild"))).isTrue(); final File greetingResourceFile = projectRoot.toPath().resolve("src/main/java/org/acme/foo/GreetingResource.java") .toFile(); DevModeTestUtils.filter(greetingResourceFile, ImmutableMap.of("\"/greeting\"", "\"/test/hello\"")); BuildResult secondBuild = runGradleWrapper(projectRoot, "quarkusBuild", "--stacktrace"); - assertThat(secondBuild.getTasks().get(":quarkusBuild")).isEqualTo(BuildResult.SUCCESS_OUTCOME); + assertThat(BuildResult.isSuccessful(secondBuild.getTasks().get(":quarkusBuild"))).isTrue(); } @Test @@ -91,11 +91,11 @@ public void canDetectClasspathChangeWhenBuilding() throws Exception { createProject(SourceType.JAVA); BuildResult firstBuild = runGradleWrapper(projectRoot, "quarkusBuild", "--stacktrace"); - assertThat(firstBuild.getTasks().get(":quarkusBuild")).isEqualTo(BuildResult.SUCCESS_OUTCOME); + assertThat(BuildResult.isSuccessful(firstBuild.getTasks().get(":quarkusBuild"))).isTrue(); runGradleWrapper(projectRoot, "addExtension", "--extensions=hibernate-orm"); BuildResult secondBuild = runGradleWrapper(projectRoot, "quarkusBuild", "--stacktrace"); - assertThat(secondBuild.getTasks().get(":quarkusBuild")).isEqualTo(BuildResult.SUCCESS_OUTCOME); + assertThat(BuildResult.isSuccessful(secondBuild.getTasks().get(":quarkusBuild"))).isTrue(); } @Test @@ -104,13 +104,13 @@ public void canDetectOutputChangeWhenBuilding() throws Exception { BuildResult firstBuild = runGradleWrapper(projectRoot, "quarkusBuild", "--stacktrace"); - assertThat(firstBuild.getTasks().get(":quarkusBuild")).isEqualTo(BuildResult.SUCCESS_OUTCOME); + assertThat(BuildResult.isSuccessful(firstBuild.getTasks().get(":quarkusBuild"))).isTrue(); Path runnerJar = projectRoot.toPath().resolve("build").resolve("quarkus-app").resolve("quarkus-run.jar"); Files.delete(runnerJar); BuildResult secondBuild = runGradleWrapper(projectRoot, "quarkusBuild", "--stacktrace"); - assertThat(secondBuild.getTasks().get(":quarkusBuild")).isEqualTo(BuildResult.SUCCESS_OUTCOME); + assertThat(BuildResult.isSuccessful(secondBuild.getTasks().get(":quarkusBuild"))).isTrue(); assertThat(runnerJar).exists(); } @@ -120,7 +120,7 @@ public void canDetectUpToDateTests() throws Exception { BuildResult firstBuild = runGradleWrapper(projectRoot, "test"); - assertThat(firstBuild.getTasks().get(":test")).isEqualTo(BuildResult.SUCCESS_OUTCOME); + assertThat(BuildResult.isSuccessful(firstBuild.getTasks().get(":test"))).isTrue(); BuildResult secondBuild = runGradleWrapper(projectRoot, "test"); @@ -133,12 +133,12 @@ public void canDetectSystemPropertyChangeWhenBuilding() throws Exception { BuildResult firstBuild = runGradleWrapper(projectRoot, "quarkusBuild", "--stacktrace"); - assertThat(firstBuild.getTasks().get(":quarkusBuild")).isEqualTo(BuildResult.SUCCESS_OUTCOME); + assertThat(BuildResult.isSuccessful(firstBuild.getTasks().get(":quarkusBuild"))).isTrue(); assertThat(projectRoot.toPath().resolve("build").resolve("quarkus-app").resolve("quarkus-run.jar")).exists(); BuildResult secondBuild = runGradleWrapper(projectRoot, "quarkusBuild", "-Dquarkus.package.type=fast-jar"); - assertThat(secondBuild.getTasks().get(":quarkusBuild")).isEqualTo(BuildResult.SUCCESS_OUTCOME); + assertThat(BuildResult.isSuccessful(secondBuild.getTasks().get(":quarkusBuild"))).isTrue(); assertThat(projectRoot.toPath().resolve("build").resolve("quarkus-app")).exists(); } @@ -148,7 +148,7 @@ public void canRunTest() throws Exception { BuildResult buildResult = runGradleWrapper(projectRoot, "test", "--stacktrace"); - assertThat(buildResult.getTasks().get(":test")).isEqualTo(BuildResult.SUCCESS_OUTCOME); + assertThat(BuildResult.isSuccessful(buildResult.getTasks().get(":test"))).isTrue(); } @Test @@ -158,7 +158,7 @@ public void generateCodeBeforeTests() throws Exception { BuildResult firstBuild = runGradleWrapper(projectRoot, "test", "--stacktrace"); assertThat(firstBuild.getOutput()).contains("Task :quarkusGenerateCode"); assertThat(firstBuild.getOutput()).contains("Task :quarkusGenerateCodeTests"); - assertThat(firstBuild.getTasks().get(":test")).isEqualTo(BuildResult.SUCCESS_OUTCOME); + assertThat(BuildResult.isSuccessful(firstBuild.getTasks().get(":test"))).isTrue(); } private void createProject(SourceType sourceType) throws Exception { diff --git a/integration-tests/gradle/src/test/java/io/quarkus/gradle/SpringDependencyManagementTest.java b/integration-tests/gradle/src/test/java/io/quarkus/gradle/SpringDependencyManagementTest.java index b36c10a82019b..36ff0a9dee4b8 100644 --- a/integration-tests/gradle/src/test/java/io/quarkus/gradle/SpringDependencyManagementTest.java +++ b/integration-tests/gradle/src/test/java/io/quarkus/gradle/SpringDependencyManagementTest.java @@ -17,6 +17,6 @@ public void testQuarkusBuildShouldWorkWithSpringDependencyManagement() final BuildResult result = runGradleWrapper(projectDir, "clean", "quarkusBuild"); - assertThat(result.getTasks().get(":quarkusBuild")).isEqualTo(BuildResult.SUCCESS_OUTCOME); + assertThat(BuildResult.isSuccessful(result.getTasks().get(":quarkusBuild"))).isTrue(); } } diff --git a/integration-tests/gradle/src/test/java/io/quarkus/gradle/TestFixtureModuleTest.java b/integration-tests/gradle/src/test/java/io/quarkus/gradle/TestFixtureModuleTest.java index 2b60e9226ef1a..92f0a90f36350 100644 --- a/integration-tests/gradle/src/test/java/io/quarkus/gradle/TestFixtureModuleTest.java +++ b/integration-tests/gradle/src/test/java/io/quarkus/gradle/TestFixtureModuleTest.java @@ -16,6 +16,6 @@ public void testTaskShouldUseTestFixtures() throws IOException, URISyntaxExcepti final BuildResult result = runGradleWrapper(projectDir, "clean", "test"); - assertThat(result.getTasks().get(":test")).isEqualTo(BuildResult.SUCCESS_OUTCOME); + assertThat(BuildResult.isSuccessful(result.getTasks().get(":test"))).isTrue(); } } diff --git a/integration-tests/gradle/src/test/java/io/quarkus/gradle/TestFixtureMultiModuleTest.java b/integration-tests/gradle/src/test/java/io/quarkus/gradle/TestFixtureMultiModuleTest.java index 00d9076bdca26..b48cbfda403ff 100644 --- a/integration-tests/gradle/src/test/java/io/quarkus/gradle/TestFixtureMultiModuleTest.java +++ b/integration-tests/gradle/src/test/java/io/quarkus/gradle/TestFixtureMultiModuleTest.java @@ -14,6 +14,6 @@ public class TestFixtureMultiModuleTest extends QuarkusGradleWrapperTestBase { public void testTaskShouldUseTestFixtures() throws IOException, URISyntaxException, InterruptedException { final File projectDir = getProjectDir("test-fixtures-multi-module"); final BuildResult result = runGradleWrapper(projectDir, "clean", "test"); - assertThat(result.getTasks().get(":application:test")).isEqualTo(BuildResult.SUCCESS_OUTCOME); + assertThat(BuildResult.isSuccessful(result.getTasks().get(":application:test"))).isTrue(); } }