transformedClassesDir;
+
+ /**
+ * If set to a directory, ZIG files for generated code will be written into that directory.
+ *
+ * A ZIG file is a textual representation of the generated code that is referenced in the stacktraces.
+ */
+ @ConfigItem
+ Optional generatedSourcesDir;
}
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/QuarkusAugmentor.java b/core/deployment/src/main/java/io/quarkus/deployment/QuarkusAugmentor.java
index ca3519a4be75a..dba8f2b5eeb88 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/QuarkusAugmentor.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/QuarkusAugmentor.java
@@ -57,6 +57,7 @@ public class QuarkusAugmentor {
private final Path targetDir;
private final ApplicationModel effectiveModel;
private final String baseName;
+ private final String originalBaseName;
private final boolean rebuild;
private final boolean auxiliaryApplication;
private final Optional auxiliaryDevModeType;
@@ -75,6 +76,7 @@ public class QuarkusAugmentor {
this.targetDir = builder.targetDir;
this.effectiveModel = builder.effectiveModel;
this.baseName = builder.baseName;
+ this.originalBaseName = builder.originalBaseName;
this.deploymentClassLoader = builder.deploymentClassLoader;
this.rebuild = builder.rebuild;
this.devModeType = builder.devModeType;
@@ -149,7 +151,7 @@ public BuildResult run() throws Exception {
.produce(new LaunchModeBuildItem(launchMode,
devModeType == null ? Optional.empty() : Optional.of(devModeType), auxiliaryApplication,
auxiliaryDevModeType, test))
- .produce(new BuildSystemTargetBuildItem(targetDir, baseName, rebuild,
+ .produce(new BuildSystemTargetBuildItem(targetDir, baseName, originalBaseName, rebuild,
buildSystemProperties == null ? new Properties() : buildSystemProperties))
.produce(new AppModelProviderBuildItem(effectiveModel));
for (PathCollection i : additionalApplicationArchives) {
@@ -194,6 +196,8 @@ public static Builder builder() {
public static final class Builder {
+ private static final String QUARKUS_APPLICATION = "quarkus-application";
+
public DevModeType auxiliaryDevModeType;
boolean rebuild;
List additionalApplicationArchives = new ArrayList<>();
@@ -208,7 +212,8 @@ public static final class Builder {
Properties buildSystemProperties;
ApplicationModel effectiveModel;
- String baseName = "quarkus-application";
+ String baseName = QUARKUS_APPLICATION;
+ String originalBaseName = QUARKUS_APPLICATION;
ClassLoader deploymentClassLoader;
DevModeType devModeType;
boolean test;
@@ -302,6 +307,11 @@ public Builder setBaseName(String baseName) {
return this;
}
+ public Builder setOriginalBaseName(String originalBaseName) {
+ this.originalBaseName = originalBaseName;
+ return this;
+ }
+
public Properties getBuildSystemProperties() {
return buildSystemProperties;
}
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/NativeImageResourceBundleBuildItem.java b/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/NativeImageResourceBundleBuildItem.java
index d486ee0f7dd19..520e81ea8c051 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/NativeImageResourceBundleBuildItem.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/NativeImageResourceBundleBuildItem.java
@@ -8,12 +8,23 @@
public final class NativeImageResourceBundleBuildItem extends MultiBuildItem {
private final String bundleName;
+ private final String moduleName;
public NativeImageResourceBundleBuildItem(String bundleName) {
this.bundleName = bundleName;
+ this.moduleName = null;
+ }
+
+ public NativeImageResourceBundleBuildItem(String bundleName, String moduleName) {
+ this.bundleName = bundleName;
+ this.moduleName = moduleName;
}
public String getBundleName() {
return bundleName;
}
+
+ public String getModuleName() {
+ return moduleName;
+ }
}
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/IsolatedDevModeMain.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/IsolatedDevModeMain.java
index 318a4c8e544e9..2f0a5402a4bc6 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/dev/IsolatedDevModeMain.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/IsolatedDevModeMain.java
@@ -22,8 +22,6 @@
import java.util.function.Consumer;
import java.util.function.Predicate;
-import org.apache.maven.shared.utils.cli.CommandLineException;
-import org.apache.maven.shared.utils.cli.CommandLineUtils;
import org.eclipse.microprofile.config.spi.ConfigProviderResolver;
import org.jboss.logging.Logger;
import org.jboss.logmanager.formatters.ColorPatternFormatter;
@@ -47,6 +45,7 @@
import io.quarkus.deployment.dev.testing.MessageFormat;
import io.quarkus.deployment.dev.testing.TestSupport;
import io.quarkus.deployment.steps.ClassTransformingBuildStep;
+import io.quarkus.deployment.util.CommandLineUtil;
import io.quarkus.dev.appstate.ApplicationStartException;
import io.quarkus.dev.console.DevConsoleManager;
import io.quarkus.dev.spi.DeploymentFailedStartHandler;
@@ -122,8 +121,8 @@ public void accept(Integer integer) {
public void accept(String args) {
try {
context.setArgs(
- CommandLineUtils.translateCommandline(args));
- } catch (CommandLineException e) {
+ CommandLineUtil.translateCommandline(args));
+ } catch (Exception e) {
log.error("Failed to parse command line", e);
return;
}
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/QuarkusDevModeLauncher.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/QuarkusDevModeLauncher.java
index eced94cb17d69..7108a534536b0 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/dev/QuarkusDevModeLauncher.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/QuarkusDevModeLauncher.java
@@ -28,11 +28,11 @@
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
-import org.apache.maven.shared.utils.cli.CommandLineUtils;
import org.jboss.logging.Logger;
import io.quarkus.bootstrap.app.QuarkusBootstrap;
import io.quarkus.deployment.dev.DevModeContext.ModuleInfo;
+import io.quarkus.deployment.util.CommandLineUtil;
import io.quarkus.maven.dependency.ArtifactKey;
import io.quarkus.runtime.logging.JBossVersion;
import io.quarkus.runtime.util.JavaVersionUtil;
@@ -476,7 +476,7 @@ protected void prepare() throws Exception {
args.add("-jar");
args.add(tempFile.getAbsolutePath());
if (applicationArgs != null) {
- args.addAll(Arrays.asList(CommandLineUtils.translateCommandline(applicationArgs)));
+ args.addAll(Arrays.asList(CommandLineUtil.translateCommandline(applicationArgs)));
}
}
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 e1c0873b86691..d9326e67bb9b9 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
@@ -53,6 +53,7 @@
import org.jboss.jandex.Indexer;
import org.jboss.logging.Logger;
+import io.quarkus.bootstrap.runner.DevModeMediator;
import io.quarkus.bootstrap.runner.Timing;
import io.quarkus.changeagent.ClassChangeAgent;
import io.quarkus.deployment.dev.DevModeContext.ModuleInfo;
@@ -602,6 +603,7 @@ public Set syncState(Map fileHashes) {
ret.add(i.getKey());
}
}
+ List removedFiles = List.of();
for (Map.Entry remaining : ourHashes.entrySet()) {
String file = remaining.getKey();
if (file.endsWith("META-INF/MANIFEST.MF") || file.contains("META-INF/maven")
@@ -609,8 +611,14 @@ public Set syncState(Map fileHashes) {
//we have some filters, for files that we don't want to delete
continue;
}
- log.info("Deleting removed file " + file);
- Files.deleteIfExists(applicationRoot.resolve(file));
+ log.info("Scheduled for removal " + file);
+ if (removedFiles.isEmpty()) {
+ removedFiles = new ArrayList<>();
+ }
+ removedFiles.add(applicationRoot.resolve(file));
+ }
+ if (!removedFiles.isEmpty()) {
+ DevModeMediator.removedFiles.addLast(removedFiles);
}
return ret;
} catch (IOException e) {
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/index/ApplicationArchiveBuildStep.java b/core/deployment/src/main/java/io/quarkus/deployment/index/ApplicationArchiveBuildStep.java
index 4dcaca5be140b..55ac76fb2f44e 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/index/ApplicationArchiveBuildStep.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/index/ApplicationArchiveBuildStep.java
@@ -102,6 +102,9 @@ ApplicationArchivesBuildItem build(
removedResources.put(new GACT(entry.getKey().split(":")), entry.getValue());
}
+ // Add resources removed from the classpath by extensions
+ removedResources.putAll(curateOutcomeBuildItem.getApplicationModel().getRemovedResources());
+
List applicationArchives = scanForOtherIndexes(buildCloseables,
appMarkers, root, additionalApplicationArchiveBuildItem, indexDependencyBuildItems, indexCache,
curateOutcomeBuildItem, removedResources);
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 2030fca7c05cb..e00452508859e 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
@@ -241,13 +241,13 @@ public Index apply(PathVisit visit) {
}
try (InputStream in = Files.newInputStream(visit.getPath())) {
IndexReader reader = new IndexReader(in);
- if (reader.getIndexVersion() < REQUIRED_INDEX_VERSION) {
- log.warnf(
- "Re-indexing %s - at least Jandex 2.1 must be used to index an application dependency",
- visit.getPath());
- return null;
- }
try {
+ if (reader.getIndexVersion() < REQUIRED_INDEX_VERSION) {
+ log.warnf(
+ "Re-indexing %s - at least Jandex 2.1 must be used to index an application dependency",
+ visit.getPath());
+ return null;
+ }
return reader.read();
} catch (UnsupportedVersion e) {
throw new UnsupportedVersion(
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/jbang/JBangAugmentorImpl.java b/core/deployment/src/main/java/io/quarkus/deployment/jbang/JBangAugmentorImpl.java
index 01eeaca5051ee..946699643f592 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/jbang/JBangAugmentorImpl.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/jbang/JBangAugmentorImpl.java
@@ -54,6 +54,9 @@ public void accept(CuratedApplication curatedApplication, Map re
if (quarkusBootstrap.getBaseName() != null) {
builder.setBaseName(quarkusBootstrap.getBaseName());
}
+ if (quarkusBootstrap.getOriginalBaseName() != null) {
+ builder.setOriginalBaseName(quarkusBootstrap.getOriginalBaseName());
+ }
boolean auxiliaryApplication = curatedApplication.getQuarkusBootstrap().isAuxiliaryApplication();
builder.setAuxiliaryApplication(auxiliaryApplication);
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/pkg/builditem/BuildSystemTargetBuildItem.java b/core/deployment/src/main/java/io/quarkus/deployment/pkg/builditem/BuildSystemTargetBuildItem.java
index 3fa8da77c6a2b..ccec015fef4c1 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/pkg/builditem/BuildSystemTargetBuildItem.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/pkg/builditem/BuildSystemTargetBuildItem.java
@@ -12,12 +12,28 @@ public final class BuildSystemTargetBuildItem extends SimpleBuildItem {
private final Path outputDirectory;
private final String baseName;
+ private final String originalBaseName;
private final boolean rebuild;
private final Properties buildSystemProps;
+ /**
+ * @deprecated in favor of {@link #BuildSystemTargetBuildItem(Path, String, String, boolean, Properties)}
+ *
+ * @param outputDirectory build output directory
+ * @param baseName base runner name
+ * @param rebuild indicates whether the application is being re-built
+ * @param buildSystemProps build system properties
+ */
+ @Deprecated(forRemoval = true)
public BuildSystemTargetBuildItem(Path outputDirectory, String baseName, boolean rebuild, Properties buildSystemProps) {
+ this(outputDirectory, baseName, baseName, rebuild, buildSystemProps);
+ }
+
+ public BuildSystemTargetBuildItem(Path outputDirectory, String baseName, String originalBaseName, boolean rebuild,
+ Properties buildSystemProps) {
this.outputDirectory = outputDirectory;
this.baseName = baseName;
+ this.originalBaseName = originalBaseName;
this.rebuild = rebuild;
this.buildSystemProps = buildSystemProps;
}
@@ -30,6 +46,10 @@ public String getBaseName() {
return baseName;
}
+ public String getOriginalBaseName() {
+ return originalBaseName;
+ }
+
public boolean isRebuild() {
return rebuild;
}
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/pkg/builditem/OutputTargetBuildItem.java b/core/deployment/src/main/java/io/quarkus/deployment/pkg/builditem/OutputTargetBuildItem.java
index 24479c85b677c..6eb601ace4e1d 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/pkg/builditem/OutputTargetBuildItem.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/pkg/builditem/OutputTargetBuildItem.java
@@ -17,14 +17,32 @@ public final class OutputTargetBuildItem extends SimpleBuildItem {
private final Path outputDirectory;
private final String baseName;
+ private final String originalBaseName;
private final boolean rebuild;
private final Properties buildSystemProperties;
private final Optional> includedOptionalDependencies;
+ /**
+ * @deprecated in favor of {@link #OutputTargetBuildItem(Path, String, String, boolean, Properties, Optional)}
+ *
+ * @param outputDirectory build output directory
+ * @param baseName base runner name
+ * @param rebuild indicates whether the application is being re-built
+ * @param buildSystemProperties build system properties
+ * @param includedOptionalDependencies included optional dependencies
+ */
+ @Deprecated(forRemoval = true)
public OutputTargetBuildItem(Path outputDirectory, String baseName, boolean rebuild, Properties buildSystemProperties,
Optional> includedOptionalDependencies) {
+ this(outputDirectory, baseName, baseName, rebuild, buildSystemProperties, includedOptionalDependencies);
+ }
+
+ public OutputTargetBuildItem(Path outputDirectory, String baseName, String originalBaseName, boolean rebuild,
+ Properties buildSystemProperties,
+ Optional> includedOptionalDependencies) {
this.outputDirectory = outputDirectory;
this.baseName = baseName;
+ this.originalBaseName = originalBaseName;
this.rebuild = rebuild;
this.buildSystemProperties = buildSystemProperties;
this.includedOptionalDependencies = includedOptionalDependencies;
@@ -34,10 +52,25 @@ public Path getOutputDirectory() {
return outputDirectory;
}
+ /**
+ * Base name for the Quarkus application runner file.
+ *
+ * @return base name for the Quarkus application runner file
+ */
public String getBaseName() {
return baseName;
}
+ /**
+ * The base name (not including the extension) of the original JAR generated by the build system.
+ * This name could be different from the value of {@ #getBaseName()}, which will be used for the Quarkus runner file.
+ *
+ * @return name of the original JAR generated by the build system
+ */
+ public String getOriginalBaseName() {
+ return originalBaseName;
+ }
+
public boolean isRebuild() {
return rebuild;
}
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/JarResultBuildStep.java b/core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/JarResultBuildStep.java
index 3e092d838d8fa..dd28e38cf88ac 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/JarResultBuildStep.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/JarResultBuildStep.java
@@ -158,12 +158,13 @@ OutputTargetBuildItem outputTarget(BuildSystemTargetBuildItem bst, PackageConfig
Optional> includedOptionalDependencies;
if (packageConfig.filterOptionalDependencies) {
includedOptionalDependencies = Optional.of(packageConfig.includedOptionalDependencies
- .map(set -> set.stream().map(s -> (ArtifactKey) GACT.fromString(s)).collect(Collectors.toSet()))
+ .map(set -> set.stream().map(s -> ArtifactKey.fromString(s)).collect(Collectors.toSet()))
.orElse(Collections.emptySet()));
} else {
includedOptionalDependencies = Optional.empty();
}
- return new OutputTargetBuildItem(path, name, bst.isRebuild(), bst.getBuildSystemProps(), includedOptionalDependencies);
+ return new OutputTargetBuildItem(path, name, bst.getOriginalBaseName(), bst.isRebuild(), bst.getBuildSystemProps(),
+ includedOptionalDependencies);
}
@BuildStep(onlyIf = JarRequired.class)
@@ -283,7 +284,7 @@ private JarBuildItem buildUberJar(CurateOutcomeBuildItem curateOutcomeBuildItem,
//for uberjars we move the original jar, so there is only a single jar in the output directory
final Path standardJar = outputTargetBuildItem.getOutputDirectory()
- .resolve(outputTargetBuildItem.getBaseName() + ".jar");
+ .resolve(outputTargetBuildItem.getOriginalBaseName() + ".jar");
final Path originalJar = Files.exists(standardJar) ? standardJar : null;
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/NativeImageBuildLocalContainerRunner.java b/core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/NativeImageBuildLocalContainerRunner.java
index 1be0521d44027..58c97c1eb237c 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/NativeImageBuildLocalContainerRunner.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/NativeImageBuildLocalContainerRunner.java
@@ -87,7 +87,7 @@ private static String fetchDockerEndpoint() {
OutputFilter outputFilter = new OutputFilter();
if (!ExecUtil.execWithTimeout(new File("."), outputFilter, Duration.ofMillis(3000),
"docker", "context", "ls", "--format",
- "'{{- if .Current -}} {{- .DockerEndpoint -}} {{- end -}}'")) {
+ "{{- if .Current -}} {{- .DockerEndpoint -}} {{- end -}}")) {
LOGGER.debug("Docker context lookup didn't succeed in time");
return null;
}
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/steps/LocaleProcessor.java b/core/deployment/src/main/java/io/quarkus/deployment/steps/LocaleProcessor.java
index f9ed878359e32..d616d35e424b6 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/steps/LocaleProcessor.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/steps/LocaleProcessor.java
@@ -36,8 +36,8 @@ public class LocaleProcessor {
@BuildStep(onlyIf = { NativeBuild.class, NonDefaultLocale.class })
void nativeResources(BuildProducer resources) {
- resources.produce(new NativeImageResourceBundleBuildItem("sun.util.resources.LocaleNames"));
- resources.produce(new NativeImageResourceBundleBuildItem("sun.util.resources.CurrencyNames"));
+ resources.produce(new NativeImageResourceBundleBuildItem("sun.util.resources.LocaleNames", "java.base"));
+ resources.produce(new NativeImageResourceBundleBuildItem("sun.util.resources.CurrencyNames", "java.base"));
//Adding sun.util.resources.TimeZoneNames is not necessary.
}
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/steps/NativeImageFeatureStep.java b/core/deployment/src/main/java/io/quarkus/deployment/steps/NativeImageFeatureStep.java
index 01786ec5bca51..7a4c59c54b82d 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/steps/NativeImageFeatureStep.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/steps/NativeImageFeatureStep.java
@@ -51,7 +51,7 @@
import io.quarkus.gizmo.MethodDescriptor;
import io.quarkus.gizmo.ResultHandle;
import io.quarkus.gizmo.TryBlock;
-import io.quarkus.runtime.ReflectionUtil;
+import io.quarkus.runtime.NativeImageFeatureUtils;
import io.quarkus.runtime.ResourceHelper;
import io.quarkus.runtime.graal.ResourcesFeature;
import io.quarkus.runtime.graal.WeakReflection;
@@ -64,15 +64,15 @@ public class NativeImageFeatureStep {
private static final MethodDescriptor IMAGE_SINGLETONS_LOOKUP = ofMethod(ImageSingletons.class, "lookup", Object.class,
Class.class);
- private static final MethodDescriptor BUILD_TIME_INITIALIZATION = ofMethod(
- "org.graalvm.nativeimage.impl.RuntimeClassInitializationSupport",
- "initializeAtBuildTime", void.class, String.class, String.class);
+ private static final MethodDescriptor BUILD_TIME_INITIALIZATION = ofMethod(RuntimeClassInitialization.class,
+ "initializeAtBuildTime", void.class, String[].class);
private static final MethodDescriptor INITIALIZE_CLASSES_AT_RUN_TIME = ofMethod(RuntimeClassInitialization.class,
"initializeAtRunTime", void.class, Class[].class);
private static final MethodDescriptor INITIALIZE_PACKAGES_AT_RUN_TIME = ofMethod(RuntimeClassInitialization.class,
"initializeAtRunTime", void.class, String[].class);
+ public static final String RUNTIME_CLASS_INITIALIZATION_SUPPORT = "org.graalvm.nativeimage.impl.RuntimeClassInitializationSupport";
private static final MethodDescriptor RERUN_INITIALIZATION = ofMethod(
- "org.graalvm.nativeimage.impl.RuntimeClassInitializationSupport",
+ RUNTIME_CLASS_INITIALIZATION_SUPPORT,
"rerunInitialization", void.class, Class.class, String.class);
public static final String CONFIGURATION_CONDITION = "org.graalvm.nativeimage.impl.ConfigurationCondition";
@@ -87,10 +87,12 @@ public class NativeImageFeatureStep {
String.class);
private static final MethodDescriptor LOOKUP_METHOD = ofMethod(
- ReflectionUtil.class,
+ NativeImageFeatureUtils.class,
"lookupMethod", Method.class, Class.class, String.class, Class[].class);
- private static final MethodDescriptor FOR_NAME = ofMethod(
- Class.class, "forName", Class.class, String.class, boolean.class, ClassLoader.class);
+
+ private static final MethodDescriptor FIND_MODULE_METHOD = ofMethod(
+ NativeImageFeatureUtils.class,
+ "findModule", Module.class, String.class);
private static final MethodDescriptor INVOKE = ofMethod(
Method.class, "invoke", Object.class, Object.class, Object[].class);
static final String RUNTIME_REFLECTION = RuntimeReflection.class.getName();
@@ -104,6 +106,7 @@ public class NativeImageFeatureStep {
public static final MethodDescriptor WEAK_REFLECTION_REGISTRATION = MethodDescriptor.ofMethod(WeakReflection.class,
"register", void.class, Feature.BeforeAnalysisAccess.class, Class.class, boolean.class, boolean.class,
boolean.class);
+ public static final String RUNTIME_SERIALIZATION = "org.graalvm.nativeimage.hosted.RuntimeSerialization";
@BuildStep
GeneratedResourceBuildItem generateNativeResourcesList(List resources,
@@ -169,20 +172,43 @@ public void write(String s, byte[] bytes) {
MethodCreator duringSetup = file.getMethodCreator("duringSetup", "V", DURING_SETUP_ACCESS);
// Register Lambda Capturing Types
if (!lambdaCapturingTypeBuildItems.isEmpty()) {
- ResultHandle runtimeSerializationSupportSingleton = duringSetup.invokeStaticMethod(IMAGE_SINGLETONS_LOOKUP,
- duringSetup.loadClassFromTCCL("org.graalvm.nativeimage.impl.RuntimeSerializationSupport"));
- ResultHandle configAlwaysTrue = duringSetup.invokeStaticMethod(CONFIGURATION_ALWAYS_TRUE);
- for (LambdaCapturingTypeBuildItem i : lambdaCapturingTypeBuildItems) {
- TryBlock tryBlock = duringSetup.tryBlock();
+ BranchResult graalVm22_3Test = duringSetup
+ .ifGreaterEqualZero(duringSetup.invokeVirtualMethod(VERSION_COMPARE_TO,
+ duringSetup.invokeStaticMethod(VERSION_CURRENT),
+ duringSetup.marshalAsArray(int.class, duringSetup.load(22), duringSetup.load(3))));
+ /* GraalVM >= 22.3 */
+ try (BytecodeCreator greaterThan22_2 = graalVm22_3Test.trueBranch()) {
+ MethodDescriptor registerLambdaCapturingClass = ofMethod(RUNTIME_SERIALIZATION, "registerLambdaCapturingClass",
+ void.class, Class.class);
+ for (LambdaCapturingTypeBuildItem i : lambdaCapturingTypeBuildItems) {
+ TryBlock tryBlock = greaterThan22_2.tryBlock();
- tryBlock.invokeInterfaceMethod(REGISTER_LAMBDA_CAPTURING_CLASS, runtimeSerializationSupportSingleton,
- configAlwaysTrue,
- tryBlock.load(i.getClassName()));
+ tryBlock.invokeStaticMethod(registerLambdaCapturingClass,
+ tryBlock.loadClassFromTCCL(i.getClassName()));
- CatchBlockCreator catchBlock = tryBlock.addCatch(Throwable.class);
- catchBlock.invokeVirtualMethod(ofMethod(Throwable.class, "printStackTrace", void.class),
- catchBlock.getCaughtException());
+ CatchBlockCreator catchBlock = tryBlock.addCatch(Throwable.class);
+ catchBlock.invokeVirtualMethod(ofMethod(Throwable.class, "printStackTrace", void.class),
+ catchBlock.getCaughtException());
+ }
+ }
+ /* GraalVM < 22.3 */
+ try (BytecodeCreator smallerThan22_3 = graalVm22_3Test.falseBranch()) {
+ ResultHandle runtimeSerializationSupportSingleton = smallerThan22_3.invokeStaticMethod(IMAGE_SINGLETONS_LOOKUP,
+ smallerThan22_3.loadClassFromTCCL("org.graalvm.nativeimage.impl.RuntimeSerializationSupport"));
+ ResultHandle configAlwaysTrue = smallerThan22_3.invokeStaticMethod(CONFIGURATION_ALWAYS_TRUE);
+
+ for (LambdaCapturingTypeBuildItem i : lambdaCapturingTypeBuildItems) {
+ TryBlock tryBlock = smallerThan22_3.tryBlock();
+
+ tryBlock.invokeInterfaceMethod(REGISTER_LAMBDA_CAPTURING_CLASS, runtimeSerializationSupportSingleton,
+ configAlwaysTrue,
+ tryBlock.load(i.getClassName()));
+
+ CatchBlockCreator catchBlock = tryBlock.addCatch(Throwable.class);
+ catchBlock.invokeVirtualMethod(ofMethod(Throwable.class, "printStackTrace", void.class),
+ catchBlock.getCaughtException());
+ }
}
}
duringSetup.returnValue(null);
@@ -207,12 +233,8 @@ public void write(String s, byte[] bytes) {
cc.invokeVirtualMethod(ofMethod(Throwable.class, "printStackTrace", void.class), cc.getCaughtException());
}
- ResultHandle imageSingleton = overallCatch.invokeStaticMethod(IMAGE_SINGLETONS_LOOKUP,
- overallCatch.loadClassFromTCCL("org.graalvm.nativeimage.impl.RuntimeClassInitializationSupport"));
- overallCatch.invokeInterfaceMethod(BUILD_TIME_INITIALIZATION,
- imageSingleton,
- overallCatch.load(""), // empty string means everything
- overallCatch.load("Quarkus build time init default"));
+ overallCatch.invokeStaticMethod(BUILD_TIME_INITIALIZATION,
+ overallCatch.marshalAsArray(String.class, overallCatch.load(""))); // empty string means initialize everything
if (!runtimeInitializedClassBuildItems.isEmpty()) {
ResultHandle thisClass = overallCatch.loadClassFromTCCL(GRAAL_FEATURE);
@@ -251,6 +273,8 @@ public void write(String s, byte[] bytes) {
ResultHandle cl = overallCatch.invokeVirtualMethod(ofMethod(Class.class, "getClassLoader", ClassLoader.class),
thisClass);
ResultHandle quarkus = overallCatch.load("Quarkus");
+ ResultHandle imageSingleton = overallCatch.invokeStaticMethod(IMAGE_SINGLETONS_LOOKUP,
+ overallCatch.loadClassFromTCCL(RUNTIME_CLASS_INITIALIZATION_SUPPORT));
for (RuntimeReinitializedClassBuildItem runtimeReinitializedClass : runtimeReinitializedClassBuildItems) {
TryBlock tc = overallCatch.tryBlock();
ResultHandle clazz = tc.invokeStaticMethod(
@@ -268,6 +292,10 @@ public void write(String s, byte[] bytes) {
exports.produce(new JPMSExportBuildItem("org.graalvm.nativeimage.builder", "com.oracle.svm.core.jdk.proxy",
GraalVM.Version.VERSION_22_1_0, GraalVM.Version.VERSION_22_3_0));
+ ResultHandle versionCompareto22_3Result = overallCatch.invokeVirtualMethod(VERSION_COMPARE_TO,
+ overallCatch.invokeStaticMethod(VERSION_CURRENT),
+ overallCatch.marshalAsArray(int.class, overallCatch.load(22), overallCatch.load(3)));
+
for (NativeImageProxyDefinitionBuildItem proxy : proxies) {
ResultHandle array = overallCatch.newArray(Class.class, overallCatch.load(proxy.getClasses().size()));
int i = 0;
@@ -278,10 +306,7 @@ public void write(String s, byte[] bytes) {
}
- BranchResult graalVm22_3Test = overallCatch
- .ifGreaterEqualZero(overallCatch.invokeVirtualMethod(VERSION_COMPARE_TO,
- overallCatch.invokeStaticMethod(VERSION_CURRENT),
- overallCatch.marshalAsArray(int.class, overallCatch.load(22), overallCatch.load(3))));
+ BranchResult graalVm22_3Test = overallCatch.ifGreaterEqualZero(versionCompareto22_3Result);
/* GraalVM >= 22.3 */
try (BytecodeCreator greaterThan22_2 = graalVm22_3Test.trueBranch()) {
MethodDescriptor registerMethod = ofMethod("org.graalvm.nativeimage.hosted.RuntimeProxyCreation",
@@ -385,26 +410,22 @@ public void write(String s, byte[] bytes) {
/* GraalVM >= 22.3 */
try (BytecodeCreator greaterThan22_2 = graalVm22_3Test.trueBranch()) {
- ResultHandle runtimeResourceSupportClass = greaterThan22_2.loadClassFromTCCL(RUNTIME_RESOURCE_SUPPORT);
- ResultHandle addResourceBundlesParams = greaterThan22_2.marshalAsArray(Class.class,
- greaterThan22_2.loadClassFromTCCL(CONFIGURATION_CONDITION),
- greaterThan22_2.loadClassFromTCCL(String.class));
- ResultHandle addResourceBundlesMethod = greaterThan22_2.invokeStaticMethod(
- LOOKUP_METHOD,
- runtimeResourceSupportClass, greaterThan22_2.load("addResourceBundles"), addResourceBundlesParams);
- ResultHandle runtimeResourceSupport = greaterThan22_2.invokeStaticMethod(
- IMAGE_SINGLETONS_LOOKUP,
- runtimeResourceSupportClass);
- ResultHandle configAlwaysTrue = greaterThan22_2.invokeStaticMethod(CONFIGURATION_ALWAYS_TRUE);
+ MethodDescriptor addResourceBundle = ofMethod("org.graalvm.nativeimage.hosted.RuntimeResourceAccess",
+ "addResourceBundle", void.class, Module.class, String.class);
for (NativeImageResourceBundleBuildItem i : resourceBundles) {
- TryBlock et = greaterThan22_2.tryBlock();
-
- et.invokeVirtualMethod(
- INVOKE,
- addResourceBundlesMethod, runtimeResourceSupport,
- et.marshalAsArray(Object.class, configAlwaysTrue, et.load(i.getBundleName())));
- CatchBlockCreator c = et.addCatch(Throwable.class);
+ TryBlock tc = greaterThan22_2.tryBlock();
+
+ String moduleName = i.getModuleName();
+ ResultHandle moduleNameHandle;
+ if (moduleName == null) {
+ moduleNameHandle = tc.loadNull();
+ } else {
+ moduleNameHandle = tc.load(moduleName);
+ }
+ ResultHandle module = tc.invokeStaticMethod(FIND_MODULE_METHOD, moduleNameHandle);
+ tc.invokeStaticMethod(addResourceBundle, module, tc.load(i.getBundleName()));
+ CatchBlockCreator c = tc.addCatch(Throwable.class);
//c.invokeVirtualMethod(ofMethod(Throwable.class, "printStackTrace", void.class), c.getCaughtException());
}
}
@@ -468,14 +489,7 @@ public void write(String s, byte[] bytes) {
TryBlock tc = mv.tryBlock();
- ResultHandle currentThread = tc
- .invokeStaticMethod(ofMethod(Thread.class, "currentThread", Thread.class));
- ResultHandle tccl = tc.invokeVirtualMethod(
- ofMethod(Thread.class, "getContextClassLoader", ClassLoader.class),
- currentThread);
- ResultHandle clazz = tc.invokeStaticMethod(
- ofMethod(Class.class, "forName", Class.class, String.class, boolean.class, ClassLoader.class),
- tc.load(entry.getKey()), tc.load(false), tccl);
+ ResultHandle clazz = tc.loadClassFromTCCL(entry.getKey());
//we call these methods first, so if they are going to throw an exception it happens before anything has been registered
ResultHandle constructors = tc
.invokeVirtualMethod(ofMethod(Class.class, "getDeclaredConstructors", Constructor[].class), clazz);
@@ -575,14 +589,7 @@ public void write(String s, byte[] bytes) {
TryBlock tc = mv.tryBlock();
- ResultHandle currentThread = tc
- .invokeStaticMethod(ofMethod(Thread.class, "currentThread", Thread.class));
- ResultHandle tccl = tc.invokeVirtualMethod(
- ofMethod(Thread.class, "getContextClassLoader", ClassLoader.class),
- currentThread);
- ResultHandle clazz = tc.invokeStaticMethod(
- ofMethod(Class.class, "forName", Class.class, String.class, boolean.class, ClassLoader.class),
- tc.load(className), tc.load(false), tccl);
+ ResultHandle clazz = tc.loadClassFromTCCL(className);
//we call these methods first, so if they are going to throw an exception it happens before anything has been registered
ResultHandle constructors = tc
.invokeVirtualMethod(ofMethod(Class.class, "getDeclaredConstructors", Constructor[].class), clazz);
@@ -666,15 +673,7 @@ private MethodDescriptor createRegisterSerializationForClassMethod(ClassCreator
TryBlock tc = addSerializationForClass.tryBlock();
- ResultHandle currentThread = tc
- .invokeStaticMethod(ofMethod(Thread.class, "currentThread", Thread.class));
- ResultHandle tccl = tc.invokeVirtualMethod(
- ofMethod(Thread.class, "getContextClassLoader", ClassLoader.class),
- currentThread);
-
- ResultHandle runtimeSerializationClass = tc.invokeStaticMethod(FOR_NAME,
- tc.load("org.graalvm.nativeimage.hosted.RuntimeSerialization"),
- tc.load(false), tccl);
+ ResultHandle runtimeSerializationClass = tc.loadClassFromTCCL(RUNTIME_SERIALIZATION);
ResultHandle registerArgTypes = tc.newArray(Class.class, tc.load(1));
tc.writeArrayValue(registerArgTypes, 0, tc.loadClassFromTCCL(Class[].class));
ResultHandle registerLookupMethod = tc.invokeStaticMethod(LOOKUP_METHOD, runtimeSerializationClass,
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/steps/ResourceBundleStep.java b/core/deployment/src/main/java/io/quarkus/deployment/steps/ResourceBundleStep.java
index f2cfba72a2ce0..5f959fad51bac 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/steps/ResourceBundleStep.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/steps/ResourceBundleStep.java
@@ -12,6 +12,6 @@ public NativeImageResourceBundleBuildItem nativeImageResourceBundle() {
* This might no longer be required if GraalVM auto-includes it in a future release.
* See https://github.com/oracle/graal/issues/2005 for more details about it.
*/
- return new NativeImageResourceBundleBuildItem("sun.security.util.Resources");
+ return new NativeImageResourceBundleBuildItem("sun.security.util.Resources", "java.base");
}
}
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/util/CommandLineUtil.java b/core/deployment/src/main/java/io/quarkus/deployment/util/CommandLineUtil.java
new file mode 100644
index 0000000000000..b9fdc7d7ffe59
--- /dev/null
+++ b/core/deployment/src/main/java/io/quarkus/deployment/util/CommandLineUtil.java
@@ -0,0 +1,107 @@
+package io.quarkus.deployment.util;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+
+/**
+ * This class contains code coming from org.apache.maven.shared.utils.cli.CommandLineUtils.
+ *
+ * We don't want to directly use code coming from Maven as this artifact should be Maven-agnostic.
+ *
+ * @author Trygve Laugstøl
+ */
+public final class CommandLineUtil {
+
+ private CommandLineUtil() {
+ }
+
+ /**
+ * @param toProcess The command line to translate.
+ * @return The array of translated parts.
+ * @throws IllegalStateException in case of unbalanced quotes.
+ */
+ public static String[] translateCommandline(String toProcess) {
+ if ((toProcess == null) || (toProcess.length() == 0)) {
+ return new String[0];
+ }
+
+ // parse with a simple finite state machine
+
+ final int normal = 0;
+ final int inQuote = 1;
+ final int inDoubleQuote = 2;
+ boolean inEscape = false;
+ int state = normal;
+ final StringTokenizer tok = new StringTokenizer(toProcess, "\"\' \\", true);
+ List tokens = new ArrayList();
+ StringBuilder current = new StringBuilder();
+
+ while (tok.hasMoreTokens()) {
+ String nextTok = tok.nextToken();
+ switch (state) {
+ case inQuote:
+ if ("\'".equals(nextTok)) {
+ if (inEscape) {
+ current.append(nextTok);
+ inEscape = false;
+ } else {
+ state = normal;
+ }
+ } else {
+ current.append(nextTok);
+ inEscape = "\\".equals(nextTok);
+ }
+ break;
+ case inDoubleQuote:
+ if ("\"".equals(nextTok)) {
+ if (inEscape) {
+ current.append(nextTok);
+ inEscape = false;
+ } else {
+ state = normal;
+ }
+ } else {
+ current.append(nextTok);
+ inEscape = "\\".equals(nextTok);
+ }
+ break;
+ default:
+ if ("\'".equals(nextTok)) {
+ if (inEscape) {
+ inEscape = false;
+ current.append(nextTok);
+ } else {
+ state = inQuote;
+ }
+ } else if ("\"".equals(nextTok)) {
+ if (inEscape) {
+ inEscape = false;
+ current.append(nextTok);
+ } else {
+ state = inDoubleQuote;
+ }
+ } else if (" ".equals(nextTok)) {
+ if (current.length() != 0) {
+ tokens.add(current.toString());
+ current.setLength(0);
+ }
+ } else {
+ current.append(nextTok);
+ inEscape = "\\".equals(nextTok);
+ }
+ break;
+ }
+ }
+
+ if (current.length() != 0) {
+ tokens.add(current.toString());
+ }
+
+ if ((state == inQuote) || (state == inDoubleQuote)) {
+ throw new IllegalStateException("unbalanced quotes in " + toProcess);
+ }
+
+ return tokens.toArray(new String[tokens.size()]);
+ }
+}
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/util/JandexUtil.java b/core/deployment/src/main/java/io/quarkus/deployment/util/JandexUtil.java
index 1666ef4e6264f..4d2d7e01e923d 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/util/JandexUtil.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/util/JandexUtil.java
@@ -11,6 +11,7 @@
import java.util.Set;
import org.jboss.jandex.AnnotationInstance;
+import org.jboss.jandex.AnnotationTarget;
import org.jboss.jandex.ArrayType;
import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.ClassType;
@@ -29,6 +30,7 @@
public final class JandexUtil {
public final static DotName DOTNAME_OBJECT = DotName.createSimple(Object.class.getName());
+ public final static DotName DOTNAME_RECORD = DotName.createSimple("java.lang.Record");
private JandexUtil() {
}
@@ -119,8 +121,8 @@ private static List findParametersRecursively(Type type, DotName target,
return null;
}
- // always end at Object
- if (DOTNAME_OBJECT.equals(name)) {
+ // always end at Object or Record
+ if (DOTNAME_OBJECT.equals(name) || DOTNAME_RECORD.equals(name)) {
return null;
}
@@ -288,25 +290,32 @@ private static ClassInfo fetchFromIndex(DotName dotName, IndexView index) {
}
/**
- * Returns the enclosing class of the given annotation instance. For field or method annotations this
- * will return the enclosing class. For parameters, this will return the enclosing class of the enclosing
- * method. For classes, it will return the class itself.
+ * Returns the enclosing class of the given annotation instance. For field, method or record component annotations,
+ * this will return the enclosing class. For parameters, this will return the enclosing class of the enclosing
+ * method. For classes, it will return the class itself. For type annotations, it will return the class enclosing
+ * the annotated type usage.
*
- * @param annotationInstance the annotation whose enclosing class to look up.
- * @return the enclosing class.
+ * @param annotationInstance the annotation whose enclosing class to look up
+ * @return the enclosing class
*/
public static ClassInfo getEnclosingClass(AnnotationInstance annotationInstance) {
- switch (annotationInstance.target().kind()) {
+ return getEnclosingClass(annotationInstance.target());
+ }
+
+ private static ClassInfo getEnclosingClass(AnnotationTarget annotationTarget) {
+ switch (annotationTarget.kind()) {
case FIELD:
- return annotationInstance.target().asField().declaringClass();
+ return annotationTarget.asField().declaringClass();
case METHOD:
- return annotationInstance.target().asMethod().declaringClass();
+ return annotationTarget.asMethod().declaringClass();
case METHOD_PARAMETER:
- return annotationInstance.target().asMethodParameter().method().declaringClass();
+ return annotationTarget.asMethodParameter().method().declaringClass();
+ case RECORD_COMPONENT:
+ return annotationTarget.asRecordComponent().declaringClass();
case CLASS:
- return annotationInstance.target().asClass();
+ return annotationTarget.asClass();
case TYPE:
- return annotationInstance.target().asType().asClass(); // TODO is it legal here or should I throw ?
+ return getEnclosingClass(annotationTarget.asType().enclosingTarget());
default:
throw new RuntimeException(); // this should not occur
}
@@ -323,7 +332,7 @@ public static ClassInfo getEnclosingClass(AnnotationInstance annotationInstance)
* @throws BuildException if one of the superclasses is not indexed.
*/
public static boolean isSubclassOf(IndexView index, ClassInfo info, DotName parentName) throws BuildException {
- if (info.superName().equals(DOTNAME_OBJECT)) {
+ if (info.superName().equals(DOTNAME_OBJECT) || info.superName().equals(DOTNAME_RECORD)) {
return false;
}
if (info.superName().equals(parentName)) {
diff --git a/core/deployment/src/main/java/io/quarkus/runner/bootstrap/AugmentActionImpl.java b/core/deployment/src/main/java/io/quarkus/runner/bootstrap/AugmentActionImpl.java
index 6d9cca4a075da..a2007cf6732db 100644
--- a/core/deployment/src/main/java/io/quarkus/runner/bootstrap/AugmentActionImpl.java
+++ b/core/deployment/src/main/java/io/quarkus/runner/bootstrap/AugmentActionImpl.java
@@ -291,6 +291,9 @@ private BuildResult runAugment(boolean firstRun, Set changedResources,
if (quarkusBootstrap.getBaseName() != null) {
builder.setBaseName(quarkusBootstrap.getBaseName());
}
+ if (quarkusBootstrap.getOriginalBaseName() != null) {
+ builder.setOriginalBaseName(quarkusBootstrap.getOriginalBaseName());
+ }
boolean auxiliaryApplication = curatedApplication.getQuarkusBootstrap().isAuxiliaryApplication();
builder.setAuxiliaryApplication(auxiliaryApplication);
diff --git a/core/runtime/src/main/java/io/quarkus/runtime/ReflectionUtil.java b/core/runtime/src/main/java/io/quarkus/runtime/NativeImageFeatureUtils.java
similarity index 55%
rename from core/runtime/src/main/java/io/quarkus/runtime/ReflectionUtil.java
rename to core/runtime/src/main/java/io/quarkus/runtime/NativeImageFeatureUtils.java
index face04fad7ed8..cdecbd71dcedf 100644
--- a/core/runtime/src/main/java/io/quarkus/runtime/ReflectionUtil.java
+++ b/core/runtime/src/main/java/io/quarkus/runtime/NativeImageFeatureUtils.java
@@ -2,7 +2,7 @@
import java.lang.reflect.Method;
-public class ReflectionUtil {
+public class NativeImageFeatureUtils {
public static Method lookupMethod(Class> declaringClass, String methodName, Class>... parameterTypes)
throws NoSuchMethodException {
@@ -10,4 +10,11 @@ public static Method lookupMethod(Class> declaringClass, String methodName, Cl
result.setAccessible(true);
return result;
}
+
+ public static Module findModule(String moduleName) {
+ if (moduleName == null) {
+ return ClassLoader.getSystemClassLoader().getUnnamedModule();
+ }
+ return ModuleLayer.boot().findModule(moduleName).orElseThrow();
+ }
}
diff --git a/core/runtime/src/main/java/io/quarkus/runtime/annotations/ConfigDocMapKey.java b/core/runtime/src/main/java/io/quarkus/runtime/annotations/ConfigDocMapKey.java
index a6d1096c26c85..74e6b54fd62a6 100644
--- a/core/runtime/src/main/java/io/quarkus/runtime/annotations/ConfigDocMapKey.java
+++ b/core/runtime/src/main/java/io/quarkus/runtime/annotations/ConfigDocMapKey.java
@@ -1,6 +1,7 @@
package io.quarkus.runtime.annotations;
import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.SOURCE;
@@ -13,7 +14,7 @@
*/
@Documented
@Retention(SOURCE)
-@Target({ FIELD, PARAMETER })
+@Target({ FIELD, PARAMETER, METHOD })
public @interface ConfigDocMapKey {
String value();
}
diff --git a/core/runtime/src/main/java/io/quarkus/runtime/annotations/ConfigDocSection.java b/core/runtime/src/main/java/io/quarkus/runtime/annotations/ConfigDocSection.java
index 86915c752b300..372cc7782d621 100644
--- a/core/runtime/src/main/java/io/quarkus/runtime/annotations/ConfigDocSection.java
+++ b/core/runtime/src/main/java/io/quarkus/runtime/annotations/ConfigDocSection.java
@@ -1,6 +1,7 @@
package io.quarkus.runtime.annotations;
import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.SOURCE;
@@ -14,6 +15,6 @@
*/
@Documented
@Retention(SOURCE)
-@Target({ FIELD, PARAMETER })
+@Target({ FIELD, PARAMETER, METHOD })
public @interface ConfigDocSection {
}
diff --git a/core/runtime/src/main/java/io/quarkus/runtime/configuration/ConfigUtils.java b/core/runtime/src/main/java/io/quarkus/runtime/configuration/ConfigUtils.java
index a0e3d24df1d41..d971720ba9488 100644
--- a/core/runtime/src/main/java/io/quarkus/runtime/configuration/ConfigUtils.java
+++ b/core/runtime/src/main/java/io/quarkus/runtime/configuration/ConfigUtils.java
@@ -5,6 +5,8 @@
import static io.smallrye.config.SmallRyeConfig.SMALLRYE_CONFIG_PROFILE;
import static io.smallrye.config.SmallRyeConfig.SMALLRYE_CONFIG_PROFILE_PARENT;
import static io.smallrye.config.SmallRyeConfigBuilder.META_INF_MICROPROFILE_CONFIG_PROPERTIES;
+import static java.lang.Integer.MAX_VALUE;
+import static java.lang.Integer.MIN_VALUE;
import java.io.IOException;
import java.net.URL;
@@ -13,7 +15,6 @@
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
@@ -39,13 +40,13 @@
import io.smallrye.config.EnvConfigSource;
import io.smallrye.config.FallbackConfigSourceInterceptor;
import io.smallrye.config.KeyMap;
-import io.smallrye.config.KeyMapBackedConfigSource;
import io.smallrye.config.Priorities;
import io.smallrye.config.ProfileConfigSourceInterceptor;
import io.smallrye.config.RelocateConfigSourceInterceptor;
import io.smallrye.config.SmallRyeConfig;
import io.smallrye.config.SmallRyeConfigBuilder;
import io.smallrye.config.SysPropConfigSource;
+import io.smallrye.config.common.MapBackedConfigSource;
import io.smallrye.config.common.utils.ConfigSourceUtil;
/**
@@ -115,10 +116,8 @@ public static SmallRyeConfigBuilder configBuilder(final boolean runTime, final b
builder.addDiscoveredValidator();
builder.withDefaultValue(UUID_KEY, UUID.randomUUID().toString());
builder.withSources(new DotEnvConfigSourceProvider());
- builder.withSources(
- new DefaultsConfigSource(loadBuildTimeRunTimeValues(), "BuildTime RunTime Fixed", Integer.MAX_VALUE));
- builder.withSources(
- new DefaultsConfigSource(loadRunTimeDefaultValues(), "RunTime Defaults", Integer.MIN_VALUE + 100));
+ builder.withSources(new DefaultsConfigSource(loadBuildTimeRunTimeValues(), "BuildTime RunTime Fixed", MAX_VALUE));
+ builder.withSources(new DefaultsConfigSource(loadRunTimeDefaultValues(), "RunTime Defaults", MIN_VALUE + 100));
} else {
List sources = new ArrayList<>();
sources.addAll(classPathSources(META_INF_MICROPROFILE_CONFIG_PROPERTIES, classLoader));
@@ -381,43 +380,35 @@ public Set getPropertyNames() {
}
}
- static class DefaultsConfigSource extends KeyMapBackedConfigSource {
+ static class DefaultsConfigSource extends MapBackedConfigSource {
private final KeyMap wildcards;
- private final Set propertyNames;
public DefaultsConfigSource(final Map properties, final String name, final int ordinal) {
- super(name, ordinal, propertiesToKeyMap(properties));
+ // Defaults may contain wildcards, but we don't want to expose them in getPropertyNames, so we need to filter them
+ super(name, filterWildcards(properties), ordinal);
this.wildcards = new KeyMap<>();
- this.propertyNames = new HashSet<>();
for (Map.Entry entry : properties.entrySet()) {
if (entry.getKey().contains("*")) {
this.wildcards.findOrAdd(entry.getKey()).putRootValue(entry.getValue());
- } else {
- this.propertyNames.add(entry.getKey());
}
}
}
- @Override
- public Set getPropertyNames() {
- return propertyNames;
- }
-
@Override
public String getValue(final String propertyName) {
String value = super.getValue(propertyName);
return value == null ? wildcards.findRootValue(propertyName) : value;
}
- private static KeyMap propertiesToKeyMap(final Map properties) {
- KeyMap keyMap = new KeyMap<>();
+ private static Map filterWildcards(final Map properties) {
+ Map filtered = new HashMap<>();
for (Map.Entry entry : properties.entrySet()) {
if (entry.getKey().contains("*")) {
continue;
}
- keyMap.findOrAdd(entry.getKey()).putRootValue(entry.getValue());
+ filtered.put(entry.getKey(), entry.getValue());
}
- return keyMap;
+ return filtered;
}
}
diff --git a/devtools/cli/src/main/java/io/quarkus/cli/build/MavenRunner.java b/devtools/cli/src/main/java/io/quarkus/cli/build/MavenRunner.java
index d8bcb2b29ab90..2c801a999901a 100644
--- a/devtools/cli/src/main/java/io/quarkus/cli/build/MavenRunner.java
+++ b/devtools/cli/src/main/java/io/quarkus/cli/build/MavenRunner.java
@@ -1,6 +1,7 @@
package io.quarkus.cli.build;
import java.io.File;
+import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayDeque;
import java.util.ArrayList;
@@ -32,6 +33,7 @@
import picocli.CommandLine;
public class MavenRunner implements BuildSystemRunner {
+ public static String MAVEN_SETTINGS = "maven.settings";
static final String[] windowsWrapper = { "mvnw.cmd", "mvnw.bat" };
static final String otherWrapper = "mvnw";
@@ -238,13 +240,13 @@ void setMavenProperties(ArrayDeque args, boolean batchMode) {
args.addFirst("-Dstyle.color=always");
}
- String mavenSettings = propertiesOptions.properties.remove("maven.settings");
+ String mavenSettings = propertiesOptions.properties.remove(MAVEN_SETTINGS);
if (mavenSettings != null && !mavenSettings.isEmpty()) {
args.add("-s");
args.add(mavenSettings);
} else {
- mavenSettings = System.getProperty("maven.settings");
- if (mavenSettings != null && !mavenSettings.isEmpty()) {
+ mavenSettings = System.getProperty(MAVEN_SETTINGS);
+ if (mavenSettings != null && !mavenSettings.isEmpty() && Files.exists(Path.of(mavenSettings))) {
args.add("-s");
args.add(mavenSettings);
}
diff --git a/devtools/cli/src/test/java/io/quarkus/cli/CliDriver.java b/devtools/cli/src/test/java/io/quarkus/cli/CliDriver.java
index ddf060402c37e..2ee05931bef2b 100644
--- a/devtools/cli/src/test/java/io/quarkus/cli/CliDriver.java
+++ b/devtools/cli/src/test/java/io/quarkus/cli/CliDriver.java
@@ -1,5 +1,8 @@
package io.quarkus.cli;
+import static io.quarkus.cli.build.MavenRunner.MAVEN_SETTINGS;
+import static org.apache.maven.cli.MavenCli.LOCAL_REPO_PROPERTY;
+
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.PrintStream;
@@ -12,6 +15,9 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
+import java.util.function.BinaryOperator;
+import java.util.function.UnaryOperator;
import org.junit.jupiter.api.Assertions;
@@ -20,6 +26,9 @@
public class CliDriver {
static final PrintStream stdout = System.out;
static final PrintStream stderr = System.err;
+ private static final BinaryOperator ARG_FORMATTER = (key, value) -> "-D" + key + "=" + value;
+ private static final UnaryOperator REPO_ARG_FORMATTER = value -> ARG_FORMATTER.apply(LOCAL_REPO_PROPERTY, value);
+ private static final UnaryOperator SETTINGS_ARG_FORMATTER = value -> ARG_FORMATTER.apply(MAVEN_SETTINGS, value);
public static class CliDriverBuilder {
@@ -63,8 +72,10 @@ public Result execute() throws Exception {
newArgs.subList(index, newArgs.size()).clear();
}
- propagateProperty("maven.repo.local", mavenLocalRepo, newArgs);
- propagateProperty("maven.settings", mavenSettings, newArgs);
+ Optional.ofNullable(mavenLocalRepo).or(CliDriver::getMavenLocalRepoProperty).map(REPO_ARG_FORMATTER)
+ .ifPresent(newArgs::add);
+ Optional.ofNullable(mavenSettings).or(CliDriver::getMavenSettingsProperty).map(SETTINGS_ARG_FORMATTER)
+ .ifPresent(newArgs::add);
newArgs.add("--cli-test");
newArgs.add("--cli-test-dir");
@@ -81,7 +92,7 @@ public Result execute() throws Exception {
PrintStream errPs = new PrintStream(err);
System.setErr(errPs);
- final Map originalProps = collectOverridenProps(newArgs);
+ final Map originalProps = collectOverriddenProps(newArgs);
Result result = new Result();
QuarkusCli cli = new QuarkusCli();
@@ -109,7 +120,7 @@ protected void resetProperties(Map originalProps) {
}
}
- protected Map collectOverridenProps(List newArgs) {
+ protected Map collectOverriddenProps(List newArgs) {
final Map originalProps = new HashMap<>();
for (String s : newArgs) {
if (s.startsWith("-D")) {
@@ -121,22 +132,14 @@ protected Map collectOverridenProps(List newArgs) {
originalProps.put(propName, origValue);
} else if (System.getProperties().contains(propName)) {
originalProps.put(propName, "true");
+ } else {
+ originalProps.put(propName, null);
}
}
}
}
return originalProps;
}
-
- private static void propagateProperty(String propName, String testValue, List args) {
- if (testValue == null) {
- testValue = System.getProperty(propName);
- if (testValue == null) {
- return;
- }
- }
- args.add("-D" + propName + "=" + testValue);
- }
}
public static CliDriverBuilder builder() {
@@ -144,14 +147,8 @@ public static CliDriverBuilder builder() {
}
public static void preserveLocalRepoSettings(Collection args) {
- String s = convertToProperty("maven.repo.local");
- if (s != null) {
- args.add(s);
- }
- s = convertToProperty("maven.settings");
- if (s != null) {
- args.add(s);
- }
+ getMavenLocalRepoProperty().map(REPO_ARG_FORMATTER).ifPresent(args::add);
+ getMavenSettingsProperty().map(SETTINGS_ARG_FORMATTER).ifPresent(args::add);
}
public static Result executeArbitraryCommand(Path startingDir, String... args) throws Exception {
@@ -439,12 +436,12 @@ public static void validateApplicationProperties(Path projectRoot, List
"Properties file should contain " + conf + ". Found:\n" + propertiesFile));
}
- private static String convertToProperty(String name) {
- String value = System.getProperty(name);
- if (value != null) {
- return "-D" + name + "=" + value;
- }
- return null;
+ private static Optional getMavenLocalRepoProperty() {
+ return Optional.ofNullable(System.getProperty(LOCAL_REPO_PROPERTY));
+ }
+
+ private static Optional getMavenSettingsProperty() {
+ return Optional.ofNullable(System.getProperty(MAVEN_SETTINGS)).filter(value -> Files.exists(Path.of(value)));
}
private static void retryDelete(File file) {
diff --git a/devtools/cli/src/test/java/io/quarkus/cli/RegistryClientBuilderTestBase.java b/devtools/cli/src/test/java/io/quarkus/cli/RegistryClientBuilderTestBase.java
index 00a402bcda5ca..d101dbe001899 100644
--- a/devtools/cli/src/test/java/io/quarkus/cli/RegistryClientBuilderTestBase.java
+++ b/devtools/cli/src/test/java/io/quarkus/cli/RegistryClientBuilderTestBase.java
@@ -1,7 +1,7 @@
package io.quarkus.cli;
-import java.io.BufferedReader;
import java.io.BufferedWriter;
+import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.nio.file.Files;
@@ -59,7 +59,7 @@ static void setup() throws Exception {
final BootstrapMavenContext mavenContext = new BootstrapMavenContext(
BootstrapMavenContext.config().setWorkspaceDiscovery(false));
- final Settings settings = getBaseMavenSettings(mavenContext.getUserSettings().toPath());
+ final Settings settings = getBaseMavenSettings(mavenContext.getUserSettings());
Profile profile = new Profile();
settings.addActiveProfile("qs-test-registry");
@@ -106,11 +106,9 @@ protected static String getCurrentQuarkusVersion() {
return v;
}
- private static Settings getBaseMavenSettings(Path mavenSettings) throws IOException {
- if (Files.exists(mavenSettings)) {
- try (BufferedReader reader = Files.newBufferedReader(mavenSettings)) {
- return new DefaultSettingsReader().read(reader, Map.of());
- }
+ private static Settings getBaseMavenSettings(File mavenSettings) throws IOException {
+ if (mavenSettings != null && mavenSettings.exists()) {
+ return new DefaultSettingsReader().read(mavenSettings, Map.of());
}
return new Settings();
}
diff --git a/devtools/gradle/build.gradle b/devtools/gradle/build.gradle
index d800441c15f2d..5368eedb8580b 100644
--- a/devtools/gradle/build.gradle
+++ b/devtools/gradle/build.gradle
@@ -31,7 +31,7 @@ subprojects {
implementation "io.quarkus:quarkus-bootstrap-core:${version}"
testImplementation gradleTestKit()
- testImplementation 'org.junit.jupiter:junit-jupiter:5.9.0'
+ testImplementation 'org.junit.jupiter:junit-jupiter:5.9.1'
testImplementation 'org.assertj:assertj-core:3.23.1'
}
diff --git a/devtools/gradle/gradle-application-plugin/build.gradle b/devtools/gradle/gradle-application-plugin/build.gradle
index 2f24773c33488..c7bba6e4c532f 100644
--- a/devtools/gradle/gradle-application-plugin/build.gradle
+++ b/devtools/gradle/gradle-application-plugin/build.gradle
@@ -33,3 +33,7 @@ pluginBundle {
vcsUrl = 'https://github.com/quarkusio/quarkus'
tags = ['quarkus', 'quarkusio', 'graalvm']
}
+
+test {
+ systemProperty 'kotlin_version', project.kotlin_version
+}
\ No newline at end of file
diff --git a/devtools/gradle/gradle-application-plugin/pom.xml b/devtools/gradle/gradle-application-plugin/pom.xml
index cefcb1fc66b3c..fa6bf4c85e9a5 100644
--- a/devtools/gradle/gradle-application-plugin/pom.xml
+++ b/devtools/gradle/gradle-application-plugin/pom.xml
@@ -54,6 +54,18 @@
quarkus-devmode-test-utils
test
+
+ org.jetbrains.kotlin
+ kotlin-gradle-plugin
+ ${kotlin.version}
+ test
+
+
+ org.checkerframework
+ checker-qual
+
+
+
diff --git a/devtools/gradle/gradle-application-plugin/src/test/java/io/quarkus/gradle/QuarkusPluginTest.java b/devtools/gradle/gradle-application-plugin/src/test/java/io/quarkus/gradle/QuarkusPluginTest.java
index 0f29e3f3c2e51..000e71d0745b1 100644
--- a/devtools/gradle/gradle-application-plugin/src/test/java/io/quarkus/gradle/QuarkusPluginTest.java
+++ b/devtools/gradle/gradle-application-plugin/src/test/java/io/quarkus/gradle/QuarkusPluginTest.java
@@ -1,10 +1,15 @@
package io.quarkus.gradle;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.gradle.testkit.runner.TaskOutcome.SUCCESS;
+import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@@ -16,12 +21,18 @@
import org.gradle.api.provider.Provider;
import org.gradle.api.tasks.TaskContainer;
import org.gradle.testfixtures.ProjectBuilder;
+import org.gradle.testkit.runner.BuildResult;
+import org.gradle.testkit.runner.GradleRunner;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
import io.quarkus.gradle.extension.QuarkusPluginExtension;
public class QuarkusPluginTest {
+ @TempDir
+ Path testProjectDir;
+
@Test
public void shouldCreateTasks() {
Project project = ProjectBuilder.builder().build();
@@ -67,7 +78,7 @@ public void shouldMakeQuarkusDevAndQuarkusBuildDependOnClassesTask() {
}
@Test
- public void shouldReturnMutlipleOutputSourceDirectories() {
+ public void shouldReturnMultipleOutputSourceDirectories() {
Project project = ProjectBuilder.builder().build();
project.getPluginManager().apply(QuarkusPlugin.ID);
project.getPluginManager().apply("java");
@@ -84,7 +95,68 @@ public void shouldReturnMutlipleOutputSourceDirectories() {
}
- private static final List getDependantProvidedTaskName(Task task) {
+ @Test
+ public void shouldNotFailOnProjectDependenciesWithoutMain() throws IOException {
+ var kotlinVersion = System.getProperty("kotlin_version", "1.7.10");
+ var settingFile = testProjectDir.resolve("settings.gradle.kts");
+ var mppProjectDir = testProjectDir.resolve("mpp");
+ var quarkusProjectDir = testProjectDir.resolve("quarkus");
+ var mppBuild = mppProjectDir.resolve("build.gradle.kts");
+ var quarkusBuild = quarkusProjectDir.resolve("build.gradle.kts");
+ Files.createDirectory(mppProjectDir);
+ Files.createDirectory(quarkusProjectDir);
+ Files.writeString(settingFile,
+ "rootProject.name = \"quarkus-mpp-sample\"\n" +
+ "\n" +
+ "include(\n" +
+ " \"mpp\",\n" +
+ " \"quarkus\"\n" +
+ ")");
+
+ Files.writeString(mppBuild,
+ "buildscript {\n" +
+ " repositories {\n" +
+ " mavenLocal()\n" +
+ " mavenCentral()\n" +
+ " }\n" +
+ " dependencies {\n" +
+ " classpath(\"org.jetbrains.kotlin:kotlin-gradle-plugin:" + kotlinVersion + "\")\n" +
+ " }\n" +
+ "}\n" +
+ "\n" +
+ "apply(plugin = \"org.jetbrains.kotlin.multiplatform\")\n" +
+ "\n" +
+ "repositories {\n" +
+ " mavenCentral()\n" +
+ "}\n" +
+ "\n" +
+ "configure{\n" +
+ " jvm()\n" +
+ "}");
+
+ Files.writeString(quarkusBuild,
+ "plugins {\n" +
+ " id(\"io.quarkus\")\n" +
+ "}\n" +
+ "\n" +
+ "repositories {\n" +
+ " mavenCentral()\n" +
+ "}\n" +
+ "\n" +
+ "dependencies {\n" +
+ " implementation(project(\":mpp\"))\n" +
+ "}");
+
+ BuildResult result = GradleRunner.create()
+ .withPluginClasspath()
+ .withProjectDir(testProjectDir.toFile())
+ .withArguments("quarkusGenerateCode")
+ .build();
+
+ assertEquals(SUCCESS, result.task(":quarkus:quarkusGenerateCode").getOutcome());
+ }
+
+ private static List getDependantProvidedTaskName(Task task) {
List dependantTaskNames = new ArrayList<>();
for (Object t : task.getDependsOn()) {
try {
diff --git a/devtools/gradle/gradle-extension-plugin/src/main/java/io/quarkus/extension/gradle/dependency/DeploymentClasspathBuilder.java b/devtools/gradle/gradle-extension-plugin/src/main/java/io/quarkus/extension/gradle/dependency/DeploymentClasspathBuilder.java
index 5508c2e8e1a7f..1c01060da4c65 100644
--- a/devtools/gradle/gradle-extension-plugin/src/main/java/io/quarkus/extension/gradle/dependency/DeploymentClasspathBuilder.java
+++ b/devtools/gradle/gradle-extension-plugin/src/main/java/io/quarkus/extension/gradle/dependency/DeploymentClasspathBuilder.java
@@ -43,9 +43,7 @@ public void exportDeploymentClasspath(String configurationName) {
dependencies);
} else {
DependencyUtils.requireDeploymentDependency(deploymentConfigurationName, extension, dependencies);
- if (!alreadyProcessed.add(extension.getExtensionId())) {
- continue;
- }
+ alreadyProcessed.add(extension.getExtensionId());
}
}
});
@@ -73,9 +71,9 @@ private Set collectQuarkusExtensions(ResolvedDependency dep
}
Set extensions = new LinkedHashSet<>();
for (ResolvedArtifact moduleArtifact : dependency.getModuleArtifacts()) {
- ExtensionDependency extension = DependencyUtils.getExtensionInfoOrNull(project, moduleArtifact);
- if (extension != null) {
- extensions.add(extension);
+ var optionalExtension = DependencyUtils.getOptionalExtensionInfo(project, moduleArtifact);
+ if (optionalExtension.isPresent()) {
+ extensions.add(optionalExtension.get());
return extensions;
}
}
diff --git a/devtools/gradle/gradle-extension-plugin/src/main/java/io/quarkus/extension/gradle/tasks/ValidateExtensionTask.java b/devtools/gradle/gradle-extension-plugin/src/main/java/io/quarkus/extension/gradle/tasks/ValidateExtensionTask.java
index be96802daf78d..f2a1bb28cac0a 100644
--- a/devtools/gradle/gradle-extension-plugin/src/main/java/io/quarkus/extension/gradle/tasks/ValidateExtensionTask.java
+++ b/devtools/gradle/gradle-extension-plugin/src/main/java/io/quarkus/extension/gradle/tasks/ValidateExtensionTask.java
@@ -2,7 +2,9 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.Optional;
import java.util.Set;
+import java.util.stream.Collectors;
import javax.inject.Inject;
@@ -18,7 +20,6 @@
import io.quarkus.bootstrap.model.AppArtifactKey;
import io.quarkus.extension.gradle.QuarkusExtensionConfiguration;
import io.quarkus.gradle.tooling.dependency.DependencyUtils;
-import io.quarkus.gradle.tooling.dependency.ExtensionDependency;
public class ValidateExtensionTask extends DefaultTask {
@@ -62,13 +63,7 @@ public void validateExtension() {
deploymentModuleKeys);
deploymentModuleKeys.removeAll(existingDeploymentModuleKeys);
- boolean hasErrors = false;
- if (!invalidRuntimeArtifacts.isEmpty()) {
- hasErrors = true;
- }
- if (!deploymentModuleKeys.isEmpty()) {
- hasErrors = true;
- }
+ boolean hasErrors = !invalidRuntimeArtifacts.isEmpty() || !deploymentModuleKeys.isEmpty();
if (hasErrors) {
printValidationErrors(invalidRuntimeArtifacts, deploymentModuleKeys);
@@ -76,15 +71,13 @@ public void validateExtension() {
}
private List collectRuntimeExtensionsDeploymentKeys(Set runtimeArtifacts) {
- List runtimeExtensions = new ArrayList<>();
- for (ResolvedArtifact resolvedArtifact : runtimeArtifacts) {
- ExtensionDependency extension = DependencyUtils.getExtensionInfoOrNull(getProject(), resolvedArtifact);
- if (extension != null) {
- runtimeExtensions.add(new AppArtifactKey(extension.getDeploymentModule().getGroupId(),
- extension.getDeploymentModule().getArtifactId()));
- }
- }
- return runtimeExtensions;
+ return runtimeArtifacts.stream()
+ .map(resolvedArtifact -> DependencyUtils.getOptionalExtensionInfo(getProject(), resolvedArtifact))
+ .filter(Optional::isPresent)
+ .map(Optional::get)
+ .map(extension -> new AppArtifactKey(extension.getDeploymentModule().getGroupId(),
+ extension.getDeploymentModule().getArtifactId()))
+ .collect(Collectors.toList());
}
private List findExtensionInConfiguration(Set deploymentArtifacts,
diff --git a/devtools/gradle/gradle-model/build.gradle b/devtools/gradle/gradle-model/build.gradle
index 15e648b26cae7..29e30073f46cf 100644
--- a/devtools/gradle/gradle-model/build.gradle
+++ b/devtools/gradle/gradle-model/build.gradle
@@ -3,6 +3,7 @@ dependencies {
implementation "io.quarkus:quarkus-bootstrap-gradle-resolver:${version}"
implementation "org.jetbrains.kotlin:kotlin-gradle-plugin-api:${kotlin_version}"
testImplementation "io.quarkus:quarkus-devtools-testing:${version}"
+ testImplementation "org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlin_version}"
}
task sourcesJar(type: Jar, dependsOn: classes) {
diff --git a/devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/dependency/ConditionalDependenciesEnabler.java b/devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/dependency/ConditionalDependenciesEnabler.java
index 6ab5650d7b5a9..7cd6180ccbfd6 100644
--- a/devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/dependency/ConditionalDependenciesEnabler.java
+++ b/devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/dependency/ConditionalDependenciesEnabler.java
@@ -6,7 +6,10 @@
import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
import org.gradle.api.Project;
import org.gradle.api.artifacts.Configuration;
@@ -37,8 +40,7 @@ public class ConditionalDependenciesEnabler {
private final Set existingArtifacts = new HashSet<>();
private final List unsatisfiedConditionalDeps = new ArrayList<>();
- public ConditionalDependenciesEnabler(Project project, LaunchMode mode,
- Configuration platforms) {
+ public ConditionalDependenciesEnabler(Project project, LaunchMode mode, Configuration platforms) {
this.project = project;
this.enforcedPlatforms = platforms;
@@ -59,7 +61,7 @@ public ConditionalDependenciesEnabler(Project project, LaunchMode mode,
final Dependency conditionalDep = unsatisfiedConditionalDeps.get(i);
// Try to resolve it with the latest evolved graph available
if (resolveConditionalDependency(conditionalDep)) {
- // Mark the resolution as a success so we know the graph evolved
+ // Mark the resolution as a success, so we know the graph has evolved
satisfiedConditionalDeps = true;
unsatisfiedConditionalDeps.remove(i);
} else {
@@ -88,23 +90,25 @@ private void reset() {
}
private void collectConditionalDependencies(Set runtimeArtifacts) {
- // For every artifact in the dependency graph:
- for (ResolvedArtifact artifact : runtimeArtifacts) {
- // Add to master list of artifacts:
- existingArtifacts.add(getKey(artifact));
- ExtensionDependency extension = DependencyUtils.getExtensionInfoOrNull(project, artifact);
- // If this artifact represents an extension:
- if (extension != null) {
- // Add to master list of accepted extensions:
- allExtensions.put(extension.getExtensionId(), extension);
- for (Dependency conditionalDep : extension.getConditionalDependencies()) {
- // If the dependency is not present yet in the graph, queue it for resolution later
- if (!exists(conditionalDep)) {
- queueConditionalDependency(extension, conditionalDep);
- }
- }
- }
- }
+ addToMasterList(runtimeArtifacts);
+ var artifactExtensions = getArtifactExtensions(runtimeArtifacts);
+ allExtensions.putAll(artifactExtensions);
+ artifactExtensions.forEach((ignored, extension) -> queueAbsentExtensionConditionalDependencies(extension));
+ }
+
+ private void addToMasterList(Set artifacts) {
+ artifacts.stream().map(ConditionalDependenciesEnabler::getKey).forEach(existingArtifacts::add);
+ }
+
+ private Map getArtifactExtensions(Set runtimeArtifacts) {
+ return runtimeArtifacts.stream()
+ .flatMap(artifact -> DependencyUtils.getOptionalExtensionInfo(project, artifact).stream())
+ .collect(Collectors.toMap(ExtensionDependency::getExtensionId, Function.identity()));
+ }
+
+ private void queueAbsentExtensionConditionalDependencies(ExtensionDependency extension) {
+ extension.getConditionalDependencies().stream().filter(dep -> !exists(dep))
+ .forEach(dep -> queueConditionalDependency(extension, dep));
}
private boolean resolveConditionalDependency(Dependency conditionalDep) {
@@ -112,51 +116,31 @@ private boolean resolveConditionalDependency(Dependency conditionalDep) {
final Configuration conditionalDeps = createConditionalDependenciesConfiguration(project, conditionalDep);
Set resolvedArtifacts = conditionalDeps.getResolvedConfiguration().getResolvedArtifacts();
- boolean satisfied = false;
- // Resolved artifacts don't have great linking back to the original artifact, so I think
- // this loop is trying to find the artifact that represents the original conditional
- // dependency
- for (ResolvedArtifact artifact : resolvedArtifacts) {
- if (conditionalDep.getName().equals(artifact.getName())
- && conditionalDep.getVersion().equals(artifact.getModuleVersion().getId().getVersion())
- && artifact.getModuleVersion().getId().getGroup().equals(conditionalDep.getGroup())) {
- // Once the dependency is found, reload the extension info from within
- final ExtensionDependency extensionDependency = DependencyUtils.getExtensionInfoOrNull(project, artifact);
- // Now check if this conditional dependency is resolved given the latest graph evolution
- if (extensionDependency != null && (extensionDependency.getDependencyConditions().isEmpty()
- || exist(extensionDependency.getDependencyConditions()))) {
- satisfied = true;
- enableConditionalDependency(extensionDependency.getExtensionId());
- break;
- }
- }
+ boolean isConditionalDependencyResolved = resolvedArtifacts.stream()
+ .filter(artifact -> areEquals(conditionalDep, artifact))
+ .flatMap(artifact -> DependencyUtils.getOptionalExtensionInfo(project, artifact).stream())
+ .filter(extension -> extension.getDependencyConditions().isEmpty()
+ || exist(extension.getDependencyConditions()))
+ .findFirst().map(extension -> {
+ enableConditionalDependency(extension.getExtensionId());
+ return true;
+ }).orElse(false);
+
+ if (isConditionalDependencyResolved) {
+ addToMasterList(resolvedArtifacts);
+ var artifactExtensions = getArtifactExtensions(resolvedArtifacts);
+ artifactExtensions.forEach((id, extension) -> extension.setConditional(true));
+ allExtensions.putAll(artifactExtensions);
+ artifactExtensions.forEach((ignored, extension) -> queueAbsentExtensionConditionalDependencies(extension));
}
- // No resolution (yet); give up.
- if (!satisfied) {
- return false;
- }
+ return isConditionalDependencyResolved;
+ }
- // The conditional dependency resolved! Let's now add all of /its/ dependencies
- for (ResolvedArtifact artifact : resolvedArtifacts) {
- // First add the artifact to the master list
- existingArtifacts.add(getKey(artifact));
- ExtensionDependency extensionDependency = DependencyUtils.getExtensionInfoOrNull(project, artifact);
- if (extensionDependency == null) {
- continue;
- }
- // If this artifact represents an extension, mark this one as a conditional extension
- extensionDependency.setConditional(true);
- // Add to the master list of accepted extensions
- allExtensions.put(extensionDependency.getExtensionId(), extensionDependency);
- for (Dependency cd : extensionDependency.getConditionalDependencies()) {
- // Add any unsatisfied/unresolved conditional dependencies of this dependency to the queue
- if (!exists(cd)) {
- queueConditionalDependency(extensionDependency, cd);
- }
- }
- }
- return satisfied;
+ private boolean areEquals(Dependency dependency, ResolvedArtifact artifact) {
+ return dependency.getName().equals(artifact.getName())
+ && Objects.equals(dependency.getVersion(), artifact.getModuleVersion().getId().getVersion())
+ && artifact.getModuleVersion().getId().getGroup().equals(dependency.getGroup());
}
private void queueConditionalDependency(ExtensionDependency extension, Dependency conditionalDep) {
diff --git a/devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/tooling/dependency/DependencyUtils.java b/devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/tooling/dependency/DependencyUtils.java
index 5d0f37b1793e3..d68064a42277b 100644
--- a/devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/tooling/dependency/DependencyUtils.java
+++ b/devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/tooling/dependency/DependencyUtils.java
@@ -10,6 +10,7 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.Optional;
import java.util.Properties;
import org.gradle.api.GradleException;
@@ -73,48 +74,59 @@ public static String asDependencyNotation(ArtifactCoords artifactCoords) {
return String.join(":", artifactCoords.getGroupId(), artifactCoords.getArtifactId(), artifactCoords.getVersion());
}
- public static ExtensionDependency getExtensionInfoOrNull(Project project, ResolvedArtifact artifact) {
- ModuleVersionIdentifier artifactId = artifact.getModuleVersion().getId();
- File artifactFile = artifact.getFile();
-
- if (artifact.getId().getComponentIdentifier() instanceof ProjectComponentIdentifier) {
- final Project projectDep = project.getRootProject().findProject(
- ((ProjectComponentIdentifier) artifact.getId().getComponentIdentifier()).getProjectPath());
- SourceSetContainer sourceSets = projectDep == null ? null
- : projectDep.getExtensions().findByType(SourceSetContainer.class);
- if (sourceSets != null) {
- SourceSet mainSourceSet = sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME);
- File resourcesDir = mainSourceSet.getOutput().getResourcesDir();
- Path descriptorPath = resourcesDir.toPath().resolve(BootstrapConstants.DESCRIPTOR_PATH);
- if (Files.exists(descriptorPath)) {
- return loadExtensionInfo(project, descriptorPath, artifactId, projectDep);
- }
- }
- }
+ public static Optional getOptionalExtensionInfo(Project project, ResolvedArtifact artifact) {
+ return loadExtensionDependencyFromProject(artifact, project)
+ .or(() -> loadExtensionDependencyFromDir(artifact, project))
+ .or(() -> loadExtensionDependencyFromJar(artifact, project));
+ }
- if (!artifactFile.exists()) {
- return null;
- }
- if (artifactFile.isDirectory()) {
- Path descriptorPath = artifactFile.toPath().resolve(BootstrapConstants.DESCRIPTOR_PATH);
- if (Files.exists(descriptorPath)) {
- return loadExtensionInfo(project, descriptorPath, artifactId, null);
- }
- } else if (ArtifactCoords.TYPE_JAR.equals(artifact.getExtension())) {
- try (FileSystem artifactFs = ZipUtils.newFileSystem(artifactFile.toPath())) {
- Path descriptorPath = artifactFs.getPath(BootstrapConstants.DESCRIPTOR_PATH);
- if (Files.exists(descriptorPath)) {
- return loadExtensionInfo(project, descriptorPath, artifactId, null);
- }
- } catch (IOException e) {
- throw new GradleException("Failed to read " + artifactFile, e);
- }
- }
- return null;
+ private static Optional loadExtensionDependencyFromProject(ResolvedArtifact artifact,
+ Project project) {
+ Optional projectDep = Optional.of(artifact.getId().getComponentIdentifier())
+ .filter(ProjectComponentIdentifier.class::isInstance)
+ .map(ProjectComponentIdentifier.class::cast)
+ .map(ProjectComponentIdentifier::getProjectPath)
+ .map(projectPath -> project.getRootProject().findProject(projectPath));
+
+ return projectDep
+ .map(Project::getExtensions)
+ .map(container -> container.findByType(SourceSetContainer.class))
+ .map(container -> container.findByName(SourceSet.MAIN_SOURCE_SET_NAME))
+ .map(it -> it.getOutput().getResourcesDir())
+ .map(File::toPath)
+ .flatMap(resourceDir -> loadOptionalExtensionInfo(project, resourceDir, artifact.getModuleVersion().getId(),
+ projectDep.get()));
+ }
+
+ private static Optional loadExtensionDependencyFromDir(ResolvedArtifact artifact, Project project) {
+ return Optional.of(artifact.getFile().toPath()).filter(Files::exists)
+ .flatMap(path -> loadOptionalExtensionInfo(project, path, artifact.getModuleVersion().getId(), null));
+ }
+
+ private static Optional loadExtensionDependencyFromJar(ResolvedArtifact artifact, Project project) {
+ return Optional.of(artifact)
+ .filter(it -> ArtifactCoords.TYPE_JAR.equals(it.getExtension()))
+ .filter(it -> Files.exists(it.getFile().toPath()))
+ .flatMap(it -> {
+ try (FileSystem artifactFs = ZipUtils.newFileSystem(it.getFile().toPath())) {
+ return loadOptionalExtensionInfo(project, artifactFs.getPath(""), artifact.getModuleVersion().getId(),
+ null);
+ } catch (IOException e) {
+ throw new GradleException("Failed to read " + it.getFile(), e);
+ }
+ });
+ }
+
+ private static Optional loadOptionalExtensionInfo(Project project, Path resourcePath,
+ ModuleVersionIdentifier extensionId, Project extensionProject) {
+ return Optional.of(resourcePath)
+ .map(path -> path.resolve(BootstrapConstants.DESCRIPTOR_PATH))
+ .filter(Files::exists)
+ .map(descriptorPath -> loadExtensionInfo(project, descriptorPath, extensionId, extensionProject));
}
private static ExtensionDependency loadExtensionInfo(Project project, Path descriptorPath,
- ModuleVersionIdentifier exentionId, Project extensionProject) {
+ ModuleVersionIdentifier extensionId, Project extensionProject) {
final Properties extensionProperties = new Properties();
try (BufferedReader reader = Files.newBufferedReader(descriptorPath)) {
extensionProperties.load(reader);
@@ -138,10 +150,10 @@ private static ExtensionDependency loadExtensionInfo(Project project, Path descr
final ArtifactKey[] constraints = BootstrapUtils
.parseDependencyCondition(extensionProperties.getProperty(BootstrapConstants.DEPENDENCY_CONDITION));
if (extensionProject != null) {
- return new LocalExtensionDependency(extensionProject, exentionId, deploymentModule, conditionalDependencies,
+ return new LocalExtensionDependency(extensionProject, extensionId, deploymentModule, conditionalDependencies,
constraints == null ? Collections.emptyList() : Arrays.asList(constraints));
}
- return new ExtensionDependency(exentionId, deploymentModule, conditionalDependencies,
+ return new ExtensionDependency(extensionId, deploymentModule, conditionalDependencies,
constraints == null ? Collections.emptyList() : Arrays.asList(constraints));
}
diff --git a/devtools/maven/src/main/java/io/quarkus/maven/QuarkusBootstrapProvider.java b/devtools/maven/src/main/java/io/quarkus/maven/QuarkusBootstrapProvider.java
index d3529126378ca..7815865536442 100644
--- a/devtools/maven/src/main/java/io/quarkus/maven/QuarkusBootstrapProvider.java
+++ b/devtools/maven/src/main/java/io/quarkus/maven/QuarkusBootstrapProvider.java
@@ -37,8 +37,6 @@
import io.quarkus.maven.dependency.ArtifactCoords;
import io.quarkus.maven.dependency.ArtifactKey;
import io.quarkus.maven.dependency.Dependency;
-import io.quarkus.maven.dependency.GACT;
-import io.quarkus.maven.dependency.GACTV;
import io.quarkus.maven.dependency.ResolvedArtifactDependency;
import io.quarkus.runtime.LaunchMode;
import io.smallrye.common.expression.Expression;
@@ -59,7 +57,7 @@ public class QuarkusBootstrapProvider implements Closeable {
.concurrencyLevel(4).softValues().initialCapacity(10).build();
static ArtifactKey getProjectId(MavenProject project) {
- return new GACT(project.getGroupId(), project.getArtifactId());
+ return ArtifactKey.ga(project.getGroupId(), project.getArtifactId());
}
public RepositorySystem repositorySystem() {
@@ -209,12 +207,13 @@ private CuratedApplication doBootstrap(QuarkusBootstrapMojo mojo, LaunchMode mod
final List localProjects = mojo.mavenProject().getCollectedProjects();
final Set localProjectKeys = new HashSet<>(localProjects.size());
for (MavenProject p : localProjects) {
- localProjectKeys.add(new GACT(p.getGroupId(), p.getArtifactId()));
+ localProjectKeys.add(ArtifactKey.ga(p.getGroupId(), p.getArtifactId()));
}
reloadableModules = new HashSet<>(localProjects.size() + 1);
for (Artifact a : mojo.mavenProject().getArtifacts()) {
- if (localProjectKeys.contains(new GACT(a.getGroupId(), a.getArtifactId()))) {
- reloadableModules.add(new GACT(a.getGroupId(), a.getArtifactId(), a.getClassifier(), a.getType()));
+ if (localProjectKeys.contains(ArtifactKey.ga(a.getGroupId(), a.getArtifactId()))) {
+ reloadableModules
+ .add(ArtifactKey.of(a.getGroupId(), a.getArtifactId(), a.getClassifier(), a.getType()));
}
}
reloadableModules.add(appArtifact.getKey());
@@ -228,7 +227,6 @@ private CuratedApplication doBootstrap(QuarkusBootstrapMojo mojo, LaunchMode mod
} catch (AppModelResolverException e) {
throw new MojoExecutionException("Failed to bootstrap application in " + mode + " mode", e);
}
-
QuarkusBootstrap.Builder builder = QuarkusBootstrap.builder()
.setAppArtifact(appModel.getAppArtifact())
.setExistingModel(appModel)
@@ -237,6 +235,7 @@ private CuratedApplication doBootstrap(QuarkusBootstrapMojo mojo, LaunchMode mod
.setBuildSystemProperties(effectiveProperties)
.setProjectRoot(mojo.baseDir().toPath())
.setBaseName(mojo.finalName())
+ .setOriginalBaseName(mojo.mavenProject().getBuild().getFinalName())
.setTargetDirectory(mojo.buildDir().toPath())
.setForcedDependencies(forcedDependencies);
@@ -277,12 +276,12 @@ protected CuratedApplication bootstrapApplication(QuarkusBootstrapMojo mojo, Lau
return prodApp == null ? prodApp = doBootstrap(mojo, mode) : prodApp;
}
- protected GACTV managingProject(QuarkusBootstrapMojo mojo) {
+ protected ArtifactCoords managingProject(QuarkusBootstrapMojo mojo) {
if (mojo.appArtifactCoords() == null) {
return null;
}
final Artifact artifact = mojo.mavenProject().getArtifact();
- return new GACTV(artifact.getGroupId(), artifact.getArtifactId(),
+ return ArtifactCoords.of(artifact.getGroupId(), artifact.getArtifactId(),
artifact.getClassifier(), artifact.getArtifactHandler().getExtension(),
artifact.getVersion());
}
@@ -321,7 +320,7 @@ private ArtifactCoords appArtifact(QuarkusBootstrapMojo mojo)
}
final String groupId = coordsArr[0];
final String artifactId = coordsArr[1];
- String classifier = "";
+ String classifier = ArtifactCoords.DEFAULT_CLASSIFIER;
String type = ArtifactCoords.TYPE_JAR;
String version = null;
if (coordsArr.length == 3) {
@@ -349,7 +348,7 @@ private ArtifactCoords appArtifact(QuarkusBootstrapMojo mojo)
}
}
- return new GACTV(groupId, artifactId, classifier, type, version);
+ return ArtifactCoords.of(groupId, artifactId, classifier, type, version);
}
@Override
diff --git a/docs/src/main/asciidoc/deploying-to-kubernetes.adoc b/docs/src/main/asciidoc/deploying-to-kubernetes.adoc
index 4128b0c53197d..c92d25fe88144 100644
--- a/docs/src/main/asciidoc/deploying-to-kubernetes.adoc
+++ b/docs/src/main/asciidoc/deploying-to-kubernetes.adoc
@@ -1052,7 +1052,7 @@ kubectl port-forward svc/ 5005:5005
Using this command, you'll forward the traffic from the "localhost:5005" to the kubernetes service running the java agent using the port "5005" which is the one that the java agent uses by default for remote debugging. You can also configure another java agent port using the property `quarkus.kubernetes.remote-debug.address-port`.
-Finally, all you need to do is to configure your favorite IDE to attach the java agent process that is forwarded to `localhost:5005` and start to debug your application. For example, in IntelliJ IDEA, you can follow https://www.jetbrains.com/help/idea/tutorial-remote-debug.html:[this tutorial] to debug remote applications.
+Finally, all you need to do is to configure your favorite IDE to attach the java agent process that is forwarded to `localhost:5005` and start to debug your application. For example, in IntelliJ IDEA, you can follow https://www.jetbrains.com/help/idea/tutorial-remote-debug.html[this tutorial] to debug remote applications.
== Using existing resources
diff --git a/docs/src/main/asciidoc/hibernate-orm-panache.adoc b/docs/src/main/asciidoc/hibernate-orm-panache.adoc
index 8859677edd6dc..5008778c42402 100644
--- a/docs/src/main/asciidoc/hibernate-orm-panache.adoc
+++ b/docs/src/main/asciidoc/hibernate-orm-panache.adoc
@@ -815,7 +815,7 @@ public class RaceWeight {
}
// Only the race and the average weight will be loaded
-PanacheQuery query = Person.find("select d.race, AVG(d.weight) from Dog d group by d.race).project(RaceWeight.class);
+PanacheQuery query = Person.find("select d.race, AVG(d.weight) from Dog d group by d.race").project(RaceWeight.class);
----
<1> Hibernate ORM will use this constructor. When the query has a select clause, it is possible to have multiple constructors.
@@ -827,7 +827,7 @@ For example, this will fail:
[source,java]
----
-PanacheQuery query = Person.find("select new MyView(d.race, AVG(d.weight)) from Dog d group by d.race).project(AnotherView.class);
+PanacheQuery query = Person.find("select new MyView(d.race, AVG(d.weight)) from Dog d group by d.race").project(AnotherView.class);
----
====
diff --git a/docs/src/main/asciidoc/http-reference.adoc b/docs/src/main/asciidoc/http-reference.adoc
index 0ecb30bb527e2..3633a29e46301 100644
--- a/docs/src/main/asciidoc/http-reference.adoc
+++ b/docs/src/main/asciidoc/http-reference.adoc
@@ -127,8 +127,8 @@ Your `application.properties` would then look like this:
[source,properties]
----
-quarkus.http.ssl.certificate.file=/path/to/certificate
-quarkus.http.ssl.certificate.key-file=/path/to/key
+quarkus.http.ssl.certificate.files=/path/to/certificate
+quarkus.http.ssl.certificate.key-files=/path/to/key
----
=== Providing a keystore
diff --git a/docs/src/main/asciidoc/javascript/config.js b/docs/src/main/asciidoc/javascript/config.js
index 22e453b5b853c..898d7643f61cf 100644
--- a/docs/src/main/asciidoc/javascript/config.js
+++ b/docs/src/main/asciidoc/javascript/config.js
@@ -296,6 +296,11 @@ function makeCollapsibleHandler(descDiv, td, row,
return;
}
+ // don't collapse if the target is button with attribute "do-not-collapse"
+ if( (target.localName == 'button' && target.hasAttribute("do-not-collapse"))) {
+ return;
+ }
+
var isCollapsed = descDiv.classList.contains('description-collapsed');
if( isCollapsed ) {
collapsibleSpan.childNodes.item(0).nodeValue = 'Show less';
diff --git a/docs/src/main/asciidoc/kafka-schema-registry-avro.adoc b/docs/src/main/asciidoc/kafka-schema-registry-avro.adoc
index 054de5e36cda3..8c06be867948b 100644
--- a/docs/src/main/asciidoc/kafka-schema-registry-avro.adoc
+++ b/docs/src/main/asciidoc/kafka-schema-registry-avro.adoc
@@ -610,6 +610,81 @@ public class MovieResourceTest {
}
----
+[[apicurio-versions-compatibility]]
+== Using compatible versions of the Apicurio Registry
+
+The `quarkus-apicurio-registry-avro` extension depends on recent versions of Apicurio Registry client,
+and most versions of Apicurio Registry server and client are backwards compatible.
+For some you need to make sure that the client used by Serdes is compatible with the server.
+
+For example, with Apicurio dev service if you set the image name to use version `2.1.5.Final`:
+
+[source,properties]
+----
+quarkus.apicurio-registry.devservices.image-name=quay.io/apicurio/apicurio-registry-mem:2.1.5.Final
+----
+
+You need to make sure that `apicurio-registry-serdes-avro-serde` dependency
+and the REST client `apicurio-common-rest-client-vertx` dependency are set to compatible versions:
+
+[source,xml,role="primary asciidoc-tabs-target-sync-cli asciidoc-tabs-target-sync-maven"]
+.pom.xml
+----
+
+ io.quarkus
+ quarkus-apicurio-registry-avro
+
+
+ io.apicurio
+ apicurio-common-rest-client-vertx
+
+
+ io.apicurio
+ apicurio-registry-serdes-avro-serde
+
+
+
+
+ io.apicurio
+ apicurio-registry-serdes-avro-serde
+ 2.1.5.Final
+
+
+ io.apicurio
+ apicurio-common-rest-client-jdk
+
+
+
+
+ io.apicurio
+ apicurio-common-rest-client-vertx
+ 0.1.5.Final
+
+----
+
+[source,gradle,role="secondary asciidoc-tabs-target-sync-gradle"]
+.build.gradle
+----
+dependencies {
+ implementation(platform("io.quarkus.platform:quarkus-bom:2.12.3.Final"))
+
+ ...
+
+ implementation("io.quarkus:quarkus-apicurio-registry-avro")
+ implementation("io.apicurio:apicurio-registry-serdes-avro-serde") {
+ exclude group: "io.apicurio", module: "apicurio-common-rest-client-jdk"
+ version {
+ strictly "2.1.5.Final"
+ }
+ }
+ implementation("io.apicurio:apicurio-common-rest-client-vertx") {
+ version {
+ strictly "0.1.5.Final"
+ }
+ }
+}
+----
+
[[confluent]]
== Using the Confluent Schema Registry
diff --git a/docs/src/main/asciidoc/kafka.adoc b/docs/src/main/asciidoc/kafka.adoc
index efb06fd119ec2..a8281d1280a9a 100644
--- a/docs/src/main/asciidoc/kafka.adoc
+++ b/docs/src/main/asciidoc/kafka.adoc
@@ -282,7 +282,7 @@ Thus, you can use both.
The first one provides more fine-grained tuning such as the worker pool to use and whether it preserves the order.
The second one, used also with other reactive features of Quarkus, uses the default worker pool and preserves the order.
-Detailed information on the usage of `@Blocking` annotation can be found in https://smallrye.io/smallrye-reactive-messaging/smallrye-reactive-messaging/3.1/advanced/blocking.html[SmallRye Reactive Messaging – Handling blocking execution].
+Detailed information on the usage of `@Blocking` annotation can be found in https://smallrye.io/smallrye-reactive-messaging/latest/concepts/blocking/[SmallRye Reactive Messaging – Handling blocking execution].
====
[TIP]
@@ -364,6 +364,9 @@ If high throughput is important for you, and you are not limited by the downstre
- or set `enable.auto.commit` to true and annotate the consuming method with `@Acknowledgment(Acknowledgment.Strategy.NONE)`.
====
+Smallrye Reactive Messaging enables implementing custom commit strategies.
+See https://smallrye.io/smallrye-reactive-messaging/latest/kafka/receiving-kafka-records/#acknowledgement[SmallRye Reactive Messaging documentation] for more information.
+
[[error-handling]]
=== Error Handling Strategies
@@ -389,6 +392,9 @@ The record written on the dead letter queue contains a set of additional headers
- *dead-letter-partition*: the original partition of the record (integer mapped to String)
- *dead-letter-offset*: the original offset of the record (long mapped to String)
+Smallrye Reactive Messaging enables implementing custom failure strategies.
+See https://smallrye.io/smallrye-reactive-messaging/latest/kafka/receiving-kafka-records/#acknowledgement[SmallRye Reactive Messaging documentation] for more information.
+
==== Retrying processing
You can combine Reactive Messaging with https://github.com/smallrye/smallrye-fault-tolerance[SmallRye Fault Tolerance], and retry processing if it failed:
@@ -926,7 +932,18 @@ The `io.smallrye.reactive.messaging.annotations.Emitter`, `io.smallrye.reactive.
The new `Emitter.send` method returns a `CompletionStage` completed when the produced message is acknowledged.
====
-More information on how to use `Emitter` can be found in https://smallrye.io/smallrye-reactive-messaging/smallrye-reactive-messaging/3.1/emitter/emitter.html#_emitter_and_channel[SmallRye Reactive Messaging – Emitters and Channels]
+[NOTE]
+.Depreciation
+====
+`MutinyEmitter#send(Message msg)` method is deprecated in favor of following methods receiving `Message` for emitting:
+
+* `> Uni sendMessage(M msg)`
+* `> void sendMessageAndAwait(M msg)`
+* `> Cancellable sendMessageAndForget(M msg)`
+
+====
+
+More information on how to use `Emitter` can be found in https://smallrye.io/smallrye-reactive-messaging/latest/concepts/emitter/[SmallRye Reactive Messaging – Emitters and Channels]
=== Write Acknowledgement
@@ -1254,11 +1271,6 @@ The `KafkaTransactions#withTransactionAndAck` method acks and nacks the message
Nacked messages will be handled by the failure strategy of the incoming channel, (see <>).
Configuring `failure-strategy=ignore` simply resets the Kafka consumer to the last committed offsets and resumes the consumption from there.
-[NOTE]
-====
-Redpanda does not yet support link:https://github.com/redpanda-data/redpanda/issues/3279[producer scalability for exactly-once processing].
-In order to use Kafka exactly-once processing with Quarkus you can configure Dev Services for Kafka to <>.
-====
[[kafka-bare-clients]]
== Accessing Kafka clients directly
@@ -1996,10 +2008,14 @@ As described in <>, you need to add the `@Blocking` annotat
See the xref:quarkus-reactive-architecture.adoc[Quarkus Reactive Architecture documentation] for further details on this topic.
+== Channel Decorators
+
+SmallRye Reactive Messaging supports decorating incoming and outgoing channels for implementing cross-cutting concerns such as monitoring, tracing or message interception. For more information on implementing decorators and message interceptors see the http://smallrye.io/smallrye-reactive-messaging/3.19.1/concepts/decorators/[SmallRye Reactive Messaging documentation].
+
[[kafka-configuration]]
== Configuration Reference
-More details about the SmallRye Reactive Messaging configuration can be found in the https://smallrye.io/smallrye-reactive-messaging/smallrye-reactive-messaging/3.1/kafka/kafka.html[SmallRye Reactive Messaging - Kafka Connector Documentation].
+More details about the SmallRye Reactive Messaging configuration can be found in the https://smallrye.io/smallrye-reactive-messaging/latest/kafka/kafka/#using-the-kafka-connector[SmallRye Reactive Messaging - Kafka Connector Documentation].
[TIP]
====
@@ -2336,7 +2352,7 @@ public class FruitStore {
Mutiny.Session session; // <1>
@Incoming("in")
- public Uni consume(Fruit fruit) {
+ public Uni consume(Fruit entity) {
return session.withTransaction(t -> { // <2>
return entity.persistAndFlush() // <3>
.replaceWithVoid(); // <4>
diff --git a/docs/src/main/asciidoc/opentracing.adoc b/docs/src/main/asciidoc/opentracing.adoc
index 3c5e6d83c84f8..2905ffb25afc2 100644
--- a/docs/src/main/asciidoc/opentracing.adoc
+++ b/docs/src/main/asciidoc/opentracing.adoc
@@ -4,12 +4,22 @@ and pull requests should be submitted there:
https://github.com/quarkusio/quarkus/tree/main/docs/src/main/asciidoc
////
= Using OpenTracing
+:extension-status: deprecated
include::./attributes.adoc[]
This guide explains how your Quarkus application can utilize OpenTracing to provide distributed tracing for
interactive web applications.
+[IMPORTANT]
+====
+xref:opentelemetry.adoc[OpenTelemetry] is the recommended approach to tracing and telemetry for Quarkus.
+
+When Quarkus will upgrade to Eclipse MicroProfile 6, the SmallRye OpenTracing support will be discontinued.
+====
+
+include::{includes}/extension-status.adoc[]
+
== Prerequisites
:prerequisites-docker:
diff --git a/docs/src/main/asciidoc/qute.adoc b/docs/src/main/asciidoc/qute.adoc
index 0fcfce0d6d71e..b3d32086fbf5b 100644
--- a/docs/src/main/asciidoc/qute.adoc
+++ b/docs/src/main/asciidoc/qute.adoc
@@ -498,29 +498,6 @@ public class ReportGenerator {
<2> Use the `@Scheduled` annotation to instruct Quarkus to execute this method on the half hour. For more information see the xref:scheduler.adoc[Scheduler] guide.
<3> The `TemplateInstance.render()` method triggers rendering. Note that this method blocks the current thread.
-== Reactive and Asynchronous APIs
-
-Templates can be rendered as a `CompletionStage` (completed with the rendered output asynchronously) or as `Publisher` containing the rendered chunks:
-
-[source, java]
-----
-CompletionStage async = template.data("name", "neo").renderAsync();
-Publisher publisher = template.data("name", "neo").publisher();
-----
-
-In the case of a `Publisher`, the template is rendered chunk by chunk following the requests from the subscriber.
-The rendering is not started until a subscriber requests it.
-The returned `Publisher` is an instance of `io.smallrye.mutiny.Multi`.
-
-It is possible to create an instance of `io.smallrye.mutiny.Uni` as follows:
-
-[source, java]
-----
-Uni uni = Uni.createFrom().completionStage(() -> template.data("name", "neo").renderAsync());
-----
-
-In this case, the rendering only starts once the subscriber requests it.
-
== Qute Reference Guide
To learn more about Qute, please refer to the xref:qute-reference.adoc[Qute reference guide].
diff --git a/docs/src/main/asciidoc/redis-reference.adoc b/docs/src/main/asciidoc/redis-reference.adoc
index 0d5f969364a0f..5976003d40733 100644
--- a/docs/src/main/asciidoc/redis-reference.adoc
+++ b/docs/src/main/asciidoc/redis-reference.adoc
@@ -713,7 +713,7 @@ public static class MyExampleCustomizer implements RedisOptionsCustomizer {
=== Dev Services
-See link:redis-dev-services.adoc[Redis Dev Service].
+See xref:redis-dev-services.adoc[Redis Dev Service].
[[redis-configuration-reference]]
== Configuration Reference
diff --git a/docs/src/main/asciidoc/redis.adoc b/docs/src/main/asciidoc/redis.adoc
index cedbf72431104..57a2e59c3372f 100644
--- a/docs/src/main/asciidoc/redis.adoc
+++ b/docs/src/main/asciidoc/redis.adoc
@@ -526,4 +526,4 @@ Once the build is finished, you can run the executable with:
== Going further
-To learn more about the Quarkus Redis extension, check link:redis-reference.adoc[the Redis extension reference guide].
+To learn more about the Quarkus Redis extension, check xref:redis-reference.adoc[the Redis extension reference guide].
diff --git a/docs/src/main/asciidoc/security-csrf-prevention.adoc b/docs/src/main/asciidoc/security-csrf-prevention.adoc
index 376c5934a5469..e877219bf1b54 100644
--- a/docs/src/main/asciidoc/security-csrf-prevention.adoc
+++ b/docs/src/main/asciidoc/security-csrf-prevention.adoc
@@ -7,9 +7,9 @@ https://github.com/quarkusio/quarkus/tree/main/docs/src/main/asciidoc
include::./attributes.adoc[]
-https://owasp.org/www-community/attacks/csrf[Cross-Site Request Forgery(CSRF)] is an attack that forces an end user to execute unwanted actions on a web application in which they are currently authenticated.
+https://owasp.org/www-community/attacks/csrf[Cross-Site Request Forgery (CSRF)] is an attack that forces an end user to execute unwanted actions on a web application in which they are currently authenticated.
-Quarkus Security provides a CSRF prevention feature which consists of a xref:resteasy-reactive.adoc[Resteasy Reactive] server filter which creates and verifies CSRF tokens and an HTML form parameter provider which supports the xref:qute-reference.adoc#injecting-beans-directly-in-templates[injection of CSRF tokens in Qute templates].
+Quarkus Security provides a CSRF prevention feature which consists of a xref:resteasy-reactive.adoc[RESTEasy Reactive] server filter which creates and verifies CSRF tokens and an HTML form parameter provider which supports the xref:qute-reference.adoc#injecting-beans-directly-in-templates[injection of CSRF tokens in Qute templates].
== Creating the Project
@@ -45,7 +45,7 @@ This will add the following to your build file:
implementation("io.quarkus:quarkus-csrf-reactive")
----
-Next lets add a Qute template producing an HTML form:
+Next, let's add a `csrfToken.html` Qute template producing an HTML form in the `src/main/resources/templates` folder:
[source,html]
----
@@ -67,11 +67,8 @@ Next lets add a Qute template producing an HTML form: