diff --git a/bom/application/pom.xml b/bom/application/pom.xml index cec9c8237e854..d5e56ca3375a0 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -177,7 +177,7 @@ 3.14.9 1.17.2 0.2.0 - 4.5.1 + 4.6.1 5.2.SP7 2.1.SP2 5.4.Final @@ -191,7 +191,7 @@ 3.31.0 2.18.0 0.23.0 - 1.42.3 + 1.43.0 2.1 4.7.1 1.0.4 @@ -211,7 +211,7 @@ 2.7 0.11.0 - 9.30.2 + 9.31 0.0.6 0.1.3 2.9.2 diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/CodeGenLock.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/CodeGenLock.java new file mode 100644 index 0000000000000..7a57d86a5e26f --- /dev/null +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/CodeGenLock.java @@ -0,0 +1,26 @@ +package io.quarkus.deployment.dev; + +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +/** + * Lock that is used to prevent scanning and compiling while code generator is updating sources + * There is a race when testing this, where you can see the intermediate empty state of the + * file, or where the file time changes twice. Codegen hold this lock during modification + * to avoid the race. + */ +public class CodeGenLock { + + /** + * Allow for multiple code generators to run at the same time but give exclusive run to RuntimeUpdatesProcessor + */ + private static final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true); + + public static Lock lockForCodeGen() { + return lock.readLock(); + } + + public static Lock lockForCompilation() { + return lock.writeLock(); + } +} diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/CodeGenWatcher.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/CodeGenWatcher.java index 35c731d896f58..aea88af8328dd 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/dev/CodeGenWatcher.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/CodeGenWatcher.java @@ -4,6 +4,7 @@ import java.util.Collection; import java.util.List; import java.util.Properties; +import java.util.concurrent.locks.Lock; import org.eclipse.microprofile.config.Config; import org.jboss.logging.Logger; @@ -22,6 +23,7 @@ class CodeGenWatcher { private final QuarkusClassLoader deploymentClassLoader; private final FSWatchUtil fsWatchUtil; + private final Lock codeGenLock = CodeGenLock.lockForCodeGen(); CodeGenWatcher(CuratedApplication curatedApplication, DevModeContext context) throws CodeGenException { final QuarkusClassLoader deploymentClassLoader = curatedApplication.createDeploymentClassLoader(); @@ -39,12 +41,15 @@ class CodeGenWatcher { for (CodeGenData codeGen : codeGens) { watchers.add(new FSWatchUtil.Watcher(codeGen.sourceDir, codeGen.provider.inputExtension(), modifiedPaths -> { + codeGenLock.lock(); try { CodeGenerator.trigger(deploymentClassLoader, codeGen, curatedApplication.getApplicationModel(), config, false); } catch (Exception any) { log.warn("Code generation failed", any); + } finally { + codeGenLock.unlock(); } })); } diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/RuntimeUpdatesProcessor.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/RuntimeUpdatesProcessor.java index 1da4db6de658e..3d63057412663 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/dev/RuntimeUpdatesProcessor.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/RuntimeUpdatesProcessor.java @@ -38,6 +38,7 @@ import java.util.concurrent.ConcurrentSkipListSet; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.function.BiConsumer; import java.util.function.BiFunction; @@ -107,6 +108,7 @@ public class RuntimeUpdatesProcessor implements HotReplacementContext, Closeable private final BiConsumer copyResourceNotification; private final BiFunction classTransformers; private final ReentrantLock scanLock = new ReentrantLock(); + private final Lock codeGenLock = CodeGenLock.lockForCompilation(); /** * The index for the last successful start. Used to determine if the class has changed its structure @@ -442,6 +444,8 @@ public boolean doScan(boolean userInitiated, boolean forceRestart) { return false; } scanLock.lock(); + codeGenLock.lock(); + try { final long startNanoseconds = System.nanoTime(); for (Runnable step : preScanSteps) { @@ -564,6 +568,7 @@ public boolean doScan(boolean userInitiated, boolean forceRestart) { } finally { scanLock.unlock(); + codeGenLock.unlock(); } } diff --git a/docs/src/main/asciidoc/kubernetes-client.adoc b/docs/src/main/asciidoc/kubernetes-client.adoc index 15aab18ee1f0b..afd2d0653debe 100644 --- a/docs/src/main/asciidoc/kubernetes-client.adoc +++ b/docs/src/main/asciidoc/kubernetes-client.adoc @@ -57,10 +57,15 @@ Note that the full list of properties is available in the link:#quarkus-kubernet In dev mode and when running tests, xref:kubernetes-dev-services.adoc[Dev Services for Kubernetes] automatically starts a Kubernetes API server. -=== Overriding +=== Customizing and overriding -The extension also allows application code to override either of `io.fabric8.kubernetes.client.Config` or `io.fabric8.kubernetes.client.KubernetesClient` which are -normally provided by the extension by simply declaring custom versions of those beans. +Quarkus provides multiple integration points for influencing the Kubernetes Client provided as a CDI bean. + +The first integration point is the use of the `io.quarkus.kubernetes.client.KubernetesConfigCustomizer` interface. When such a bean exists, +it allows for arbitrary customizations of the `io.fabric8.kubernetes.client.Config` created by Quarkus (which takes into account the `quarkus.kubernetes-client.*` properties). + +Alternatively, application code can override the `io.fabric8.kubernetes.client.Config` or even the `io.fabric8.kubernetes.client.KubernetesClient` bean (which are +normally provided by the extension) by simply declaring custom versions of those beans. An example of this can be seen in the following snippet: diff --git a/docs/src/main/asciidoc/qute-reference.adoc b/docs/src/main/asciidoc/qute-reference.adoc index 46229b19c993e..3c2db01f3403a 100644 --- a/docs/src/main/asciidoc/qute-reference.adoc +++ b/docs/src/main/asciidoc/qute-reference.adoc @@ -665,7 +665,7 @@ And must be used in a form of `{item_hasNext}` inside a `{#for}` section with th {#for item in items} {item_count}. {item.name} <1> {#if item_hasNext}
{/if} <2> -{/each} +{/for} ---- <1> `item_count` represents one-based index. <2> `
` is only rendered if the iteration has more elements. diff --git a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/BeanArchiveProcessor.java b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/BeanArchiveProcessor.java index 5e8158993fafd..53eda169c5dc1 100644 --- a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/BeanArchiveProcessor.java +++ b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/BeanArchiveProcessor.java @@ -189,7 +189,9 @@ private boolean possiblyBeanArchive(ApplicationArchive archive) { || text.contains("bean-discovery-mode=\"all\"")) { LOGGER.warnf("Detected bean archive with bean discovery mode of 'all', " + "this is not portable in CDI Lite and is treated as 'annotated' in Quarkus! " - + "Path to beans.xml: %s", pathVisit.getPath()); + + "Path to beans.xml: %s", + archive.getKey() != null ? archive.getKey().toGacString() + ":" + pathVisit.getPath() + : pathVisit.getPath()); } } catch (IOException e) { throw new UncheckedIOException(e); diff --git a/extensions/grpc/codegen/src/main/java/io/quarkus/grpc/deployment/GrpcPostProcessing.java b/extensions/grpc/codegen/src/main/java/io/quarkus/grpc/deployment/GrpcPostProcessing.java index ca1131b81efaa..84cf4429aa1b6 100644 --- a/extensions/grpc/codegen/src/main/java/io/quarkus/grpc/deployment/GrpcPostProcessing.java +++ b/extensions/grpc/codegen/src/main/java/io/quarkus/grpc/deployment/GrpcPostProcessing.java @@ -1,14 +1,7 @@ package io.quarkus.grpc.deployment; import java.io.File; -import java.io.IOException; -import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.StandardCopyOption; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; -import java.util.function.Consumer; import org.jboss.logging.Logger; @@ -72,7 +65,6 @@ private boolean isEnabled(CodeGenContext context, String name, boolean def) { public void postprocess() { SourceRoot sr = new SourceRoot(root); - Map changedFiles = new HashMap(); try { sr.parse("", new SourceRoot.Callback() { @Override @@ -84,19 +76,9 @@ public com.github.javaparser.utils.SourceRoot.Callback.Result process(Path local if (unit.getPrimaryType().isPresent()) { TypeDeclaration type = unit.getPrimaryType().get(); postprocess(unit, type); - - // save to a temporary file first, then move all temporary unit files at the same time - try { - unit.setStorage(Files.createTempFile(null, null), - sr.getParserConfiguration().getCharacterEncoding()) - .getStorage().get().save(sr.getPrinter()); - } catch (IOException ex) { - throw new RuntimeException(ex); - } - - changedFiles.put(unit.getStorage().get().getPath(), absolutePath); - return Result.DONT_SAVE; + return Result.SAVE; } + } else { // Compilation issue - report and skip log.errorf( @@ -108,33 +90,9 @@ public com.github.javaparser.utils.SourceRoot.Callback.Result process(Path local return Result.DONT_SAVE; } }); - - changedFiles.entrySet().forEach(new Consumer>() { - @Override - public void accept(Entry entry) { - try { - Files.move(entry.getKey(), entry.getValue(), StandardCopyOption.REPLACE_EXISTING); - } catch (IOException ex) { - throw new RuntimeException(ex); - } - } - }); - changedFiles.clear(); - } catch (Exception e) { // read issue, report and exit log.error("Unable to parse the classes generated using protoc - skipping gRPC post processing", e); - } finally { - changedFiles.entrySet().forEach(new Consumer>() { - @Override - public void accept(Entry e) { - try { - Files.deleteIfExists(e.getKey()); - } catch (IOException discard) { - // Ignore it. - } - } - }); } } diff --git a/extensions/kubernetes-client/deployment/pom.xml b/extensions/kubernetes-client/deployment/pom.xml index bd989bda54851..0f4acad427f0b 100644 --- a/extensions/kubernetes-client/deployment/pom.xml +++ b/extensions/kubernetes-client/deployment/pom.xml @@ -29,6 +29,11 @@ io.quarkus quarkus-vertx-deployment + + io.quarkus + quarkus-junit5-internal + test + diff --git a/extensions/kubernetes-client/deployment/src/test/java/io/quarkus/kubernetes/client/deployment/KubernetesClientCDITest.java b/extensions/kubernetes-client/deployment/src/test/java/io/quarkus/kubernetes/client/deployment/KubernetesClientCDITest.java new file mode 100644 index 0000000000000..d9202ab71d5ba --- /dev/null +++ b/extensions/kubernetes-client/deployment/src/test/java/io/quarkus/kubernetes/client/deployment/KubernetesClientCDITest.java @@ -0,0 +1,40 @@ +package io.quarkus.kubernetes.client.deployment; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import jakarta.inject.Inject; +import jakarta.inject.Singleton; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.fabric8.kubernetes.client.Config; +import io.fabric8.kubernetes.client.KubernetesClient; +import io.quarkus.kubernetes.client.KubernetesConfigCustomizer; +import io.quarkus.test.QuarkusUnitTest; + +public class KubernetesClientCDITest { + + @Inject + KubernetesClient client; + + @Test + public void test() { + assertEquals("-1", client.getConfiguration().getApiVersion()); + } + + @RegisterExtension + static QuarkusUnitTest runner = new QuarkusUnitTest() + .withApplicationRoot((jar) -> jar + .addClasses(Customizer.class)) + .overrideConfigKey("quarkus.kubernetes-client.devservices.enabled", "false"); + + @Singleton + public static class Customizer implements KubernetesConfigCustomizer { + @Override + public void customize(Config config) { + config.setApiVersion("-1"); + } + } + +} diff --git a/extensions/kubernetes-client/runtime/src/main/java/io/quarkus/kubernetes/client/KubernetesConfigCustomizer.java b/extensions/kubernetes-client/runtime/src/main/java/io/quarkus/kubernetes/client/KubernetesConfigCustomizer.java new file mode 100644 index 0000000000000..1ff0a573bfe7c --- /dev/null +++ b/extensions/kubernetes-client/runtime/src/main/java/io/quarkus/kubernetes/client/KubernetesConfigCustomizer.java @@ -0,0 +1,25 @@ +package io.quarkus.kubernetes.client; + +import java.util.List; + +import io.fabric8.kubernetes.client.Config; +import io.fabric8.kubernetes.client.KubernetesClient; +import io.quarkus.kubernetes.client.runtime.KubernetesClientBuildConfig; +import io.quarkus.kubernetes.client.runtime.KubernetesClientProducer; +import io.quarkus.kubernetes.client.runtime.KubernetesConfigProducer; +import io.quarkus.runtime.TlsConfig; + +/** + * Meant to be implemented by a CDI bean that provided arbitrary customization for the default {@link Config} created by + * Quarkus. + *

+ * The {@link Config} is in turn used to produce the default {@link KubernetesClient} + *

+ * + * @see KubernetesConfigProducer#config(KubernetesClientBuildConfig, TlsConfig, List) } + * @see KubernetesClientProducer#kubernetesClient(Config) } + */ +public interface KubernetesConfigCustomizer { + + void customize(Config config); +} diff --git a/extensions/kubernetes-client/runtime/src/main/java/io/quarkus/kubernetes/client/runtime/KubernetesConfigProducer.java b/extensions/kubernetes-client/runtime/src/main/java/io/quarkus/kubernetes/client/runtime/KubernetesConfigProducer.java index 8c9bf33a70da1..468f092ea28a1 100644 --- a/extensions/kubernetes-client/runtime/src/main/java/io/quarkus/kubernetes/client/runtime/KubernetesConfigProducer.java +++ b/extensions/kubernetes-client/runtime/src/main/java/io/quarkus/kubernetes/client/runtime/KubernetesConfigProducer.java @@ -1,10 +1,14 @@ package io.quarkus.kubernetes.client.runtime; +import java.util.List; + import jakarta.enterprise.inject.Produces; import jakarta.inject.Singleton; import io.fabric8.kubernetes.client.Config; +import io.quarkus.arc.All; import io.quarkus.arc.DefaultBean; +import io.quarkus.kubernetes.client.KubernetesConfigCustomizer; import io.quarkus.runtime.TlsConfig; @Singleton @@ -13,7 +17,13 @@ public class KubernetesConfigProducer { @DefaultBean @Singleton @Produces - public Config config(KubernetesClientBuildConfig buildConfig, TlsConfig tlsConfig) { - return KubernetesClientUtils.createConfig(buildConfig, tlsConfig); + public Config config(KubernetesClientBuildConfig buildConfig, + TlsConfig tlsConfig, + @All List customizers) { + var result = KubernetesClientUtils.createConfig(buildConfig, tlsConfig); + for (KubernetesConfigCustomizer customizer : customizers) { + customizer.customize(result); + } + return result; } } diff --git a/extensions/resteasy-classic/resteasy/runtime/src/main/java/io/quarkus/resteasy/runtime/standalone/ResteasyStandaloneRecorder.java b/extensions/resteasy-classic/resteasy/runtime/src/main/java/io/quarkus/resteasy/runtime/standalone/ResteasyStandaloneRecorder.java index 9a290ac4a2c11..729a962356e6f 100644 --- a/extensions/resteasy-classic/resteasy/runtime/src/main/java/io/quarkus/resteasy/runtime/standalone/ResteasyStandaloneRecorder.java +++ b/extensions/resteasy-classic/resteasy/runtime/src/main/java/io/quarkus/resteasy/runtime/standalone/ResteasyStandaloneRecorder.java @@ -17,6 +17,7 @@ import io.quarkus.runtime.ShutdownContext; import io.quarkus.runtime.annotations.Recorder; import io.quarkus.security.AuthenticationCompletionException; +import io.quarkus.security.AuthenticationException; import io.quarkus.security.AuthenticationFailedException; import io.quarkus.security.AuthenticationRedirectException; import io.quarkus.security.ForbiddenException; @@ -126,9 +127,7 @@ public void handle(RoutingContext request) { } } - if (request.failure() instanceof AuthenticationFailedException - || request.failure() instanceof AuthenticationCompletionException - || request.failure() instanceof AuthenticationRedirectException + if (request.failure() instanceof AuthenticationException || request.failure() instanceof ForbiddenException) { super.handle(request); } else { diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive-common/deployment/src/main/java/io/quarkus/resteasy/reactive/common/deployment/VetoingAnnotationTransformer.java b/extensions/resteasy-reactive/quarkus-resteasy-reactive-common/deployment/src/main/java/io/quarkus/resteasy/reactive/common/deployment/VetoingAnnotationTransformer.java index 9e6e796402319..ea8835bf6002f 100644 --- a/extensions/resteasy-reactive/quarkus-resteasy-reactive-common/deployment/src/main/java/io/quarkus/resteasy/reactive/common/deployment/VetoingAnnotationTransformer.java +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive-common/deployment/src/main/java/io/quarkus/resteasy/reactive/common/deployment/VetoingAnnotationTransformer.java @@ -13,7 +13,7 @@ * then we need to make sure that Arc doesn't create a bean for it automatically (as it will fail validation because * there is no way to pass the parameter). * For these resources we add {@link jakarta.enterprise.inject.Vetoed}, and we generate custom CDI producers under the hood - * in {@link CustomResourceProducersGenerator#generate}. + * in {@code io.quarkus.resteasy.reactive.server.deployment.CustomResourceProducersGenerator#generate}. */ public class VetoingAnnotationTransformer implements AnnotationsTransformer { diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive-common/runtime/src/main/java/io/quarkus/resteasy/reactive/common/runtime/JaxRsSecurityConfig.java b/extensions/resteasy-reactive/quarkus-resteasy-reactive-common/runtime/src/main/java/io/quarkus/resteasy/reactive/common/runtime/JaxRsSecurityConfig.java index 394d53631bfc4..b635f86edb217 100644 --- a/extensions/resteasy-reactive/quarkus-resteasy-reactive-common/runtime/src/main/java/io/quarkus/resteasy/reactive/common/runtime/JaxRsSecurityConfig.java +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive-common/runtime/src/main/java/io/quarkus/resteasy/reactive/common/runtime/JaxRsSecurityConfig.java @@ -23,7 +23,7 @@ public interface JaxRsSecurityConfig { * If no security annotations are affecting a method then they will default to requiring these roles, * (equivalent to adding an @RolesAllowed annotation with the roles to every endpoint class). * - * The role of '**' means any authenticated user, which is equivalent to the {@link io.quarkus.security.Authenticated} + * The role of '**' means any authenticated user, which is equivalent to the {@code io.quarkus.security.Authenticated} * annotation. */ Optional> defaultRolesAllowed(); diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive-common/runtime/src/main/java/io/quarkus/resteasy/reactive/common/runtime/ResteasyReactiveCommonRecorder.java b/extensions/resteasy-reactive/quarkus-resteasy-reactive-common/runtime/src/main/java/io/quarkus/resteasy/reactive/common/runtime/ResteasyReactiveCommonRecorder.java index 1fdc0c5aa0467..b5044a6331e8e 100644 --- a/extensions/resteasy-reactive/quarkus-resteasy-reactive-common/runtime/src/main/java/io/quarkus/resteasy/reactive/common/runtime/ResteasyReactiveCommonRecorder.java +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive-common/runtime/src/main/java/io/quarkus/resteasy/reactive/common/runtime/ResteasyReactiveCommonRecorder.java @@ -1,7 +1,5 @@ package io.quarkus.resteasy.reactive.common.runtime; -import java.util.Collections; -import java.util.HashMap; import java.util.Map; import org.jboss.resteasy.reactive.common.core.Serialisers; @@ -14,19 +12,15 @@ @Recorder public class ResteasyReactiveCommonRecorder { - private static final Map> primitiveTypes; - static { - Map> prims = new HashMap<>(); - prims.put(byte.class.getName(), byte.class); - prims.put(boolean.class.getName(), boolean.class); - prims.put(char.class.getName(), char.class); - prims.put(short.class.getName(), short.class); - prims.put(int.class.getName(), int.class); - prims.put(float.class.getName(), float.class); - prims.put(double.class.getName(), double.class); - prims.put(long.class.getName(), long.class); - primitiveTypes = Collections.unmodifiableMap(prims); - } + private static final Map> primitiveTypes = Map.of( + byte.class.getName(), byte.class, + boolean.class.getName(), boolean.class, + char.class.getName(), char.class, + short.class.getName(), short.class, + int.class.getName(), int.class, + float.class.getName(), float.class, + double.class.getName(), double.class, + long.class.getName(), long.class); public BeanFactory factory(String targetClass, BeanContainer beanContainer) { return new ArcBeanFactory<>(loadClass(targetClass), diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive-kotlin/deployment/src/main/java/io/quarkus/resteasy/reactive/kotlin/deployment/KotlinCoroutineIntegrationProcessor.java b/extensions/resteasy-reactive/quarkus-resteasy-reactive-kotlin/deployment/src/main/java/io/quarkus/resteasy/reactive/kotlin/deployment/KotlinCoroutineIntegrationProcessor.java index a8bea26a4f378..251197554ed3a 100644 --- a/extensions/resteasy-reactive/quarkus-resteasy-reactive-kotlin/deployment/src/main/java/io/quarkus/resteasy/reactive/kotlin/deployment/KotlinCoroutineIntegrationProcessor.java +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive-kotlin/deployment/src/main/java/io/quarkus/resteasy/reactive/kotlin/deployment/KotlinCoroutineIntegrationProcessor.java @@ -125,7 +125,7 @@ public boolean isMethodSignatureAsync(MethodInfo info) { * This method generates the same invocation code as for the standard invoker but also passes along the implicit * {@code Continuation} argument provided by kotlinc and the coroutines library. * - * @see io.quarkus.resteasy.reactive.server.deployment.QuarkusInvokerFactory#create(ResourceMethod, ClassInfo, MethodInfo) + * See: io.quarkus.resteasy.reactive.server.deployment.QuarkusInvokerFactory#create(ResourceMethod, ClassInfo, MethodInfo) */ private Supplier createCoroutineInvoker(ClassInfo currentClassInfo, MethodInfo info, BuildProducer generatedClassBuildItemBuildProducer, diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/customexceptions/UniExceptionMapper.java b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/customexceptions/UniExceptionMapper.java index ee5f1e771f520..d86e45824db5b 100644 --- a/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/customexceptions/UniExceptionMapper.java +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/customexceptions/UniExceptionMapper.java @@ -9,7 +9,7 @@ public class UniExceptionMapper { @ServerExceptionMapper({ UniException.class, OtherUniException.class }) - Uni handleUni(Throwable t) { + Uni handleUni(UniException t) { return Uni.createFrom().deferred(() -> Uni.createFrom().item(Response.status(413).build())); } diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/java/io/quarkus/resteasy/reactive/server/runtime/ResteasyReactiveRecorder.java b/extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/java/io/quarkus/resteasy/reactive/server/runtime/ResteasyReactiveRecorder.java index e6ec3e33e8405..3ff0d288fd070 100644 --- a/extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/java/io/quarkus/resteasy/reactive/server/runtime/ResteasyReactiveRecorder.java +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/java/io/quarkus/resteasy/reactive/server/runtime/ResteasyReactiveRecorder.java @@ -53,6 +53,7 @@ import io.quarkus.runtime.ShutdownContext; import io.quarkus.runtime.annotations.Recorder; import io.quarkus.security.AuthenticationCompletionException; +import io.quarkus.security.AuthenticationException; import io.quarkus.security.AuthenticationFailedException; import io.quarkus.security.AuthenticationRedirectException; import io.quarkus.security.ForbiddenException; @@ -255,9 +256,7 @@ public void handle(RoutingContext event) { } } - if (event.failure() instanceof AuthenticationFailedException - || event.failure() instanceof AuthenticationCompletionException - || event.failure() instanceof AuthenticationRedirectException + if (event.failure() instanceof AuthenticationException || event.failure() instanceof ForbiddenException) { restInitialHandler.beginProcessing(event, event.failure()); } else { diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/java/io/quarkus/resteasy/reactive/server/runtime/ResteasyReactiveRuntimeRecorder.java b/extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/java/io/quarkus/resteasy/reactive/server/runtime/ResteasyReactiveRuntimeRecorder.java index af2fa0ff05c17..3841f55a4130c 100644 --- a/extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/java/io/quarkus/resteasy/reactive/server/runtime/ResteasyReactiveRuntimeRecorder.java +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/java/io/quarkus/resteasy/reactive/server/runtime/ResteasyReactiveRuntimeRecorder.java @@ -49,7 +49,7 @@ public RuntimeConfiguration get() { }; } - @SuppressWarnings({ "unchecked", "rawtypes" }) + @SuppressWarnings({ "unchecked", "rawtypes", "ForLoopReplaceableByForEach" }) public void configureHandlers(RuntimeValue deployment, Map, Supplier> runtimeConfigMap) { List> runtimeConfigurableServerRestHandlers = deployment.getValue() .getRuntimeConfigurableServerRestHandlers(); diff --git a/extensions/resteasy-reactive/rest-client-reactive-jackson/runtime/src/main/java/io/quarkus/rest/client/reactive/jackson/runtime/serialisers/ClientJacksonMessageBodyWriter.java b/extensions/resteasy-reactive/rest-client-reactive-jackson/runtime/src/main/java/io/quarkus/rest/client/reactive/jackson/runtime/serialisers/ClientJacksonMessageBodyWriter.java index 1ba281fc8c3e8..98a52d39391fe 100644 --- a/extensions/resteasy-reactive/rest-client-reactive-jackson/runtime/src/main/java/io/quarkus/rest/client/reactive/jackson/runtime/serialisers/ClientJacksonMessageBodyWriter.java +++ b/extensions/resteasy-reactive/rest-client-reactive-jackson/runtime/src/main/java/io/quarkus/rest/client/reactive/jackson/runtime/serialisers/ClientJacksonMessageBodyWriter.java @@ -49,7 +49,7 @@ public void writeTo(Object o, Class type, Type genericType, Annotation[] anno @Override public void handle(RestClientRequestContext requestContext) throws Exception { - this.context = context; + this.context = requestContext; } protected ObjectWriter getEffectiveWriter() { diff --git a/extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/ResteasyReactiveResponseRedirectHandler.java b/extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/ResteasyReactiveResponseRedirectHandler.java index 1dcf290e69ee9..13eb6a5bf53aa 100644 --- a/extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/ResteasyReactiveResponseRedirectHandler.java +++ b/extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/ResteasyReactiveResponseRedirectHandler.java @@ -15,6 +15,6 @@ default URI handle(Response response) { @Override default RedirectHandler getContext(Class aClass) { - return response -> handle(response); + return this::handle; } } diff --git a/extensions/security/spi/src/main/java/io/quarkus/security/spi/SecurityTransformerUtils.java b/extensions/security/spi/src/main/java/io/quarkus/security/spi/SecurityTransformerUtils.java index 3ef23c2c71644..ef74b21eee167 100644 --- a/extensions/security/spi/src/main/java/io/quarkus/security/spi/SecurityTransformerUtils.java +++ b/extensions/security/spi/src/main/java/io/quarkus/security/spi/SecurityTransformerUtils.java @@ -1,8 +1,5 @@ package io.quarkus.security.spi; -import static java.util.Arrays.asList; - -import java.util.HashSet; import java.util.Set; import jakarta.annotation.security.DenyAll; @@ -21,17 +18,10 @@ */ public class SecurityTransformerUtils { public static final DotName DENY_ALL = DotName.createSimple(DenyAll.class.getName()); - private static final Set SECURITY_ANNOTATIONS; - - static { - SECURITY_ANNOTATIONS = new HashSet<>(); - // keep the contents the same as in io.quarkus.security.deployment.SecurityAnnotationsRegistrar - SECURITY_ANNOTATIONS.addAll(asList( - DotName.createSimple(RolesAllowed.class.getName()), - DotName.createSimple(Authenticated.class.getName()), - DotName.createSimple(DenyAll.class.getName()), - DotName.createSimple(PermitAll.class.getName()))); - } + private static final Set SECURITY_ANNOTATIONS = Set.of(DotName.createSimple(RolesAllowed.class.getName()), + DotName.createSimple(Authenticated.class.getName()), + DotName.createSimple(DenyAll.class.getName()), + DotName.createSimple(PermitAll.class.getName())); public static boolean hasSecurityAnnotation(MethodInfo methodInfo) { for (AnnotationInstance annotation : methodInfo.annotations()) { diff --git a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/QuarkusErrorHandler.java b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/QuarkusErrorHandler.java index 4468e6da3571b..8090d1c4e2e31 100644 --- a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/QuarkusErrorHandler.java +++ b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/QuarkusErrorHandler.java @@ -18,9 +18,7 @@ import io.netty.handler.codec.http.HttpHeaderNames; import io.netty.handler.codec.http.HttpResponseStatus; import io.quarkus.runtime.TemplateHtmlBuilder; -import io.quarkus.security.AuthenticationCompletionException; -import io.quarkus.security.AuthenticationFailedException; -import io.quarkus.security.AuthenticationRedirectException; +import io.quarkus.security.AuthenticationException; import io.quarkus.security.ForbiddenException; import io.quarkus.security.UnauthorizedException; import io.quarkus.vertx.http.runtime.security.HttpAuthenticator; @@ -82,9 +80,7 @@ public void accept(Throwable throwable) { return; } - if (event.failure() instanceof AuthenticationFailedException - || event.failure() instanceof AuthenticationCompletionException - || event.failure() instanceof AuthenticationRedirectException) { + if (event.failure() instanceof AuthenticationException) { if (event.response().getStatusCode() == HttpResponseStatus.OK.code()) { //set 401 if status wasn't set upstream diff --git a/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/HandlerChain.java b/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/HandlerChain.java index c518a68c629aa..af7e1f76ae881 100644 --- a/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/HandlerChain.java +++ b/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/HandlerChain.java @@ -20,6 +20,7 @@ import org.jboss.resteasy.reactive.client.spi.MultipartResponseData; import org.jboss.resteasy.reactive.common.jaxrs.ConfigurationImpl; +@SuppressWarnings("ForLoopReplaceableByForEach") class HandlerChain { private static final ClientRestHandler[] EMPTY_REST_HANDLERS = new ClientRestHandler[0]; diff --git a/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/MultiInvoker.java b/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/MultiInvoker.java index ead3b0a0ef12a..e3a8820add5f4 100644 --- a/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/MultiInvoker.java +++ b/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/MultiInvoker.java @@ -159,18 +159,12 @@ private void registerForSse(MultiRequest multiRequest, SseEventSourceImpl sseSource = new SseEventSourceImpl(invocationBuilder.getTarget(), invocationBuilder, Integer.MAX_VALUE, TimeUnit.SECONDS); - multiRequest.onCancel(() -> { - sseSource.close(); - }); + multiRequest.onCancel(sseSource::close); sseSource.register(event -> { // DO NOT pass the response mime type because it's SSE: let the event pick between the X-SSE-Content-Type header or // the content-type SSE field multiRequest.emit(event.readData(responseType)); - }, error -> { - multiRequest.fail(error); - }, () -> { - multiRequest.complete(); - }); + }, multiRequest::fail, multiRequest::complete); // watch for user cancelling sseSource.registerAfterRequest(vertxResponse); } diff --git a/independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/EndpointIndexer.java b/independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/EndpointIndexer.java index 86008ba946ea9..20a679649c4b2 100644 --- a/independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/EndpointIndexer.java +++ b/independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/EndpointIndexer.java @@ -82,7 +82,6 @@ import java.nio.charset.StandardCharsets; import java.util.AbstractMap; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -135,22 +134,15 @@ public abstract class EndpointIndexer primitiveTypes; private static final Map> supportedReaderJavaTypes; + // spec // NOTE: sync with ContextProducer and ContextParamExtractor - private static final Set DEFAULT_CONTEXT_TYPES = Collections.unmodifiableSet(new HashSet<>(Arrays.asList( - // spec - URI_INFO, - HTTP_HEADERS, - REQUEST, - SECURITY_CONTEXT, - PROVIDERS, - RESOURCE_CONTEXT, - CONFIGURATION, - SSE, + private static final Set DEFAULT_CONTEXT_TYPES = Set.of(URI_INFO, HTTP_HEADERS, REQUEST, SECURITY_CONTEXT, + PROVIDERS, RESOURCE_CONTEXT, CONFIGURATION, SSE, SSE_EVENT_SINK, // extras SERVER_REQUEST_CONTEXT, DotName.createSimple("org.jboss.resteasy.reactive.server.SimpleResourceInfo"), //TODO: fixme - RESOURCE_INFO))); + RESOURCE_INFO); protected static final Set SUPPORT_TEMPORAL_PARAMS = Set.of(INSTANT, LOCAL_DATE, LOCAL_TIME, LOCAL_DATE_TIME, OFFSET_TIME, diff --git a/independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/HashUtil.java b/independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/HashUtil.java index 0fd5dc157e78f..1b01d6e14c875 100644 --- a/independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/HashUtil.java +++ b/independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/HashUtil.java @@ -4,6 +4,7 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +@SuppressWarnings("ForLoopReplaceableByForEach") public final class HashUtil { private HashUtil() { diff --git a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/PathPart.java b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/PathPart.java index 371cdd51be0e4..2db41c88b7adf 100644 --- a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/PathPart.java +++ b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/PathPart.java @@ -28,7 +28,7 @@ public class PathPart { /** * Create a new partial {@link Path} object. * - * @param path The file to send + * @param file The file to send * @param offset The starting byte of the file (must be >= 0) * @param count The number of bytes to send (must be >= 0 and offset+count <= file size) */ 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 9daa23b1097ff..b214cc5691aab 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 @@ -28,6 +28,7 @@ import org.jboss.resteasy.reactive.common.util.QuarkusMultivaluedHashMap; import org.jboss.resteasy.reactive.common.util.QuarkusMultivaluedMap; +@SuppressWarnings("ForLoopReplaceableByForEach") public abstract class Serialisers { public static final Annotation[] NO_ANNOTATION = new Annotation[0]; public static final ReaderInterceptor[] NO_READER_INTERCEPTOR = new ReaderInterceptor[0]; diff --git a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/jaxrs/ResponseImpl.java b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/jaxrs/ResponseImpl.java index b35ef6614dd65..6d167482c9456 100644 --- a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/jaxrs/ResponseImpl.java +++ b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/jaxrs/ResponseImpl.java @@ -36,7 +36,7 @@ * This is the Response class for user-created responses. The client response * object has more deserialising powers in @{link {@link io.quarkus.rest.server.runtime.client.QuarkusRestClientResponse}. */ -@SuppressWarnings("JavadocReference") +@SuppressWarnings({ "JavadocReference", "ForLoopReplaceableByForEach" }) public class ResponseImpl extends Response { int status; diff --git a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/jaxrs/RestResponseImpl.java b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/jaxrs/RestResponseImpl.java index 142ebb122bc2c..3f3dbb2a5fcbb 100644 --- a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/jaxrs/RestResponseImpl.java +++ b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/jaxrs/RestResponseImpl.java @@ -37,7 +37,7 @@ * This is the Response class for user-created responses. The client response * object has more deserialising powers in @{link {@link io.quarkus.rest.server.runtime.client.QuarkusRestClientResponse}. */ -@SuppressWarnings("JavadocReference") +@SuppressWarnings({ "JavadocReference", "ForLoopReplaceableByForEach" }) public class RestResponseImpl extends RestResponse { int status; 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 538c6194e5a48..23930a80f5858 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 @@ -13,6 +13,7 @@ import org.jboss.resteasy.reactive.common.util.MediaTypeHelper; import org.jboss.resteasy.reactive.spi.BeanFactory; +@SuppressWarnings("ForLoopReplaceableByForEach") public class ResourceReader { private BeanFactory> factory; 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 dae02708bc64e..5de3a260ba4ed 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 @@ -15,6 +15,7 @@ import org.jboss.resteasy.reactive.common.util.ServerMediaType; import org.jboss.resteasy.reactive.spi.BeanFactory; +@SuppressWarnings("ForLoopReplaceableByForEach") public class ResourceWriter { private BeanFactory> factory; diff --git a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/util/DeploymentUtils.java b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/util/DeploymentUtils.java index 16ac21ebbe4d6..95694a4dbf612 100644 --- a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/util/DeploymentUtils.java +++ b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/util/DeploymentUtils.java @@ -1,7 +1,5 @@ package org.jboss.resteasy.reactive.common.util; -import java.util.Collections; -import java.util.HashMap; import java.util.Map; import org.jboss.resteasy.reactive.common.core.Serialisers; @@ -9,20 +7,15 @@ import org.jboss.resteasy.reactive.common.model.ResourceWriter; public abstract class DeploymentUtils { - private static final Map> primitiveTypes; - - static { - Map> prims = new HashMap<>(); - prims.put(byte.class.getName(), byte.class); - prims.put(boolean.class.getName(), boolean.class); - prims.put(char.class.getName(), char.class); - prims.put(short.class.getName(), short.class); - prims.put(int.class.getName(), int.class); - prims.put(float.class.getName(), float.class); - prims.put(double.class.getName(), double.class); - prims.put(long.class.getName(), long.class); - primitiveTypes = Collections.unmodifiableMap(prims); - } + private static final Map> primitiveTypes = Map.of( + byte.class.getName(), byte.class, + boolean.class.getName(), boolean.class, + char.class.getName(), char.class, + short.class.getName(), short.class, + int.class.getName(), int.class, + float.class.getName(), float.class, + double.class.getName(), double.class, + long.class.getName(), long.class); public static void registerWriter(Serialisers serialisers, String entityClassName, ResourceWriter writer) { 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 eeea0e58cfd2a..81cedd7b62c60 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 @@ -15,7 +15,7 @@ /** * @author Bill Burke */ -@SuppressWarnings(value = "rawtypes") +@SuppressWarnings({ "ForLoopReplaceableByForEach" }) public class MediaTypeHelper { public static final MediaTypeComparator Q_COMPARATOR = new MediaTypeComparator("q"); public static final MediaTypeComparator QS_COMPARATOR = new MediaTypeComparator("qs"); diff --git a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/util/ParameterParser.java b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/util/ParameterParser.java index fe2652ced1323..8812bf5d23577 100644 --- a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/util/ParameterParser.java +++ b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/util/ParameterParser.java @@ -15,6 +15,7 @@ * @author Oleg Kalnichevski */ +@SuppressWarnings("ForLoopReplaceableByForEach") public class ParameterParser { /** * String to be parsed. diff --git a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/util/types/TypeVariableImpl.java b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/util/types/TypeVariableImpl.java index 4ef44b7adcbb3..fa06da739cab6 100644 --- a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/util/types/TypeVariableImpl.java +++ b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/util/types/TypeVariableImpl.java @@ -10,6 +10,7 @@ public class TypeVariableImpl implements TypeVariable { + private static final Type[] EMPTY_TYPES_ARRAY = new Type[0]; private final String name; private final List bounds; @@ -36,7 +37,7 @@ public Annotation[] getDeclaredAnnotations() { @Override public Type[] getBounds() { - return bounds.toArray(new Type[bounds.size()]); + return bounds.toArray(EMPTY_TYPES_ARRAY); } @Override diff --git a/independent-projects/resteasy-reactive/server/processor/src/main/java/org/jboss/resteasy/reactive/server/processor/generation/exceptionmappers/ServerExceptionMapperGenerator.java b/independent-projects/resteasy-reactive/server/processor/src/main/java/org/jboss/resteasy/reactive/server/processor/generation/exceptionmappers/ServerExceptionMapperGenerator.java index 878d38bfadaa6..2782c62bcbecd 100644 --- a/independent-projects/resteasy-reactive/server/processor/src/main/java/org/jboss/resteasy/reactive/server/processor/generation/exceptionmappers/ServerExceptionMapperGenerator.java +++ b/independent-projects/resteasy-reactive/server/processor/src/main/java/org/jboss/resteasy/reactive/server/processor/generation/exceptionmappers/ServerExceptionMapperGenerator.java @@ -18,8 +18,8 @@ import static org.jboss.resteasy.reactive.server.processor.util.ResteasyReactiveServerDotNames.SIMPLIFIED_RESOURCE_INFO; import java.lang.reflect.Modifier; -import java.util.Arrays; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -123,7 +123,7 @@ public static Map generatePerClassMapper(MethodInfo targetMethod Map result = new HashMap<>(); boolean handlesMultipleExceptions = handledExceptionTypes.length > 1; - boolean handledContainsThrowable = Arrays.stream(handledExceptionTypes).anyMatch(t -> t.name().equals(THROWABLE)); + Set commonHierarchyOfExceptions = getCommonHierarchyOfExceptions(handledExceptionTypes); for (Type handledExceptionType : handledExceptionTypes) { String generatedClassName = getGeneratedClassName(targetMethod, handledExceptionType); @@ -155,7 +155,7 @@ public static Map generatePerClassMapper(MethodInfo targetMethod // RESTEasy Reactive toResponse(...) method generateRRResponse(targetMethod, targetClass, handledExceptionType, cc, rrToResponseDescriptor, - returnType, handlesMultipleExceptions, handledContainsThrowable, + returnType, handlesMultipleExceptions, commonHierarchyOfExceptions, (method, contextHandle) -> { ResultHandle endpointInstanceHandle = method.invokeVirtualMethod( ofMethod(ResteasyReactiveRequestContext.class, "getEndpointInstance", Object.class), @@ -173,7 +173,7 @@ public static Map generatePerClassMapper(MethodInfo targetMethod // RESTEasy Reactive asyncResponse(...) method generateRRUniResponse(targetMethod, targetClass, handledExceptionType, cc, rrAsyncResponseDescriptor, - returnType, handlesMultipleExceptions, handledContainsThrowable, + returnType, handlesMultipleExceptions, commonHierarchyOfExceptions, (method, contextHandle) -> { ResultHandle endpointInstanceHandle = method.invokeVirtualMethod( ofMethod(ResteasyReactiveRequestContext.class, "getEndpointInstance", Object.class), @@ -251,7 +251,7 @@ public static Map generateGlobalMapper(MethodInfo targetMethod, Map result = new HashMap<>(); boolean handlesMultipleExceptions = handledExceptionTypes.length > 1; - boolean handledContainsThrowable = Arrays.stream(handledExceptionTypes).anyMatch(t -> t.name().equals(THROWABLE)); + Set commonHierarchyOfExceptions = getCommonHierarchyOfExceptions(handledExceptionTypes); for (Type handledExceptionType : handledExceptionTypes) { String generatedClassName = getGeneratedClassName(targetMethod, handledExceptionType); @@ -311,7 +311,7 @@ public static Map generateGlobalMapper(MethodInfo targetMethod, // RESTEasy Reactive toResponse(...) method generateRRResponse(targetMethod, targetClass, handledExceptionType, cc, rrToResponseDescriptor, - returnType, handlesMultipleExceptions, handledContainsThrowable, + returnType, handlesMultipleExceptions, commonHierarchyOfExceptions, (method, contextHandle) -> method.readInstanceField(delegateField, method.getThis()), unwrappableTypes); } else if (returnType == ReturnType.UNI_RESPONSE || returnType == ReturnType.UNI_REST_RESPONSE) { @@ -325,7 +325,7 @@ public static Map generateGlobalMapper(MethodInfo targetMethod, // RESTEasy Reactive asyncResponse(...) method generateRRUniResponse(targetMethod, targetClass, handledExceptionType, cc, rrAsyncResponseDescriptor, - returnType, handlesMultipleExceptions, handledContainsThrowable, + returnType, handlesMultipleExceptions, commonHierarchyOfExceptions, (method, contextHandle) -> method.readInstanceField(delegateField, method.getThis()), unwrappableTypes); } else { @@ -352,20 +352,15 @@ private static Type[] getHandledExceptionTypes(MethodInfo targetMethod) { List methodParameters = targetMethod.parameterTypes(); for (Type methodParameter : methodParameters) { if (methodParameter.kind() == Type.Kind.CLASS) { - try { - Class methodParameterClass = Class.forName(methodParameter.name().toString(), false, - Thread.currentThread().getContextClassLoader()); - if (Throwable.class.isAssignableFrom(methodParameterClass)) { - if (deducedHandledExceptionType != null) { - throw new IllegalArgumentException( - "Multiple method parameters found that extend 'Throwable'. When using '@ServerExceptionMapper', only one parameter can be of type 'Throwable'. Offending method is '" - + targetMethod.name() + "' of class '" - + targetMethod.declaringClass().name().toString() + "'"); - } - deducedHandledExceptionType = methodParameter; + Class methodParameterClass = getClassByName(methodParameter.name().toString()); + if (methodParameterClass != null && Throwable.class.isAssignableFrom(methodParameterClass)) { + if (deducedHandledExceptionType != null) { + throw new IllegalArgumentException( + "Multiple method parameters found that extend 'Throwable'. When using '@ServerExceptionMapper', only one parameter can be of type 'Throwable'. Offending method is '" + + targetMethod.name() + "' of class '" + + targetMethod.declaringClass().name().toString() + "'"); } - } catch (ClassNotFoundException ignored) { - + deducedHandledExceptionType = methodParameter; } } } @@ -377,6 +372,36 @@ private static Type[] getHandledExceptionTypes(MethodInfo targetMethod) { return new Type[] { deducedHandledExceptionType }; } + private static Set getCommonHierarchyOfExceptions(Type[] handledExceptions) { + Set commonHierarchy = new HashSet<>(); + boolean first = true; + for (Type handledException : handledExceptions) { + Class handledExceptionClass = getClassByName(handledException.name().toString()); + while (handledExceptionClass != null && !handledExceptionClass.equals(Throwable.class)) { + String handledExceptionClassName = handledExceptionClass.getName(); + if (first) { + commonHierarchy.add(handledExceptionClassName); + } else if (!commonHierarchy.contains(handledExceptionClassName)) { + commonHierarchy.remove(handledExceptionClassName); + } + + handledExceptionClass = handledExceptionClass.getSuperclass(); + } + + first = false; + } + + return commonHierarchy; + } + + private static Class getClassByName(String className) { + try { + return Class.forName(className, false, Thread.currentThread().getContextClassLoader()); + } catch (ClassNotFoundException ignored) { + return null; + } + } + private static MethodDescriptor toResponseDescriptor(Type handledExceptionType, String generatedClassName) { return ofMethod(generatedClassName, "toResponse", Response.class.getName(), @@ -432,7 +457,7 @@ private static void generateRRResponseBridge(Type handledExceptionType, ClassCre private static void generateRRResponse(MethodInfo targetMethod, ClassInfo targetClass, Type handledExceptionType, ClassCreator cc, MethodDescriptor rrToResponseDescriptor, - ReturnType returnType, boolean handlesMultipleExceptions, boolean handledContainsThrowable, + ReturnType returnType, boolean handlesMultipleExceptions, Set commonHierarchyOfExceptions, BiFunction targetInstanceHandleCreator, Set unwrappableTypes) { MethodCreator mc = cc.getMethodCreator(rrToResponseDescriptor); ResultHandle exceptionHandle = mc.getMethodParam(0); @@ -452,7 +477,7 @@ private static void generateRRResponse(MethodInfo targetMethod, ClassInfo target } else { TargetMethodParamsInfo targetMethodParamsInfo = getTargetMethodParamsInfo(targetMethod, targetClass, handledExceptionType, mc, exceptionHandle, contextHandle, handlesMultipleExceptions, - handledContainsThrowable, unwrappableTypes); + commonHierarchyOfExceptions, unwrappableTypes); ResultHandle resultHandle = mc.invokeVirtualMethod( ofMethod(targetClass.name().toString(), targetMethod.name(), targetMethod.returnType().name().toString(), targetMethodParamsInfo.getTypes()), @@ -479,7 +504,7 @@ private static void generateRRUniResponseBridge(Type handledExceptionType, Class private static void generateRRUniResponse(MethodInfo targetMethod, ClassInfo targetClass, Type handledExceptionType, ClassCreator cc, MethodDescriptor rrAsyncResponseDescriptor, - ReturnType returnType, boolean handlesMultipleExceptions, boolean handledContainsThrowable, + ReturnType returnType, boolean handlesMultipleExceptions, Set commonHierarchyOfExceptions, BiFunction targetInstanceHandleCreator, Set unwrappableTypes) { MethodCreator mc = cc.getMethodCreator(rrAsyncResponseDescriptor); ResultHandle exceptionHandle = mc.getMethodParam(0); @@ -498,7 +523,7 @@ private static void generateRRUniResponse(MethodInfo targetMethod, ClassInfo tar } else { TargetMethodParamsInfo targetMethodParamsInfo = getTargetMethodParamsInfo(targetMethod, targetClass, handledExceptionType, mc, exceptionHandle, contextHandle, handlesMultipleExceptions, - handledContainsThrowable, unwrappableTypes); + commonHierarchyOfExceptions, unwrappableTypes); uniHandle = mc.invokeVirtualMethod( ofMethod(targetClass.name().toString(), targetMethod.name(), Uni.class.getName(), targetMethodParamsInfo.getTypes()), @@ -512,7 +537,7 @@ private static void generateRRUniResponse(MethodInfo targetMethod, ClassInfo tar private static TargetMethodParamsInfo getTargetMethodParamsInfo(MethodInfo targetMethod, ClassInfo targetClass, Type handledExceptionType, MethodCreator mc, ResultHandle exceptionHandle, ResultHandle contextHandle, - boolean handlesMultipleExceptions, boolean handledContainsThrowable, Set unwrappableTypes) { + boolean handlesMultipleExceptions, Set commonHierarchyOfExceptions, Set unwrappableTypes) { List parameters = targetMethod.parameterTypes(); ResultHandle[] targetMethodParamHandles = new ResultHandle[parameters.size()]; String[] parameterTypes = new String[parameters.size()]; @@ -522,39 +547,19 @@ private static TargetMethodParamsInfo getTargetMethodParamsInfo(MethodInfo targe DotName paramDotName = parameter.name(); parameterTypes[i] = paramDotName.toString(); String parameterName = targetMethod.parameterName(i); - if (paramDotName.equals(handledExceptionType.name())) { - if (handlesMultipleExceptions) { + if (paramDotName.equals(THROWABLE)) { + targetMethodParamHandles[i] = exceptionHandle; + } else if (paramDotName.equals(handledExceptionType.name())) { + if (handlesMultipleExceptions && !commonHierarchyOfExceptions.contains(paramDotName.toString())) { throw new RuntimeException("Parameter '" + parameterName + "' of method '" + targetMethod.name() + " of class '" + targetClass.name() + "' cannot be of type '" + handledExceptionType.name() + "' because the method handles multiple exceptions. You can use '" - + (handledContainsThrowable ? Throwable.class.getName() : Exception.class.getName()) - + "' instead."); + + Throwable.class.getName() + "' instead."); } else { targetMethodParamHandles[i] = exceptionHandle; } - } else if (paramDotName.equals(THROWABLE)) { + } else if (commonHierarchyOfExceptions.contains(paramDotName.toString())) { targetMethodParamHandles[i] = exceptionHandle; - } else if (paramDotName.equals(EXCEPTION)) { - if (handlesMultipleExceptions) { - if (handledContainsThrowable) { - throw new RuntimeException("Parameter '" + parameterName + "' of method '" + targetMethod.name() - + " of class '" + targetClass.name() - + "' cannot be of type '" + handledExceptionType.name() - + "' because the method handles multiple exceptions. You can use '" + Exception.class.getName() - + "' instead."); - } else { - targetMethodParamHandles[i] = exceptionHandle; - } - } else { - if (handledContainsThrowable) { - throw new RuntimeException("Parameter '" + parameterName + "' of method '" + targetMethod.name() - + " of class '" + targetClass.name() - + "' cannot be of type '" + handledExceptionType.name() + "'. You can use '" - + Throwable.class.getName() + "' instead."); - } else { - targetMethodParamHandles[i] = exceptionHandle; - } - } } else if (paramDotName.equals(handledExceptionType.name())) { targetMethodParamHandles[i] = exceptionHandle; } else if (CONTAINER_REQUEST_CONTEXT.equals(paramDotName) diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/SseUtil.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/SseUtil.java index 200dc82a38748..da88aa6560dd5 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/SseUtil.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/SseUtil.java @@ -22,6 +22,7 @@ import org.jboss.resteasy.reactive.server.jaxrs.OutboundSseEventImpl; import org.jboss.resteasy.reactive.server.spi.ServerHttpResponse; +@SuppressWarnings("ForLoopReplaceableByForEach") public class SseUtil extends CommonSseUtil { private static final String NL = "\n"; diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/StreamingUtil.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/StreamingUtil.java index ecd59301f757b..ab04df5cff81c 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/StreamingUtil.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/StreamingUtil.java @@ -20,6 +20,7 @@ // FIXME: we need to refactor the serialisation of entities to bytes between here and Sse and Serialisers // and figure out where interceptors come into play +@SuppressWarnings("ForLoopReplaceableByForEach") public class StreamingUtil { public static CompletionStage send(ResteasyReactiveRequestContext context, diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/multipart/FormDataParser.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/multipart/FormDataParser.java index 86e342d7c1f67..d5b8ab0eceae2 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/multipart/FormDataParser.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/multipart/FormDataParser.java @@ -3,8 +3,6 @@ import java.io.Closeable; import java.io.IOException; -import org.jboss.resteasy.reactive.server.core.ResteasyReactiveRequestContext; - /** * Parser for form data. This can be used by down-stream handlers to parse * form data. @@ -25,9 +23,7 @@ public interface FormDataParser extends Closeable { void parse() throws Exception; /** - * Parse the data, blocking the current thread until parsing is complete. For blocking handlers this method is - * more efficient than {@link #parse(ResteasyReactiveRequestContext next)}, as the calling thread should do that - * actual parsing, rather than the read thread + * Parse the data, blocking the current thread until parsing is complete. * * @return The parsed form data * @throws IOException If the data could not be read diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/multipart/FormParserFactory.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/multipart/FormParserFactory.java index 8d382ed75a4b5..09af5098c8c36 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/multipart/FormParserFactory.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/multipart/FormParserFactory.java @@ -17,12 +17,13 @@ * * @author Stuart Douglas */ +@SuppressWarnings("ForLoopReplaceableByForEach") public class FormParserFactory { private final ParserDefinition[] parserDefinitions; FormParserFactory(final List parserDefinitions) { - this.parserDefinitions = parserDefinitions.toArray(new ParserDefinition[parserDefinitions.size()]); + this.parserDefinitions = parserDefinitions.toArray(new ParserDefinition[0]); } /** diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/multipart/MultipartMessageBodyWriter.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/multipart/MultipartMessageBodyWriter.java index 3e67e9b1e2d6b..a8ff157a4af84 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/multipart/MultipartMessageBodyWriter.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/multipart/MultipartMessageBodyWriter.java @@ -35,6 +35,7 @@ import org.jboss.resteasy.reactive.server.spi.ServerRequestContext; import org.jboss.resteasy.reactive.spi.BeanFactory; +@SuppressWarnings("ForLoopReplaceableByForEach") public class MultipartMessageBodyWriter extends ServerMessageBodyWriter.AllWriteableMessageBodyWriter { private static final String DOUBLE_DASH = "--"; diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/parameters/QueryParamExtractor.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/parameters/QueryParamExtractor.java index f6d31259de9bb..c8b7ddfa8fa1d 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/parameters/QueryParamExtractor.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/parameters/QueryParamExtractor.java @@ -6,6 +6,7 @@ import org.jboss.resteasy.reactive.server.core.ResteasyReactiveRequestContext; +@SuppressWarnings("ForLoopReplaceableByForEach") public class QueryParamExtractor implements ParameterExtractor { private final String name; diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/request/ServerDrivenNegotiation.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/request/ServerDrivenNegotiation.java index 28f8cb5ba0bc5..06feb1bd70913 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/request/ServerDrivenNegotiation.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/request/ServerDrivenNegotiation.java @@ -14,6 +14,7 @@ * @author Pascal S. de Kloe * @see "RFC 2296" */ +@SuppressWarnings("ForLoopReplaceableByForEach") public class ServerDrivenNegotiation { private Map requestedMediaTypes = null; diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/serialization/FixedEntityWriterArray.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/serialization/FixedEntityWriterArray.java index ba43b12513abf..24479e04762cf 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/serialization/FixedEntityWriterArray.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/serialization/FixedEntityWriterArray.java @@ -13,6 +13,7 @@ * A fixed entity writer that iterates an array of providers until it finds one that can handle * the given types. */ +@SuppressWarnings("ForLoopReplaceableByForEach") public class FixedEntityWriterArray implements EntityWriter { private final MessageBodyWriter[] writers; diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/startup/RuntimeDeploymentManager.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/startup/RuntimeDeploymentManager.java index 9cd376ea8f7af..9da3e62088016 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/startup/RuntimeDeploymentManager.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/startup/RuntimeDeploymentManager.java @@ -51,6 +51,7 @@ import org.jboss.resteasy.reactive.spi.BeanFactory; import org.jboss.resteasy.reactive.spi.ThreadSetupAction; +@SuppressWarnings("ForLoopReplaceableByForEach") public class RuntimeDeploymentManager { public static final ServerRestHandler[] EMPTY_REST_HANDLER_ARRAY = new ServerRestHandler[0]; private final DeploymentInfo info; diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/startup/RuntimeMappingDeployment.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/startup/RuntimeMappingDeployment.java index 8193685fbeb9b..6ef0814ec1ac5 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/startup/RuntimeMappingDeployment.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/startup/RuntimeMappingDeployment.java @@ -15,6 +15,7 @@ import org.jboss.resteasy.reactive.server.mapping.URITemplate; import org.jboss.resteasy.reactive.server.spi.ServerRestHandler; +@SuppressWarnings("ForLoopReplaceableByForEach") class RuntimeMappingDeployment { private final Map>>> classTemplates; 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 9de762ffa31ec..d40bdfbf3ec61 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 @@ -97,6 +97,7 @@ import org.jboss.resteasy.reactive.server.util.ScoreSystem; import org.jboss.resteasy.reactive.spi.BeanFactory; +@SuppressWarnings("ForLoopReplaceableByForEach") public class RuntimeResourceDeployment { private static final ServerRestHandler[] EMPTY_REST_HANDLER_ARRAY = new ServerRestHandler[0]; @@ -265,6 +266,7 @@ public RuntimeResource buildResourceMethod(ResourceClass clazz, for (ResourceRequestFilterHandler handler : containerRequestFilterHandlers) { if (handler.isWithFormRead()) { hasWithFormReadRequestFilters = true; + break; } } } diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/ClassRoutingHandler.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/ClassRoutingHandler.java index d7b04843a9240..96021b564068d 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/ClassRoutingHandler.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/ClassRoutingHandler.java @@ -25,6 +25,7 @@ import org.jboss.resteasy.reactive.server.mapping.RuntimeResource; import org.jboss.resteasy.reactive.server.spi.ServerRestHandler; +@SuppressWarnings("ForLoopReplaceableByForEach") public class ClassRoutingHandler implements ServerRestHandler { private static final String INVALID_ACCEPT_HEADER_MESSAGE = "The accept header value did not match the value in @Produces"; diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/FixedProducesHandler.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/FixedProducesHandler.java index 78ca786ccef8d..8029481fc125c 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/FixedProducesHandler.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/FixedProducesHandler.java @@ -18,6 +18,7 @@ * Handler that negotiates the content type for endpoints that * only produce a single type. */ +@SuppressWarnings("ForLoopReplaceableByForEach") public class FixedProducesHandler implements ServerRestHandler { final EncodedMediaType mediaType; diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/ResponseHandler.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/ResponseHandler.java index fc76d9fa445b5..5915c8baba032 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/ResponseHandler.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/ResponseHandler.java @@ -21,6 +21,7 @@ /** * Our job is to turn endpoint return types into Response instances */ +@SuppressWarnings("ForLoopReplaceableByForEach") public class ResponseHandler implements ServerRestHandler { public static final ResponseHandler NO_CUSTOMIZER_INSTANCE = new ResponseHandler(); @@ -247,6 +248,7 @@ public void customize(Response.ResponseBuilder responseBuilder) { } } + @SuppressWarnings("ForLoopReplaceableByForEach") class AddHeadersCustomizer implements ResponseBuilderCustomizer { private Map> headers; diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/jaxrs/UriInfoImpl.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/jaxrs/UriInfoImpl.java index a470d07b61f76..7cbd13cb272a6 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/jaxrs/UriInfoImpl.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/jaxrs/UriInfoImpl.java @@ -27,6 +27,7 @@ /** * UriInfo implementation */ +@SuppressWarnings("ForLoopReplaceableByForEach") public class UriInfoImpl implements UriInfo { private final ResteasyReactiveRequestContext currentRequest; diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/mapping/PathMatcher.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/mapping/PathMatcher.java index 6fdb256bdcb46..d13d30d0fddbe 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/mapping/PathMatcher.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/mapping/PathMatcher.java @@ -15,6 +15,7 @@ * * @author Stuart Douglas */ +@SuppressWarnings("ForLoopReplaceableByForEach") class PathMatcher implements Dumpable { private final T defaultHandler; diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/spi/EndpointInvoker.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/spi/EndpointInvoker.java index 4fa77ce958082..a7ea848bf5f04 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/spi/EndpointInvoker.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/spi/EndpointInvoker.java @@ -3,7 +3,7 @@ /** * Base interface implemented by the synthetic beans that represent rest endpoints. * - * @see CoroutineEndpointInvoker + * See org.jboss.resteasy.reactive.server.runtime.kotlin.CoroutineEndpointInvoker */ public interface EndpointInvoker { diff --git a/integration-tests/rest-client-reactive-multipart/src/main/java/io/quarkus/it/rest/client/multipart/MultipartClient.java b/integration-tests/rest-client-reactive-multipart/src/main/java/io/quarkus/it/rest/client/multipart/MultipartClient.java index d29ab1e011046..bb759beabc4f5 100644 --- a/integration-tests/rest-client-reactive-multipart/src/main/java/io/quarkus/it/rest/client/multipart/MultipartClient.java +++ b/integration-tests/rest-client-reactive-multipart/src/main/java/io/quarkus/it/rest/client/multipart/MultipartClient.java @@ -1,6 +1,7 @@ package io.quarkus.it.rest.client.multipart; import java.io.File; +import java.util.UUID; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.FormParam; @@ -179,6 +180,10 @@ class FileWithPojo { @PartType(MediaType.APPLICATION_JSON) private Pojo pojo; + @FormParam("uuid") + @PartType(MediaType.TEXT_PLAIN) + private UUID uuid; + public String getFileName() { return fileName; } @@ -194,6 +199,14 @@ public Pojo getPojo() { public void setPojo(Pojo pojo) { this.pojo = pojo; } + + public UUID getUuid() { + return uuid; + } + + public void setUuid(UUID uuid) { + this.uuid = uuid; + } } class Pojo { diff --git a/integration-tests/rest-client-reactive-multipart/src/main/java/io/quarkus/it/rest/client/multipart/MultipartResource.java b/integration-tests/rest-client-reactive-multipart/src/main/java/io/quarkus/it/rest/client/multipart/MultipartResource.java index 94447060b1cf8..d4b06b70f37eb 100644 --- a/integration-tests/rest-client-reactive-multipart/src/main/java/io/quarkus/it/rest/client/multipart/MultipartResource.java +++ b/integration-tests/rest-client-reactive-multipart/src/main/java/io/quarkus/it/rest/client/multipart/MultipartResource.java @@ -10,6 +10,7 @@ import java.nio.file.Files; import java.util.ArrayList; import java.util.List; +import java.util.UUID; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.DefaultValue; @@ -74,6 +75,7 @@ public String sendByteArrayWithPojo(@RestQuery @DefaultValue("true") Boolean wit FileWithPojo data = new FileWithPojo(); data.file = HELLO_WORLD.getBytes(UTF_8); data.setFileName(GREETING_TXT); + data.setUuid(UUID.randomUUID()); if (withPojo) { Pojo pojo = new Pojo(); pojo.setName("some-name"); @@ -398,11 +400,12 @@ public String consumeText(@MultipartForm MultipartBodyWithTextFile2 body) { @Path("/echo/with-pojo") @Consumes(MediaType.MULTIPART_FORM_DATA) public String consumeBinaryWithPojo(@MultipartForm MultipartBodyWithBinaryFileAndPojo fileWithPojo) { - return String.format("fileOk:%s,nameOk:%s,pojoOk:%s", + return String.format("fileOk:%s,nameOk:%s,pojoOk:%s,uuidNull:%s", containsHelloWorld(fileWithPojo.file), GREETING_TXT.equals(fileWithPojo.fileName), fileWithPojo.pojo == null ? "null" - : "some-name".equals(fileWithPojo.pojo.getName()) && "some-value".equals(fileWithPojo.pojo.getValue())); + : "some-name".equals(fileWithPojo.pojo.getName()) && "some-value".equals(fileWithPojo.pojo.getValue()), + fileWithPojo.uuid == null); } @GET @@ -494,6 +497,10 @@ public static class MultipartBodyWithBinaryFileAndPojo { @FormParam("pojo") @PartType(MediaType.APPLICATION_JSON) public Pojo pojo; + + @FormParam("uuid") + @PartType(MediaType.TEXT_PLAIN) + public String uuid; } } diff --git a/integration-tests/rest-client-reactive-multipart/src/test/java/io/quarkus/it/rest/client/multipart/MultipartResourceTest.java b/integration-tests/rest-client-reactive-multipart/src/test/java/io/quarkus/it/rest/client/multipart/MultipartResourceTest.java index ae15ebc9a2ccb..b13582f083276 100644 --- a/integration-tests/rest-client-reactive-multipart/src/test/java/io/quarkus/it/rest/client/multipart/MultipartResourceTest.java +++ b/integration-tests/rest-client-reactive-multipart/src/test/java/io/quarkus/it/rest/client/multipart/MultipartResourceTest.java @@ -270,13 +270,13 @@ public void shouldSendByteArrayAndPojo() { .when().get("/client/byte-array-as-binary-file-with-pojo") .then() .statusCode(200) - .body(equalTo("fileOk:true,nameOk:true,pojoOk:true")); + .body(equalTo("fileOk:true,nameOk:true,pojoOk:true,uuidNull:false")); given() .header("Content-Type", "text/plain") .when().get("/client/params/byte-array-as-binary-file-with-pojo") .then() .statusCode(200) - .body(equalTo("fileOk:true,nameOk:true,pojoOk:true")); + .body(equalTo("fileOk:true,nameOk:true,pojoOk:true,uuidNull:true")); // @formatter:on } @@ -289,14 +289,14 @@ public void shouldSendByteArrayAndPojoWithNullPojo() { .when().get("/client/byte-array-as-binary-file-with-pojo") .then() .statusCode(200) - .body(equalTo("fileOk:true,nameOk:true,pojoOk:null")); + .body(equalTo("fileOk:true,nameOk:true,pojoOk:null,uuidNull:false")); given() .queryParam("withPojo", "false") .header("Content-Type", "text/plain") .when().get("/client/params/byte-array-as-binary-file-with-pojo") .then() .statusCode(200) - .body(equalTo("fileOk:true,nameOk:true,pojoOk:null")); + .body(equalTo("fileOk:true,nameOk:true,pojoOk:null,uuidNull:true")); // @formatter:on } diff --git a/integration-tests/rest-client-reactive/src/test/java/io/quarkus/it/rest/client/ClientWithCustomObjectMapperTest.java b/integration-tests/rest-client-reactive/src/test/java/io/quarkus/it/rest/client/ClientWithCustomObjectMapperTest.java index b4a80c3a95559..f925704718c3b 100644 --- a/integration-tests/rest-client-reactive/src/test/java/io/quarkus/it/rest/client/ClientWithCustomObjectMapperTest.java +++ b/integration-tests/rest-client-reactive/src/test/java/io/quarkus/it/rest/client/ClientWithCustomObjectMapperTest.java @@ -1,5 +1,6 @@ package io.quarkus.it.rest.client; +import static com.github.tomakehurst.wiremock.client.WireMock.ok; import static com.github.tomakehurst.wiremock.client.WireMock.okJson; import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; import static org.assertj.core.api.Assertions.assertThat; @@ -8,9 +9,11 @@ import java.net.MalformedURLException; import java.net.URL; import java.util.Objects; +import java.util.concurrent.atomic.AtomicBoolean; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; import jakarta.ws.rs.Path; import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.MediaType; @@ -40,6 +43,8 @@ public class ClientWithCustomObjectMapperTest { @BeforeEach public void setUp() throws MalformedURLException { + ClientObjectMapperUnknown.USED.set(false); + ClientObjectMapperNoUnknown.USED.set(false); wireMockServer = new WireMockServer(options().port(20001)); wireMockServer.start(); @@ -60,10 +65,10 @@ public void tearDown() { } @Test - void testCustomObjectMappersShouldBeUsed() { + void testCustomObjectMappersShouldBeUsedInReader() { var json = "{ \"value\": \"someValue\", \"secondValue\": \"toBeIgnored\" }"; wireMockServer.stubFor( - WireMock.get(WireMock.urlMatching("/get")) + WireMock.get(WireMock.urlMatching("/client")) .willReturn(okJson(json))); // FAIL_ON_UNKNOWN_PROPERTIES disabled @@ -75,12 +80,25 @@ void testCustomObjectMappersShouldBeUsed() { .isInstanceOf(ClientWebApplicationException.class); } - @Path("/get") + @Test + void testCustomObjectMappersShouldBeUsedInWriter() { + wireMockServer.stubFor( + WireMock.post(WireMock.urlMatching("/client")) + .willReturn(ok())); + + clientDisallowsUnknown.post(new Request()); + assertThat(ClientObjectMapperNoUnknown.USED.get()).isTrue(); + } + + @Path("/client") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public interface MyClient { @GET Uni get(); + + @POST + void post(Request request); } public static class Request { @@ -119,8 +137,11 @@ public int hashCode() { } public static class ClientObjectMapperUnknown implements ContextResolver { + static final AtomicBoolean USED = new AtomicBoolean(false); + @Override public ObjectMapper getContext(Class type) { + USED.set(true); return new ObjectMapper() .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); @@ -128,8 +149,12 @@ public ObjectMapper getContext(Class type) { } public static class ClientObjectMapperNoUnknown implements ContextResolver { + + static final AtomicBoolean USED = new AtomicBoolean(false); + @Override public ObjectMapper getContext(Class type) { + USED.set(true); return new ObjectMapper() .enable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) .enable(SerializationFeature.FAIL_ON_EMPTY_BEANS);