de.thetaphi
diff --git a/core/deployment/src/main/java/io/quarkus/banner/BannerConfig.java b/core/deployment/src/main/java/io/quarkus/banner/BannerConfig.java
index ae5d02030e8301..ce1d2ddf0f9717 100644
--- a/core/deployment/src/main/java/io/quarkus/banner/BannerConfig.java
+++ b/core/deployment/src/main/java/io/quarkus/banner/BannerConfig.java
@@ -3,6 +3,9 @@
import io.quarkus.runtime.annotations.ConfigItem;
import io.quarkus.runtime.annotations.ConfigRoot;
+/**
+ * Banner
+ */
@ConfigRoot(name = "banner")
public class BannerConfig {
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/BootstrapConfig.java b/core/deployment/src/main/java/io/quarkus/deployment/BootstrapConfig.java
index fc4e1e776034c0..081810130ed904 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/BootstrapConfig.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/BootstrapConfig.java
@@ -4,6 +4,8 @@
import io.quarkus.runtime.annotations.ConfigRoot;
/**
+ * Bootstrap
+ *
* This is used currently only to suppress warnings about unknown properties
* when the user supplies something like: -Dquarkus.debug.reflection=true
*/
@@ -42,7 +44,7 @@ public class BootstrapConfig {
boolean disableJarCache;
/**
- * A temporary option introduced to avoid a logging warning when {@code }-Dquarkus.bootstrap.incubating-model-resolver}
+ * A temporary option introduced to avoid a logging warning when {@code -Dquarkus.bootstrap.incubating-model-resolver}
* is added to the build command line.
* This option enables an incubating implementation of the Quarkus Application Model resolver.
* This option will be removed as soon as the incubating implementation becomes the default one.
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/CodeGenerator.java b/core/deployment/src/main/java/io/quarkus/deployment/CodeGenerator.java
index 92abc57bd3e642..c98dad86571c4d 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/CodeGenerator.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/CodeGenerator.java
@@ -1,6 +1,6 @@
package io.quarkus.deployment;
-import static io.quarkus.commons.classloading.ClassloadHelper.fromClassNameToResourceName;
+import static io.quarkus.commons.classloading.ClassLoaderHelper.fromClassNameToResourceName;
import java.io.BufferedWriter;
import java.io.IOException;
@@ -227,7 +227,8 @@ public static void dumpCurrentConfigValues(ApplicationModel appModel, String lau
if (previouslyRecordedProperties.isEmpty()) {
try {
readConfig(appModel, mode, buildSystemProps, deploymentClassLoader, configReader -> {
- var config = configReader.initConfiguration(mode, buildSystemProps, appModel.getPlatformProperties());
+ var config = configReader.initConfiguration(mode, buildSystemProps, new Properties(),
+ appModel.getPlatformProperties());
final Map allProps = new HashMap<>();
for (String name : config.getPropertyNames()) {
allProps.put(name, ConfigTrackingValueTransformer.asString(config.getConfigValue(name)));
@@ -287,7 +288,8 @@ public static void dumpCurrentConfigValues(ApplicationModel appModel, String lau
public static Config getConfig(ApplicationModel appModel, LaunchMode launchMode, Properties buildSystemProps,
QuarkusClassLoader deploymentClassLoader) throws CodeGenException {
return readConfig(appModel, launchMode, buildSystemProps, deploymentClassLoader,
- configReader -> configReader.initConfiguration(launchMode, buildSystemProps, appModel.getPlatformProperties()));
+ configReader -> configReader.initConfiguration(launchMode, buildSystemProps, new Properties(),
+ appModel.getPlatformProperties()));
}
public static T readConfig(ApplicationModel appModel, LaunchMode launchMode, Properties buildSystemProps,
@@ -340,7 +342,7 @@ public static T readConfig(ApplicationModel appModel, LaunchMode launchMode,
final QuarkusClassLoader.Builder configClBuilder = QuarkusClassLoader.builder("CodeGenerator Config ClassLoader",
deploymentClassLoader, false);
if (!allowedConfigServices.isEmpty()) {
- configClBuilder.addElement(new MemoryClassPathElement(allowedConfigServices, true));
+ configClBuilder.addNormalPriorityElement(new MemoryClassPathElement(allowedConfigServices, true));
}
if (!bannedConfigServices.isEmpty()) {
configClBuilder.addBannedElement(new MemoryClassPathElement(bannedConfigServices, true));
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/CollectionClassProcessor.java b/core/deployment/src/main/java/io/quarkus/deployment/CollectionClassProcessor.java
index ac0efab5551dcf..530a695ea74073 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/CollectionClassProcessor.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/CollectionClassProcessor.java
@@ -8,13 +8,13 @@
public class CollectionClassProcessor {
@BuildStep
ReflectiveClassBuildItem setupCollectionClasses() {
- return ReflectiveClassBuildItem.builder(ArrayList.class.getName(),
- HashMap.class.getName(),
- HashSet.class.getName(),
- LinkedList.class.getName(),
- LinkedHashMap.class.getName(),
- LinkedHashSet.class.getName(),
- TreeMap.class.getName(),
- TreeSet.class.getName()).build();
+ return ReflectiveClassBuildItem.builder(ArrayList.class,
+ HashMap.class,
+ HashSet.class,
+ LinkedList.class,
+ LinkedHashMap.class,
+ LinkedHashSet.class,
+ TreeMap.class,
+ TreeSet.class).reason(getClass().getName()).build();
}
}
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/ConfigBuildTimeConfig.java b/core/deployment/src/main/java/io/quarkus/deployment/ConfigBuildTimeConfig.java
index 95d1c4e04bdd44..059266a4ea3ba1 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/ConfigBuildTimeConfig.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/ConfigBuildTimeConfig.java
@@ -1,10 +1,15 @@
package io.quarkus.deployment;
+import io.quarkus.runtime.annotations.ConfigDocPrefix;
import io.quarkus.runtime.annotations.ConfigItem;
import io.quarkus.runtime.annotations.ConfigPhase;
import io.quarkus.runtime.annotations.ConfigRoot;
+/**
+ * Configuration
+ */
@ConfigRoot(name = ConfigItem.PARENT, phase = ConfigPhase.BUILD_TIME)
+@ConfigDocPrefix("quarkus.config")
public class ConfigBuildTimeConfig {
/**
*
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/DebugConfig.java b/core/deployment/src/main/java/io/quarkus/deployment/DebugConfig.java
index e75f81adc70576..d3a8130efc9c89 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/DebugConfig.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/DebugConfig.java
@@ -6,6 +6,8 @@
import io.quarkus.runtime.annotations.ConfigRoot;
/**
+ * Debugging
+ *
* This is used currently only to suppress warnings about unknown properties
* when the user supplies something like: -Dquarkus.debug.reflection=true
*
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/ExtensionLoader.java b/core/deployment/src/main/java/io/quarkus/deployment/ExtensionLoader.java
index d4076b42abab70..6d7bc5bd526c9b 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/ExtensionLoader.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/ExtensionLoader.java
@@ -13,6 +13,8 @@
import static java.util.Arrays.asList;
import java.io.IOException;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
@@ -23,6 +25,7 @@
import java.lang.reflect.Parameter;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
+import java.lang.reflect.UndeclaredThrowableException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -129,12 +132,14 @@ private static boolean isRecorder(AnnotatedElement element) {
* @throws IOException if the class loader could not load a resource
* @throws ClassNotFoundException if a build step class is not found
*/
- public static Consumer loadStepsFrom(ClassLoader classLoader, Properties buildSystemProps,
+ public static Consumer loadStepsFrom(ClassLoader classLoader,
+ Properties buildSystemProps, Properties runtimeProperties,
ApplicationModel appModel, LaunchMode launchMode, DevModeType devModeType)
throws IOException, ClassNotFoundException {
final BuildTimeConfigurationReader reader = new BuildTimeConfigurationReader(classLoader);
- final SmallRyeConfig src = reader.initConfiguration(launchMode, buildSystemProps, appModel.getPlatformProperties());
+ final SmallRyeConfig src = reader.initConfiguration(launchMode, buildSystemProps, runtimeProperties,
+ appModel.getPlatformProperties());
// install globally
QuarkusConfigFactory.setConfig(src);
final BuildTimeConfigurationReader.ReadResult readResult = reader.readConfiguration(src);
@@ -432,6 +437,7 @@ private static Consumer loadStepsFromClass(Class> clazz,
final List methods = getMethods(clazz);
final Map> nameToMethods = methods.stream().collect(Collectors.groupingBy(m -> m.getName()));
+ MethodHandles.Lookup lookup = MethodHandles.publicLookup();
for (Method method : methods) {
final BuildStep buildStep = method.getAnnotation(BuildStep.class);
if (buildStep == null) {
@@ -785,6 +791,7 @@ private static Consumer loadStepsFromClass(Class> clazz,
stepId = name;
}
+ MethodHandle methodHandle = unreflect(method, lookup);
chainConfig = chainConfig
.andThen(bcb -> {
BuildStepBuilder bsb = bcb.addBuildStep(new io.quarkus.builder.BuildStep() {
@@ -846,17 +853,13 @@ public void execute(final BuildContext bc) {
}
Object result;
try {
- result = method.invoke(instance, methodArgs);
+ result = methodHandle.bindTo(instance).invokeWithArguments(methodArgs);
} catch (IllegalAccessException e) {
throw ReflectUtil.toError(e);
- } catch (InvocationTargetException e) {
- try {
- throw e.getCause();
- } catch (RuntimeException | Error e2) {
- throw e2;
- } catch (Throwable t) {
- throw new IllegalStateException(t);
- }
+ } catch (RuntimeException | Error e2) {
+ throw e2;
+ } catch (Throwable t) {
+ throw new UndeclaredThrowableException(t);
}
resultConsumer.accept(bc, result);
if (isRecorder) {
@@ -885,6 +888,15 @@ public String toString() {
return chainConfig;
}
+ private static MethodHandle unreflect(Method method, MethodHandles.Lookup lookup) {
+ try {
+ return lookup.unreflect(method);
+ } catch (IllegalAccessException e) {
+ throw ReflectUtil.toError(e);
+ }
+
+ }
+
private static BooleanSupplier and(BooleanSupplier addStep, BooleanSupplierFactoryBuildItem supplierFactory,
Class extends BooleanSupplier>[] testClasses, boolean inv) {
for (Class extends BooleanSupplier> testClass : testClasses) {
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/Feature.java b/core/deployment/src/main/java/io/quarkus/deployment/Feature.java
index b0c007df14313e..497136eab4c929 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/Feature.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/Feature.java
@@ -49,6 +49,7 @@ public enum Feature {
JDBC_MSSQL,
JDBC_MYSQL,
JDBC_ORACLE,
+ JFR,
KAFKA_CLIENT,
KAFKA_STREAMS,
KEYCLOAK_AUTHORIZATION,
@@ -72,6 +73,7 @@ public enum Feature {
OBSERVABILITY,
OIDC,
OIDC_CLIENT,
+ OIDC_CLIENT_REGISTRATION,
RESTEASY_CLIENT_OIDC_FILTER,
REST_CLIENT_OIDC_FILTER,
OIDC_CLIENT_GRAPHQL_CLIENT_INTEGRATION,
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/GeneratedClassGizmoAdaptor.java b/core/deployment/src/main/java/io/quarkus/deployment/GeneratedClassGizmoAdaptor.java
index eaff60bf8855aa..6f3547172cc3b0 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/GeneratedClassGizmoAdaptor.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/GeneratedClassGizmoAdaptor.java
@@ -1,17 +1,13 @@
package io.quarkus.deployment;
-import static io.quarkus.commons.classloading.ClassloadHelper.fromClassNameToResourceName;
-
import java.io.StringWriter;
import java.io.Writer;
-import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import io.quarkus.bootstrap.BootstrapDebug;
-import io.quarkus.bootstrap.classloading.ClassPathElement;
import io.quarkus.bootstrap.classloading.QuarkusClassLoader;
import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.builditem.GeneratedClassBuildItem;
@@ -36,7 +32,7 @@ public GeneratedClassGizmoAdaptor(BuildProducer generat
Predicate applicationClassPredicate) {
this.generatedClasses = generatedClasses;
this.applicationClassPredicate = applicationClassPredicate;
- this.sources = BootstrapDebug.DEBUG_SOURCES_DIR != null ? new ConcurrentHashMap<>() : null;
+ this.sources = BootstrapDebug.debugSourcesDir() != null ? new ConcurrentHashMap<>() : null;
}
public GeneratedClassGizmoAdaptor(BuildProducer generatedClasses,
@@ -48,7 +44,7 @@ public boolean test(String s) {
return isApplicationClass(generatedToBaseNameFunction.apply(s));
}
};
- this.sources = BootstrapDebug.DEBUG_SOURCES_DIR != null ? new ConcurrentHashMap<>() : null;
+ this.sources = BootstrapDebug.debugSourcesDir() != null ? new ConcurrentHashMap<>() : null;
}
@Override
@@ -75,12 +71,7 @@ public Writer getSourceWriter(String className) {
}
public static boolean isApplicationClass(String className) {
- QuarkusClassLoader cl = (QuarkusClassLoader) Thread.currentThread()
- .getContextClassLoader();
- //if the class file is present in this (and not the parent) CL then it is an application class
- List res = cl
- .getElementsWithResource(fromClassNameToResourceName(className), true);
- return !res.isEmpty();
+ return QuarkusClassLoader.isApplicationClass(className);
}
}
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/InetAddressProcessor.java b/core/deployment/src/main/java/io/quarkus/deployment/InetAddressProcessor.java
new file mode 100644
index 00000000000000..2f9ae24552db1a
--- /dev/null
+++ b/core/deployment/src/main/java/io/quarkus/deployment/InetAddressProcessor.java
@@ -0,0 +1,15 @@
+package io.quarkus.deployment;
+
+import io.quarkus.deployment.annotations.BuildProducer;
+import io.quarkus.deployment.annotations.BuildStep;
+import io.quarkus.deployment.builditem.nativeimage.ServiceProviderBuildItem;
+
+public class InetAddressProcessor {
+
+ @BuildStep
+ void registerInetAddressServiceProvider(BuildProducer services) {
+ // service provider loaded by java.net.InetAddress.loadResolver
+ services.produce(ServiceProviderBuildItem.allProvidersFromClassPath("java.net.spi.InetAddressResolverProvider"));
+ }
+
+}
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/IsDockerWorking.java b/core/deployment/src/main/java/io/quarkus/deployment/IsDockerWorking.java
index 1efd20d2da3826..19882135e0e292 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/IsDockerWorking.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/IsDockerWorking.java
@@ -6,6 +6,7 @@
import java.util.List;
import io.quarkus.deployment.util.ContainerRuntimeUtil;
+import io.quarkus.deployment.util.ContainerRuntimeUtil.ContainerRuntime;
public class IsDockerWorking extends IsContainerRuntimeWorking {
public IsDockerWorking() {
@@ -19,7 +20,8 @@ public IsDockerWorking(boolean silent) {
private static class DockerBinaryStrategy implements Strategy {
@Override
public Result get() {
- if (ContainerRuntimeUtil.detectContainerRuntime(false) != UNAVAILABLE) {
+ if (ContainerRuntimeUtil.detectContainerRuntime(false,
+ ContainerRuntime.DOCKER, ContainerRuntime.PODMAN) != UNAVAILABLE) {
return Result.AVAILABLE;
} else {
return Result.UNKNOWN;
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/IsPodmanWorking.java b/core/deployment/src/main/java/io/quarkus/deployment/IsPodmanWorking.java
index 2a6fce41c656d0..a9e5aa857f1d3a 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/IsPodmanWorking.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/IsPodmanWorking.java
@@ -5,6 +5,7 @@
import java.util.List;
import io.quarkus.deployment.util.ContainerRuntimeUtil;
+import io.quarkus.deployment.util.ContainerRuntimeUtil.ContainerRuntime;
public class IsPodmanWorking extends IsContainerRuntimeWorking {
public IsPodmanWorking() {
@@ -21,7 +22,11 @@ public IsPodmanWorking(boolean silent) {
private static class PodmanBinaryStrategy implements Strategy {
@Override
public Result get() {
- return (ContainerRuntimeUtil.detectContainerRuntime(false) != UNAVAILABLE) ? Result.AVAILABLE : Result.UNKNOWN;
+ if (ContainerRuntimeUtil.detectContainerRuntime(false, ContainerRuntime.PODMAN) != UNAVAILABLE) {
+ return Result.AVAILABLE;
+ } else {
+ return Result.UNKNOWN;
+ }
}
}
}
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/JniProcessor.java b/core/deployment/src/main/java/io/quarkus/deployment/JniProcessor.java
index 70cd34ba7fed40..9145a080dc9685 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/JniProcessor.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/JniProcessor.java
@@ -18,6 +18,9 @@ public class JniProcessor {
JniConfig jni;
+ /**
+ * JNI
+ */
@ConfigRoot(phase = ConfigPhase.BUILD_TIME)
static class JniConfig {
/**
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/PlatformConfig.java b/core/deployment/src/main/java/io/quarkus/deployment/PlatformConfig.java
index 82434cae34f93e..1c018ef9baca78 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/PlatformConfig.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/PlatformConfig.java
@@ -4,6 +4,8 @@
import io.quarkus.runtime.annotations.ConfigRoot;
/**
+ * Platform
+ *
* This is used currently only to suppress warnings about unknown properties
* when the user supplies something like: -Dquarkus.platform.group-id=someGroup
*
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 c5380c77d56644..b423d833787567 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/QuarkusAugmentor.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/QuarkusAugmentor.java
@@ -1,6 +1,5 @@
package io.quarkus.deployment;
-import java.io.Closeable;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
@@ -12,9 +11,11 @@
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
+import java.util.function.Supplier;
import org.jboss.logging.Logger;
+import io.quarkus.bootstrap.app.DependencyInfoProvider;
import io.quarkus.bootstrap.classloading.QuarkusClassLoader;
import io.quarkus.bootstrap.model.ApplicationModel;
import io.quarkus.builder.BuildChain;
@@ -54,8 +55,10 @@ public class QuarkusAugmentor {
private final Collection excludedFromIndexing;
private final LiveReloadBuildItem liveReloadBuildItem;
private final Properties buildSystemProperties;
+ private final Properties runtimeProperties;
private final Path targetDir;
private final ApplicationModel effectiveModel;
+ private final Supplier depInfoProvider;
private final String baseName;
private final String originalBaseName;
private final boolean rebuild;
@@ -73,6 +76,7 @@ public class QuarkusAugmentor {
this.excludedFromIndexing = builder.excludedFromIndexing;
this.liveReloadBuildItem = builder.liveReloadState;
this.buildSystemProperties = builder.buildSystemProperties;
+ this.runtimeProperties = builder.runtimeProperties;
this.targetDir = builder.targetDir;
this.effectiveModel = builder.effectiveModel;
this.baseName = builder.baseName;
@@ -83,6 +87,7 @@ public class QuarkusAugmentor {
this.auxiliaryApplication = builder.auxiliaryApplication;
this.auxiliaryDevModeType = Optional.ofNullable(builder.auxiliaryDevModeType);
this.test = builder.test;
+ this.depInfoProvider = builder.depInfoProvider;
}
public BuildResult run() throws Exception {
@@ -99,13 +104,9 @@ public BuildResult run() throws Exception {
final BuildChainBuilder chainBuilder = BuildChain.builder();
chainBuilder.setClassLoader(deploymentClassLoader);
- //provideCapabilities(chainBuilder);
-
- //TODO: we load everything from the deployment class loader
- //this allows the deployment config (application.properties) to be loaded, but in theory could result
- //in additional stuff from the deployment leaking in, this is unlikely but has a bit of a smell.
ExtensionLoader.loadStepsFrom(deploymentClassLoader,
buildSystemProperties == null ? new Properties() : buildSystemProperties,
+ runtimeProperties == null ? new Properties() : runtimeProperties,
effectiveModel, launchMode, devModeType)
.accept(chainBuilder);
@@ -153,7 +154,7 @@ public BuildResult run() throws Exception {
auxiliaryDevModeType, test))
.produce(new BuildSystemTargetBuildItem(targetDir, baseName, originalBaseName, rebuild,
buildSystemProperties == null ? new Properties() : buildSystemProperties))
- .produce(new AppModelProviderBuildItem(effectiveModel));
+ .produce(new AppModelProviderBuildItem(effectiveModel, depInfoProvider));
for (PathCollection i : additionalApplicationArchives) {
execBuilder.produce(new AdditionalApplicationArchiveBuildItem(i));
}
@@ -181,9 +182,6 @@ public BuildResult run() throws Exception {
.releaseConfig(deploymentClassLoader);
} catch (Exception ignore) {
- }
- if (deploymentClassLoader instanceof Closeable) {
- ((Closeable) deploymentClassLoader).close();
}
Thread.currentThread().setContextClassLoader(originalClassLoader);
buildCloseables.close();
@@ -210,6 +208,7 @@ public static final class Builder {
LaunchMode launchMode = LaunchMode.NORMAL;
LiveReloadBuildItem liveReloadState = new LiveReloadBuildItem();
Properties buildSystemProperties;
+ Properties runtimeProperties;
ApplicationModel effectiveModel;
String baseName = QUARKUS_APPLICATION;
@@ -218,6 +217,7 @@ public static final class Builder {
DevModeType devModeType;
boolean test;
boolean auxiliaryApplication;
+ private Supplier depInfoProvider;
public Builder addBuildChainCustomizer(Consumer customizer) {
this.buildChainCustomizers.add(customizer);
@@ -321,6 +321,15 @@ public Builder setBuildSystemProperties(final Properties buildSystemProperties)
return this;
}
+ public Properties getRuntimeProperties() {
+ return runtimeProperties;
+ }
+
+ public Builder setRuntimeProperties(final Properties runtimeProperties) {
+ this.runtimeProperties = runtimeProperties;
+ return this;
+ }
+
public Builder setRebuild(boolean rebuild) {
this.rebuild = rebuild;
return this;
@@ -357,5 +366,10 @@ public Builder setDeploymentClassLoader(ClassLoader deploymentClassLoader) {
this.deploymentClassLoader = deploymentClassLoader;
return this;
}
+
+ public Builder setDependencyInfoProvider(Supplier depInfoProvider) {
+ this.depInfoProvider = depInfoProvider;
+ return this;
+ }
}
}
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/SecureRandomProcessor.java b/core/deployment/src/main/java/io/quarkus/deployment/SecureRandomProcessor.java
new file mode 100644
index 00000000000000..6ecec735827d8b
--- /dev/null
+++ b/core/deployment/src/main/java/io/quarkus/deployment/SecureRandomProcessor.java
@@ -0,0 +1,18 @@
+package io.quarkus.deployment;
+
+import io.quarkus.deployment.annotations.BuildProducer;
+import io.quarkus.deployment.annotations.BuildStep;
+import io.quarkus.deployment.builditem.nativeimage.ReflectiveMethodBuildItem;
+
+public class SecureRandomProcessor {
+
+ @BuildStep
+ void registerReflectiveMethods(BuildProducer reflectiveMethods) {
+ // Called reflectively through java.security.SecureRandom.SecureRandom()
+ reflectiveMethods.produce(new ReflectiveMethodBuildItem(
+ getClass().getName(),
+ "sun.security.provider.NativePRNG", "",
+ java.security.SecureRandomParameters.class));
+ }
+
+}
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/SnapStartConfig.java b/core/deployment/src/main/java/io/quarkus/deployment/SnapStartConfig.java
index 540e9973f63b41..bfe08594a15bc3 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/SnapStartConfig.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/SnapStartConfig.java
@@ -7,6 +7,8 @@
import io.quarkus.runtime.annotations.ConfigRoot;
/**
+ * SnapStart
+ *
* Configure the various optimization to use
* SnapStart
*/
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/SslProcessor.java b/core/deployment/src/main/java/io/quarkus/deployment/SslProcessor.java
index 4430394cbfda6a..627bcaadfeb29e 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/SslProcessor.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/SslProcessor.java
@@ -16,6 +16,9 @@ public class SslProcessor {
SslConfig ssl;
+ /**
+ * SSL
+ */
@ConfigRoot(phase = ConfigPhase.BUILD_TIME)
static class SslConfig {
/**
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/annotations/BuildProducer.java b/core/deployment/src/main/java/io/quarkus/deployment/annotations/BuildProducer.java
index 5f59db467b6a37..2bec80a3b38fde 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/annotations/BuildProducer.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/annotations/BuildProducer.java
@@ -1,5 +1,7 @@
package io.quarkus.deployment.annotations;
+import java.util.Collection;
+
import io.quarkus.builder.item.BuildItem;
/**
@@ -16,4 +18,7 @@ public interface BuildProducer {
void produce(T item);
+ default void produce(Collection items) {
+ items.forEach(this::produce);
+ }
}
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/builditem/AppModelProviderBuildItem.java b/core/deployment/src/main/java/io/quarkus/deployment/builditem/AppModelProviderBuildItem.java
index 19e8d697a8ef40..aff617365d12eb 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/builditem/AppModelProviderBuildItem.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/builditem/AppModelProviderBuildItem.java
@@ -1,7 +1,11 @@
package io.quarkus.deployment.builditem;
+import java.util.Objects;
+import java.util.function.Supplier;
+
import org.jboss.logging.Logger;
+import io.quarkus.bootstrap.app.DependencyInfoProvider;
import io.quarkus.bootstrap.model.ApplicationModel;
import io.quarkus.bootstrap.model.PlatformImports;
import io.quarkus.builder.item.SimpleBuildItem;
@@ -12,9 +16,15 @@ public final class AppModelProviderBuildItem extends SimpleBuildItem {
private static final Logger log = Logger.getLogger(AppModelProviderBuildItem.class);
private final ApplicationModel appModel;
+ private final Supplier depInfoProvider;
public AppModelProviderBuildItem(ApplicationModel appModel) {
- this.appModel = appModel;
+ this(appModel, null);
+ }
+
+ public AppModelProviderBuildItem(ApplicationModel appModel, Supplier depInfoProvider) {
+ this.appModel = Objects.requireNonNull(appModel);
+ this.depInfoProvider = depInfoProvider;
}
public ApplicationModel validateAndGet(BootstrapConfig config) {
@@ -34,4 +44,8 @@ public ApplicationModel validateAndGet(BootstrapConfig config) {
}
return appModel;
}
+
+ public Supplier getDependencyInfoProvider() {
+ return depInfoProvider;
+ }
}
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/builditem/ApplicationArchivesBuildItem.java b/core/deployment/src/main/java/io/quarkus/deployment/builditem/ApplicationArchivesBuildItem.java
index 154b6b1def97f8..2429ab00e0bca3 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/builditem/ApplicationArchivesBuildItem.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/builditem/ApplicationArchivesBuildItem.java
@@ -15,11 +15,16 @@ public final class ApplicationArchivesBuildItem extends SimpleBuildItem {
private final ApplicationArchive root;
private final Collection applicationArchives;
- private Set allArchives;
+ private final Set allArchives;
public ApplicationArchivesBuildItem(ApplicationArchive root, Collection applicationArchives) {
this.root = root;
this.applicationArchives = applicationArchives;
+
+ HashSet ret = new HashSet<>(applicationArchives);
+ ret.add(root);
+
+ this.allArchives = Collections.unmodifiableSet(ret);
}
/**
@@ -43,11 +48,6 @@ public Collection getApplicationArchives() {
* @return A set of all application archives, including the root archive
*/
public Set getAllApplicationArchives() {
- if (allArchives == null) {
- HashSet ret = new HashSet<>(applicationArchives);
- ret.add(root);
- allArchives = Collections.unmodifiableSet(ret);
- }
return allArchives;
}
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/builditem/BytecodeTransformerBuildItem.java b/core/deployment/src/main/java/io/quarkus/deployment/builditem/BytecodeTransformerBuildItem.java
index ec968f494b8b09..ea79ca227b8bf7 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/builditem/BytecodeTransformerBuildItem.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/builditem/BytecodeTransformerBuildItem.java
@@ -8,6 +8,15 @@
import io.quarkus.builder.item.MultiBuildItem;
+/**
+ * Transform a class using ASM {@link ClassVisitor}. Note that the transformation is performed after assembling the
+ * index and thus the changes won't be visible to any processor steps relying on the index.
+ *
+ * You may consider using {@code io.quarkus.arc.deployment.AnnotationsTransformerBuildItem} if your transformation
+ * should be visible for Arc. See also
+ * I Need To
+ * Transform Annotation Metadata section of Quarkus CDI integration guide.
+ */
public final class BytecodeTransformerBuildItem extends MultiBuildItem {
final String classToTransform;
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/builditem/DevServicesResultBuildItem.java b/core/deployment/src/main/java/io/quarkus/deployment/builditem/DevServicesResultBuildItem.java
index 7645cc96b49da3..5c59ad4e2ca26c 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/builditem/DevServicesResultBuildItem.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/builditem/DevServicesResultBuildItem.java
@@ -20,11 +20,17 @@
public final class DevServicesResultBuildItem extends MultiBuildItem {
private final String name;
+ private final String description;
private final String containerId;
private final Map config;
public DevServicesResultBuildItem(String name, String containerId, Map config) {
+ this(name, null, containerId, config);
+ }
+
+ public DevServicesResultBuildItem(String name, String description, String containerId, Map config) {
this.name = name;
+ this.description = description;
this.containerId = containerId;
this.config = config;
}
@@ -33,6 +39,10 @@ public String getName() {
return name;
}
+ public String getDescription() {
+ return description;
+ }
+
public String getContainerId() {
return containerId;
}
@@ -44,6 +54,7 @@ public Map getConfig() {
public static class RunningDevService implements Closeable {
private final String name;
+ private final String description;
private final String containerId;
private final Map config;
private final Closeable closeable;
@@ -54,12 +65,25 @@ private static Map mapOf(String key, String value) {
return map;
}
- public RunningDevService(String name, String containerId, Closeable closeable, String key, String value) {
- this(name, containerId, closeable, mapOf(key, value));
+ public RunningDevService(String name, String containerId, Closeable closeable, String key,
+ String value) {
+ this(name, null, containerId, closeable, mapOf(key, value));
+ }
+
+ public RunningDevService(String name, String description, String containerId, Closeable closeable, String key,
+ String value) {
+ this(name, description, containerId, closeable, mapOf(key, value));
+ }
+
+ public RunningDevService(String name, String containerId, Closeable closeable,
+ Map config) {
+ this(name, null, containerId, closeable, config);
}
- public RunningDevService(String name, String containerId, Closeable closeable, Map config) {
+ public RunningDevService(String name, String description, String containerId, Closeable closeable,
+ Map config) {
this.name = name;
+ this.description = description;
this.containerId = containerId;
this.closeable = closeable;
this.config = Collections.unmodifiableMap(config);
@@ -69,6 +93,10 @@ public String getName() {
return name;
}
+ public String getDescription() {
+ return description;
+ }
+
public String getContainerId() {
return containerId;
}
@@ -93,7 +121,7 @@ public void close() throws IOException {
}
public DevServicesResultBuildItem toBuildItem() {
- return new DevServicesResultBuildItem(name, containerId, config);
+ return new DevServicesResultBuildItem(name, description, containerId, config);
}
}
}
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/builditem/GeneratedResourceBuildItem.java b/core/deployment/src/main/java/io/quarkus/deployment/builditem/GeneratedResourceBuildItem.java
index 8cdfd9bd8526bd..75721b1f08ea71 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/builditem/GeneratedResourceBuildItem.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/builditem/GeneratedResourceBuildItem.java
@@ -6,9 +6,17 @@ public final class GeneratedResourceBuildItem extends MultiBuildItem {
final String name;
final byte[] data;
- // This option is only meant to be set by extensions that also generated the resource on the file system
- // and must rely on Quarkus not getting in the way of loading that resource.
- // It is currently used by Kogito to get serving of static resources in Dev Mode by Vert.x
+ /**
+ * This option is only meant to be set by extensions that also generated the resource on the file system
+ * and must rely on Quarkus not getting in the way of loading that resource.
+ * It is currently used by Kogito to get serving of static resources in Dev Mode by Vert.x
+ *
+ *
+ * @deprecated If you want to serve static resources use
+ * {@link io.quarkus.vertx.http.deployment.spi.GeneratedStaticResourceBuildItem}
+ * instead.
+ */
+ @Deprecated
final boolean excludeFromDevCL;
public GeneratedResourceBuildItem(String name, byte[] data) {
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/NativeImageAgentConfigDirectoryBuildItem.java b/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/NativeImageAgentConfigDirectoryBuildItem.java
new file mode 100644
index 00000000000000..c85bd992bccb8a
--- /dev/null
+++ b/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/NativeImageAgentConfigDirectoryBuildItem.java
@@ -0,0 +1,25 @@
+package io.quarkus.deployment.builditem.nativeimage;
+
+import io.quarkus.builder.item.SimpleBuildItem;
+import io.quarkus.deployment.pkg.NativeConfig;
+
+/**
+ * Native configuration generated by native image agent can be integrated
+ * directly into subsequence native build steps,
+ * if the user enables {@link NativeConfig#agentConfigurationApply()}.
+ * This build item is used to transfer the native configuration folder path
+ * onto the {@link io.quarkus.deployment.pkg.steps.NativeImageBuildStep}.
+ * If the build item is passed,
+ * the directory is added to the native image build execution.
+ */
+public final class NativeImageAgentConfigDirectoryBuildItem extends SimpleBuildItem {
+ private final String directory;
+
+ public NativeImageAgentConfigDirectoryBuildItem(String directory) {
+ this.directory = directory;
+ }
+
+ public String getDirectory() {
+ return directory;
+ }
+}
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/NativeImageResourceBuildItem.java b/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/NativeImageResourceBuildItem.java
index f58313c940ae5f..5e491ed3da0e3b 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/NativeImageResourceBuildItem.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/NativeImageResourceBuildItem.java
@@ -2,15 +2,21 @@
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.List;
import io.quarkus.builder.item.MultiBuildItem;
+import io.quarkus.deployment.util.ArtifactResourceResolver;
+import io.quarkus.maven.dependency.ArtifactCoords;
+import io.quarkus.maven.dependency.ResolvedDependency;
+import io.quarkus.paths.PathFilter;
+import io.quarkus.util.GlobUtil;
/**
* A build item that indicates that a static resource should be included in the native image.
*
* A static resource is a file that is not processed by the build steps, but is included in the native image as-is.
- * The resource path passed to the constructor is a {@code /}-separated path name (with the same semantics as the parameters
+ * The resource path passed to the constructor is a {@code /}-separated path name (with the same semantics as the parameters)
* passed to {@link java.lang.ClassLoader#getResources(String)}.
*
* Related build items:
@@ -23,6 +29,23 @@ public final class NativeImageResourceBuildItem extends MultiBuildItem {
private final List resources;
+ /**
+ * Builds a {@code NativeImageResourceBuildItem} for the given artifact and path
+ *
+ * @param dependencies the resolved dependencies of the build
+ * @param artifactCoordinates the coordinates of the artifact containing the resources
+ * @param resourceFilter the filter for the resources in glob syntax (see {@link GlobUtil})
+ * @return
+ */
+ public static NativeImageResourceBuildItem ofDependencyResources(
+ Collection dependencies,
+ ArtifactCoords artifactCoordinates,
+ PathFilter resourceFilter) {
+
+ var resolver = ArtifactResourceResolver.of(dependencies, artifactCoordinates);
+ return new NativeImageResourceBuildItem(resolver.resourceList(resourceFilter));
+ }
+
public NativeImageResourceBuildItem(String... resources) {
this.resources = Arrays.asList(resources);
}
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/ReflectiveClassBuildItem.java b/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/ReflectiveClassBuildItem.java
index d71a00b8e0eabe..ca4b0e37c7fdf0 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/ReflectiveClassBuildItem.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/ReflectiveClassBuildItem.java
@@ -2,24 +2,29 @@
import static java.util.Arrays.stream;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import io.quarkus.builder.item.MultiBuildItem;
+import io.quarkus.logging.Log;
/**
* Used to register a class for reflection in native mode
*/
public final class ReflectiveClassBuildItem extends MultiBuildItem {
+ // The names of the classes that should be registered for reflection
private final List className;
private final boolean methods;
+ private final boolean queryMethods;
private final boolean fields;
+ private final boolean classes;
private final boolean constructors;
+ private final boolean queryConstructors;
private final boolean weak;
private final boolean serialization;
private final boolean unsafeAllocated;
+ private final String reason;
public static Builder builder(Class>... classes) {
String[] classNames = stream(classes)
@@ -38,25 +43,11 @@ public static Builder builder(String... classNames) {
return new Builder().className(classNames);
}
- private ReflectiveClassBuildItem(boolean constructors, boolean methods, boolean fields, boolean weak, boolean serialization,
- boolean unsafeAllocated, Class>... classes) {
- List names = new ArrayList<>();
- for (Class> i : classes) {
- if (i == null) {
- throw new NullPointerException();
- }
- names.add(i.getName());
- }
- this.className = names;
- this.methods = methods;
- this.fields = fields;
- this.constructors = constructors;
- this.weak = weak;
- this.serialization = serialization;
- this.unsafeAllocated = unsafeAllocated;
- if (weak && serialization) {
- throw new RuntimeException("Weak reflection not supported with serialization");
- }
+ private ReflectiveClassBuildItem(boolean constructors, boolean queryConstructors, boolean methods, boolean queryMethods,
+ boolean fields, boolean getClasses, boolean weak, boolean serialization, boolean unsafeAllocated, String reason,
+ Class>... classes) {
+ this(constructors, queryConstructors, methods, queryMethods, fields, getClasses, weak, serialization,
+ unsafeAllocated, reason, stream(classes).map(Class::getName).toArray(String[]::new));
}
/**
@@ -74,7 +65,7 @@ public ReflectiveClassBuildItem(boolean methods, boolean fields, Class>... cla
*/
@Deprecated(since = "3.0", forRemoval = true)
public ReflectiveClassBuildItem(boolean constructors, boolean methods, boolean fields, Class>... classes) {
- this(constructors, methods, fields, false, false, false, classes);
+ this(constructors, false, methods, false, fields, false, false, false, false, null, classes);
}
/**
@@ -92,7 +83,7 @@ public ReflectiveClassBuildItem(boolean methods, boolean fields, String... class
*/
@Deprecated(since = "3.0", forRemoval = true)
public ReflectiveClassBuildItem(boolean constructors, boolean methods, boolean fields, String... classNames) {
- this(constructors, methods, fields, false, false, false, classNames);
+ this(constructors, false, methods, false, fields, false, false, false, classNames);
}
/**
@@ -102,7 +93,7 @@ public ReflectiveClassBuildItem(boolean constructors, boolean methods, boolean f
@Deprecated(since = "3.0", forRemoval = true)
public ReflectiveClassBuildItem(boolean constructors, boolean methods, boolean fields, boolean serialization,
String... classNames) {
- this(constructors, methods, fields, false, serialization, false, classNames);
+ this(constructors, false, methods, false, fields, false, serialization, false, classNames);
}
public static ReflectiveClassBuildItem weakClass(String... classNames) {
@@ -123,8 +114,17 @@ public static ReflectiveClassBuildItem serializationClass(String... classNames)
return ReflectiveClassBuildItem.builder(classNames).serialization().build();
}
- ReflectiveClassBuildItem(boolean constructors, boolean methods, boolean fields, boolean weak, boolean serialization,
+ @Deprecated(since = "3.14", forRemoval = true)
+ ReflectiveClassBuildItem(boolean constructors, boolean queryConstructors, boolean methods, boolean queryMethods,
+ boolean fields, boolean weak, boolean serialization,
boolean unsafeAllocated, String... className) {
+ this(constructors, queryConstructors, methods, queryMethods, fields, false, weak, serialization, unsafeAllocated,
+ null, className);
+ }
+
+ ReflectiveClassBuildItem(boolean constructors, boolean queryConstructors, boolean methods, boolean queryMethods,
+ boolean fields, boolean classes, boolean weak, boolean serialization,
+ boolean unsafeAllocated, String reason, String... className) {
for (String i : className) {
if (i == null) {
throw new NullPointerException();
@@ -132,11 +132,29 @@ public static ReflectiveClassBuildItem serializationClass(String... classNames)
}
this.className = Arrays.asList(className);
this.methods = methods;
+ if (methods && queryMethods) {
+ Log.warnf(
+ "Both methods and queryMethods are set to true for classes: %s. queryMethods is redundant and will be ignored",
+ String.join(", ", className));
+ this.queryMethods = false;
+ } else {
+ this.queryMethods = queryMethods;
+ }
this.fields = fields;
+ this.classes = classes;
this.constructors = constructors;
+ if (constructors && queryConstructors) {
+ Log.warnf(
+ "Both constructors and queryConstructors are set to true for classes: %s. queryConstructors is redundant and will be ignored",
+ String.join(", ", className));
+ this.queryConstructors = false;
+ } else {
+ this.queryConstructors = queryConstructors;
+ }
this.weak = weak;
this.serialization = serialization;
this.unsafeAllocated = unsafeAllocated;
+ this.reason = reason;
}
public List getClassNames() {
@@ -147,14 +165,26 @@ public boolean isMethods() {
return methods;
}
+ public boolean isQueryMethods() {
+ return queryMethods;
+ }
+
public boolean isFields() {
return fields;
}
+ public boolean isClasses() {
+ return classes;
+ }
+
public boolean isConstructors() {
return constructors;
}
+ public boolean isQueryConstructors() {
+ return queryConstructors;
+ }
+
/**
* @deprecated As of GraalVM 21.2 finalFieldsWritable is no longer needed when registering fields for reflection. This will
* be removed in a future verion of Quarkus.
@@ -176,14 +206,22 @@ public boolean isUnsafeAllocated() {
return unsafeAllocated;
}
+ public String getReason() {
+ return reason;
+ }
+
public static class Builder {
private String[] className;
private boolean constructors = true;
+ private boolean queryConstructors;
private boolean methods;
+ private boolean queryMethods;
private boolean fields;
+ private boolean classes;
private boolean weak;
private boolean serialization;
private boolean unsafeAllocated;
+ private String reason;
private Builder() {
}
@@ -193,6 +231,10 @@ public Builder className(String[] className) {
return this;
}
+ /**
+ * Configures whether constructors should be registered for reflection (true by default).
+ * Setting this enables getting all declared constructors for the class as well as invoking them reflectively.
+ */
public Builder constructors(boolean constructors) {
this.constructors = constructors;
return this;
@@ -202,6 +244,23 @@ public Builder constructors() {
return constructors(true);
}
+ /**
+ * Configures whether constructors should be registered for reflection, for query purposes only.
+ * Setting this enables getting all declared constructors for the class but does not allow invoking them reflectively.
+ */
+ public Builder queryConstructors(boolean queryConstructors) {
+ this.queryConstructors = queryConstructors;
+ return this;
+ }
+
+ public Builder queryConstructors() {
+ return queryConstructors(true);
+ }
+
+ /**
+ * Configures whether methods should be registered for reflection.
+ * Setting this enables getting all declared methods for the class as well as invoking them reflectively.
+ */
public Builder methods(boolean methods) {
this.methods = methods;
return this;
@@ -211,6 +270,24 @@ public Builder methods() {
return methods(true);
}
+ /**
+ * Configures whether declared methods should be registered for reflection, for query purposes only,
+ * i.e. {@link Class#getDeclaredMethods()}. Setting this enables getting all declared methods for the class but
+ * does not allow invoking them reflectively.
+ */
+ public Builder queryMethods(boolean queryMethods) {
+ this.queryMethods = queryMethods;
+ return this;
+ }
+
+ public Builder queryMethods() {
+ return queryMethods(true);
+ }
+
+ /**
+ * Configures whether fields should be registered for reflection.
+ * Setting this enables getting all declared fields for the class as well as accessing them reflectively.
+ */
public Builder fields(boolean fields) {
this.fields = fields;
return this;
@@ -220,6 +297,19 @@ public Builder fields() {
return fields(true);
}
+ /**
+ * Configures whether declared classes should be registered for reflection.
+ * Setting this enables getting all declared classes through Class.getClasses().
+ */
+ public Builder classes(boolean classes) {
+ this.classes = classes;
+ return this;
+ }
+
+ public Builder classes() {
+ return fields(true);
+ }
+
/**
* @deprecated As of GraalVM 21.2 finalFieldsWritable is no longer needed when registering fields for reflection. This
* will be removed in a future version of Quarkus.
@@ -238,6 +328,9 @@ public Builder weak() {
return weak(true);
}
+ /**
+ * Configures whether serialization support should be enabled for the class.
+ */
public Builder serialization(boolean serialization) {
this.serialization = serialization;
return this;
@@ -247,17 +340,26 @@ public Builder serialization() {
return serialization(true);
}
+ /**
+ * Configures whether the class can be allocated in an unsafe manner (through JNI).
+ */
public Builder unsafeAllocated(boolean unsafeAllocated) {
this.unsafeAllocated = unsafeAllocated;
return this;
}
+ public Builder reason(String reason) {
+ this.reason = reason;
+ return this;
+ }
+
public Builder unsafeAllocated() {
return unsafeAllocated(true);
}
public ReflectiveClassBuildItem build() {
- return new ReflectiveClassBuildItem(constructors, methods, fields, weak, serialization, unsafeAllocated, className);
+ return new ReflectiveClassBuildItem(constructors, queryConstructors, methods, queryMethods, fields, classes, weak,
+ serialization, unsafeAllocated, reason, className);
}
}
}
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/ReflectiveFieldBuildItem.java b/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/ReflectiveFieldBuildItem.java
index 9738b2256b474f..ecfdfd7e491b31 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/ReflectiveFieldBuildItem.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/ReflectiveFieldBuildItem.java
@@ -10,15 +10,28 @@ public final class ReflectiveFieldBuildItem extends MultiBuildItem {
final String declaringClass;
final String name;
+ final String reason;
+
+ public ReflectiveFieldBuildItem(String reason, FieldInfo field) {
+ this(reason, field.declaringClass().name().toString(), field.name());
+ }
public ReflectiveFieldBuildItem(FieldInfo field) {
- this.name = field.name();
- this.declaringClass = field.declaringClass().name().toString();
+ this(null, field);
}
public ReflectiveFieldBuildItem(Field field) {
- this.name = field.getName();
- this.declaringClass = field.getDeclaringClass().getName();
+ this(null, field);
+ }
+
+ public ReflectiveFieldBuildItem(String reason, Field field) {
+ this(reason, field.getDeclaringClass().getName(), field.getName());
+ }
+
+ public ReflectiveFieldBuildItem(String reason, String declaringClass, String fieldName) {
+ this.reason = reason;
+ this.name = fieldName;
+ this.declaringClass = declaringClass;
}
public String getDeclaringClass() {
@@ -28,4 +41,8 @@ public String getDeclaringClass() {
public String getName() {
return name;
}
+
+ public String getReason() {
+ return reason;
+ }
}
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/ReflectiveHierarchyBuildItem.java b/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/ReflectiveHierarchyBuildItem.java
index bd13ee0931508e..54b7c35d01ffeb 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/ReflectiveHierarchyBuildItem.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/ReflectiveHierarchyBuildItem.java
@@ -192,7 +192,7 @@ public static Builder builder(DotName className) {
* @return a new {@link Builder} instance, initialized from the specified {@link Type}
*/
public static Builder builder(Type type) {
- return new Builder().type(type);
+ return new Builder(type);
}
public static class Builder {
@@ -205,6 +205,23 @@ public static class Builder {
private String source = UNKNOWN_SOURCE;
private boolean serialization;
+ /**
+ * @deprecated use {@link ReflectiveHierarchyBuildItem#builder(Type)},
+ * {@link ReflectiveHierarchyBuildItem#builder(String)} or
+ * {@link ReflectiveHierarchyBuildItem#builder(DotName)} instead
+ */
+ @Deprecated(since = "3.12", forRemoval = true)
+ public Builder() {
+ }
+
+ private Builder(Type type) {
+ this.type = type;
+ }
+
+ /**
+ * @deprecated use {@link ReflectiveHierarchyBuildItem#builder(Type)} instead
+ */
+ @Deprecated(since = "3.12", forRemoval = true)
public Builder type(Type type) {
this.type = type;
return this;
@@ -215,7 +232,9 @@ public Builder type(Type type) {
*
* @param className a {@link DotName} representing the name of the class of the Type to be registered for reflection
* @return this {@link Builder} instance
+ * @deprecated use {@link ReflectiveHierarchyBuildItem#builder(DotName)} instead
*/
+ @Deprecated(since = "3.12", forRemoval = true)
public Builder className(DotName className) {
return type(Type.create(className, Type.Kind.CLASS));
}
@@ -225,7 +244,9 @@ public Builder className(DotName className) {
*
* @param className the name of the class of the Type to be registered for reflection
* @return this {@link Builder} instance
+ * @deprecated use {@link ReflectiveHierarchyBuildItem#builder(String)} instead
*/
+ @Deprecated(since = "3.12", forRemoval = true)
public Builder className(String className) {
return className(DotName.createSimple(className));
}
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/ReflectiveMethodBuildItem.java b/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/ReflectiveMethodBuildItem.java
index 2a1f7515548db7..48692063f53441 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/ReflectiveMethodBuildItem.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/ReflectiveMethodBuildItem.java
@@ -13,44 +13,76 @@ public final class ReflectiveMethodBuildItem extends MultiBuildItem {
final String declaringClass;
final String name;
final String[] params;
+ final boolean queryOnly;
+ final String reason;
public ReflectiveMethodBuildItem(MethodInfo methodInfo) {
- String[] params = new String[methodInfo.parametersCount()];
- for (int i = 0; i < params.length; ++i) {
- params[i] = methodInfo.parameterType(i).name().toString();
- }
- this.name = methodInfo.name();
- this.params = params;
- this.declaringClass = methodInfo.declaringClass().name().toString();
+ this(null, false, methodInfo);
+ }
+
+ public ReflectiveMethodBuildItem(String reason, MethodInfo methodInfo) {
+ this(reason, false, methodInfo);
+ }
+
+ public ReflectiveMethodBuildItem(boolean queryOnly, MethodInfo methodInfo) {
+ this(null, queryOnly, methodInfo);
+ }
+
+ public ReflectiveMethodBuildItem(String reason, boolean queryOnly, MethodInfo methodInfo) {
+ this(reason, queryOnly, methodInfo.declaringClass().name().toString(), methodInfo.name(),
+ methodInfo.parameterTypes().stream().map(p -> p.name().toString()).toArray(String[]::new));
}
public ReflectiveMethodBuildItem(Method method) {
- this.params = new String[method.getParameterCount()];
- if (method.getParameterCount() > 0) {
- Class>[] parameterTypes = method.getParameterTypes();
- for (int i = 0; i < params.length; ++i) {
- params[i] = parameterTypes[i].getName();
- }
- }
- this.name = method.getName();
- this.declaringClass = method.getDeclaringClass().getName();
+ this(false, method);
+ }
+
+ public ReflectiveMethodBuildItem(boolean queryOnly, Method method) {
+ this(null, queryOnly, method);
+ }
+
+ public ReflectiveMethodBuildItem(String reason, boolean queryOnly, Method method) {
+ this(reason, queryOnly, method.getDeclaringClass().getName(), method.getName(),
+ Arrays.stream(method.getParameterTypes()).map(Class::getName).toArray(String[]::new));
}
public ReflectiveMethodBuildItem(String declaringClass, String name,
String... params) {
+ this(null, false, declaringClass, name, params);
+ }
+
+ public ReflectiveMethodBuildItem(String reason, String declaringClass, String name,
+ String... params) {
+ this(reason, false, declaringClass, name, params);
+ }
+
+ public ReflectiveMethodBuildItem(boolean queryOnly, String declaringClass, String name,
+ String... params) {
+ this(null, queryOnly, declaringClass, name, params);
+ }
+
+ public ReflectiveMethodBuildItem(String reason, boolean queryOnly, String declaringClass, String name,
+ String... params) {
this.declaringClass = declaringClass;
this.name = name;
this.params = params;
+ this.queryOnly = queryOnly;
+ this.reason = reason;
+ }
+
+ public ReflectiveMethodBuildItem(String reason, String declaringClass, String name,
+ Class>... params) {
+ this(reason, false, declaringClass, name, Arrays.stream(params).map(Class::getName).toArray(String[]::new));
}
public ReflectiveMethodBuildItem(String declaringClass, String name,
Class>... params) {
- this.declaringClass = declaringClass;
- this.name = name;
- this.params = new String[params.length];
- for (int i = 0; i < params.length; ++i) {
- this.params[i] = params[i].getName();
- }
+ this(false, declaringClass, name, params);
+ }
+
+ public ReflectiveMethodBuildItem(boolean queryOnly, String declaringClass, String name,
+ Class>... params) {
+ this(null, queryOnly, declaringClass, name, Arrays.stream(params).map(Class::getName).toArray(String[]::new));
}
public String getName() {
@@ -65,6 +97,14 @@ public String getDeclaringClass() {
return declaringClass;
}
+ public boolean isQueryOnly() {
+ return queryOnly;
+ }
+
+ public String getReason() {
+ return reason;
+ }
+
@Override
public boolean equals(Object o) {
if (this == o)
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/ServiceProviderBuildItem.java b/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/ServiceProviderBuildItem.java
index 28854dcb5bfc11..590adea75ab3f0 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/ServiceProviderBuildItem.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/ServiceProviderBuildItem.java
@@ -11,7 +11,11 @@
import java.util.Set;
import io.quarkus.builder.item.MultiBuildItem;
+import io.quarkus.deployment.util.ArtifactResourceResolver;
import io.quarkus.deployment.util.ServiceUtil;
+import io.quarkus.maven.dependency.ArtifactCoords;
+import io.quarkus.maven.dependency.ResolvedDependency;
+import io.quarkus.paths.PathFilter;
/**
* Represents a Service Provider registration.
@@ -21,6 +25,8 @@
public final class ServiceProviderBuildItem extends MultiBuildItem {
public static final String SPI_ROOT = "META-INF/services/";
+ private static final PathFilter SPI_FILTER = PathFilter.forIncludes(List.of(SPI_ROOT + "*"));
+
private final String serviceInterface;
private final List providers;
@@ -52,7 +58,7 @@ public static ServiceProviderBuildItem allProviders(final String serviceInterfac
line = line.substring(0, commentIndex);
}
line = line.trim();
- if (line.length() != 0) {
+ if (!line.isEmpty()) {
classNames.add(line);
}
}
@@ -87,6 +93,48 @@ public static ServiceProviderBuildItem allProvidersFromClassPath(final String se
}
}
+ /**
+ * Creates a new {@link Collection} of {@code ServiceProviderBuildItem}s for the selected artifact.
+ * It includes all the providers, that are contained in all the service interface descriptor files defined in
+ * {@code "META-INF/services/"} in the selected artifact.
+ *
+ * @param dependencies the resolved dependencies of the build
+ * @param artifactCoordinates the coordinates of the artifact containing the service definitions
+ * @return a {@link Collection} of {@code ServiceProviderBuildItem}s containing all the found service providers
+ */
+ public static Collection allProvidersOfDependency(
+ Collection dependencies,
+ ArtifactCoords artifactCoordinates) {
+
+ return allProvidersOfDependencies(dependencies, List.of(artifactCoordinates));
+ }
+
+ /**
+ * Creates a new {@link Collection} of {@code ServiceProviderBuildItem}s for the selected artifacts.
+ * It includes all the providers, that are contained in all the service interface descriptor files defined in
+ * {@code "META-INF/services/"} in all the selected artifacts.
+ *
+ * @param dependencies the resolved dependencies of the build
+ * @param artifactCoordinatesCollection a {@link Collection} of coordinates of the artifacts containing the service
+ * definitions
+ * @return a {@link Collection} of {@code ServiceProviderBuildItem}s containing all the found service providers
+ */
+ public static Collection allProvidersOfDependencies(
+ Collection dependencies,
+ Collection artifactCoordinatesCollection) {
+
+ var resolver = ArtifactResourceResolver.of(dependencies, artifactCoordinatesCollection);
+ return resolver.resourcePathList(SPI_FILTER).stream()
+ .map(ServiceProviderBuildItem::ofSpiPath)
+ .toList();
+ }
+
+ private static ServiceProviderBuildItem ofSpiPath(Path spiPath) {
+ return new ServiceProviderBuildItem(
+ spiPath.getFileName().toString(),
+ ServiceUtil.classNamesNamedIn(spiPath.toString()));
+ }
+
/**
* Registers the specified service interface descriptor to be embedded and allow reflection (instantiation only)
* of the specified provider classes. Note that the service interface descriptor file has to exist and match the
@@ -136,12 +184,12 @@ private ServiceProviderBuildItem(String serviceInterfaceClassName, List
this.providers = providers;
// Validation
- if (serviceInterface.length() == 0) {
+ if (serviceInterface.isEmpty()) {
throw new IllegalArgumentException("The serviceDescriptorFile interface cannot be blank");
}
providers.forEach(s -> {
- if (s == null || s.length() == 0) {
+ if (s == null || s.isEmpty()) {
throw new IllegalArgumentException("The provider class name cannot be null or blank");
}
});
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/cmd/DeployConfig.java b/core/deployment/src/main/java/io/quarkus/deployment/cmd/DeployConfig.java
index 5fcf7264f97e2d..aeb85e44b89d6e 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/cmd/DeployConfig.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/cmd/DeployConfig.java
@@ -6,6 +6,9 @@
import io.quarkus.runtime.annotations.ConfigPhase;
import io.quarkus.runtime.annotations.ConfigRoot;
+/**
+ * Deployment
+ */
@ConfigRoot(phase = ConfigPhase.BUILD_TIME)
public class DeployConfig {
/**
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/configuration/BuildTimeConfigurationReader.java b/core/deployment/src/main/java/io/quarkus/deployment/configuration/BuildTimeConfigurationReader.java
index 36458eba693084..e493211f6336e1 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/configuration/BuildTimeConfigurationReader.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/configuration/BuildTimeConfigurationReader.java
@@ -6,13 +6,11 @@
import static io.quarkus.deployment.util.ReflectUtil.toError;
import static io.quarkus.deployment.util.ReflectUtil.typeOfParameter;
import static io.quarkus.deployment.util.ReflectUtil.unwrapInvocationTargetException;
-import static io.quarkus.runtime.configuration.PropertiesUtil.filterPropertiesInRoots;
+import static io.quarkus.runtime.configuration.PropertiesUtil.isPropertyInRoots;
import static io.smallrye.config.ConfigMappings.ConfigClassWithPrefix.configClassWithPrefix;
import static io.smallrye.config.Expressions.withoutExpansion;
-import static io.smallrye.config.PropertiesConfigSourceProvider.classPathSources;
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.util.stream.Collectors.toSet;
import java.io.IOException;
@@ -79,9 +77,8 @@
import io.smallrye.config.ConfigMappings.ConfigClassWithPrefix;
import io.smallrye.config.ConfigValue;
import io.smallrye.config.Converters;
+import io.smallrye.config.DefaultValuesConfigSource;
import io.smallrye.config.EnvConfigSource;
-import io.smallrye.config.KeyMap;
-import io.smallrye.config.KeyMapBackedConfigSource;
import io.smallrye.config.ProfileConfigSourceInterceptor;
import io.smallrye.config.PropertiesConfigSource;
import io.smallrye.config.SecretKeys;
@@ -89,7 +86,6 @@
import io.smallrye.config.SmallRyeConfigBuilder;
import io.smallrye.config.SysPropConfigSource;
import io.smallrye.config.common.AbstractConfigSource;
-import io.smallrye.config.common.MapBackedConfigSource;
/**
* A configuration reader.
@@ -384,29 +380,25 @@ public List getBuildTimeVisibleMappings() {
* @param platformProperties Quarkus platform properties to add as a configuration source
* @return configuration instance
*/
- public SmallRyeConfig initConfiguration(LaunchMode launchMode, Properties buildSystemProps,
+ public SmallRyeConfig initConfiguration(LaunchMode launchMode, Properties buildSystemProps, Properties runtimeProperties,
Map platformProperties) {
// now prepare & load the build configuration
- final SmallRyeConfigBuilder builder = ConfigUtils.configBuilder(false, launchMode);
+ SmallRyeConfigBuilder builder = ConfigUtils.configBuilder(false, launchMode);
if (classLoader != null) {
builder.forClassLoader(classLoader);
}
- final DefaultValuesConfigurationSource ds1 = new DefaultValuesConfigurationSource(getBuildTimePatternMap());
- final DefaultValuesConfigurationSource ds2 = new DefaultValuesConfigurationSource(getBuildTimeRunTimePatternMap());
- final PropertiesConfigSource pcs = new PropertiesConfigSource(buildSystemProps, "Build system");
- if (platformProperties.isEmpty()) {
- builder.withSources(ds1, ds2, pcs);
- } else {
- final KeyMap props = new KeyMap<>(platformProperties.size());
- for (Map.Entry prop : platformProperties.entrySet()) {
- props.findOrAdd(new io.smallrye.config.NameIterator(prop.getKey())).putRootValue(prop.getValue());
- }
- final KeyMapBackedConfigSource platformConfigSource = new KeyMapBackedConfigSource("Quarkus platform",
- // Our default value configuration source is using an ordinal of Integer.MIN_VALUE
- // (see io.quarkus.deployment.configuration.DefaultValuesConfigurationSource)
- Integer.MIN_VALUE + 1000, props);
- builder.withSources(ds1, ds2, platformConfigSource, pcs);
+ builder
+ .withSources(new DefaultValuesConfigurationSource(getBuildTimePatternMap()))
+ .withSources(new DefaultValuesConfigurationSource(getBuildTimeRunTimePatternMap()))
+ .withSources(new PropertiesConfigSource(buildSystemProps, "Build system"))
+ .withSources(new PropertiesConfigSource(runtimeProperties, "Runtime Properties"));
+
+ if (!platformProperties.isEmpty()) {
+ // Our default value configuration source is using an ordinal of Integer.MIN_VALUE
+ // (see io.quarkus.deployment.configuration.DefaultValuesConfigurationSource)
+ builder.withSources(
+ new DefaultValuesConfigSource(platformProperties, "Quarkus platform", Integer.MIN_VALUE + 1000));
}
for (ConfigClassWithPrefix mapping : getBuildTimeVisibleMappings()) {
@@ -537,7 +529,7 @@ ReadResult run() {
}
NameIterator ni = new NameIterator(propertyName);
- if (ni.hasNext() && PropertiesUtil.isPropertyInRoot(registeredRoots, ni)) {
+ if (ni.hasNext() && PropertiesUtil.isPropertyInRoots(propertyName, registeredRoots)) {
// build time patterns
Container matched = buildTimePatternMap.match(ni);
boolean knownProperty = matched != null;
@@ -616,13 +608,7 @@ ReadResult run() {
// it's not managed by us; record it
ConfigValue configValue = withoutExpansion(() -> runtimeConfig.getConfigValue(propertyName));
if (configValue.getValue() != null) {
- String configName = configValue.getNameProfiled();
- // record the profile parent in the original form; if recorded in the active profile it may mess the profile ordering
- if (configName.equals("quarkus.config.profile.parent")) {
- runTimeValues.put(propertyName, configValue.getValue());
- } else {
- runTimeValues.put(configName, configValue.getValue());
- }
+ runTimeValues.put(propertyName, configValue.getValue());
}
// in the case the user defined compound keys in YAML (or similar config source, that quotes the name)
@@ -1058,7 +1044,7 @@ private Set getAllProperties(final Set registeredRoots) {
unprofiledProperty = property.substring(profileDot + 1);
}
}
- if (filterPropertiesInRoots(List.of(unprofiledProperty), registeredRoots).iterator().hasNext()) {
+ if (PropertiesUtil.isPropertyInRoots(unprofiledProperty, registeredRoots)) {
sourcesProperties.add(property);
}
}
@@ -1095,42 +1081,25 @@ public String getValue(final String propertyName) {
properties.add(property);
}
- // TODO - Add better API to set an empty Profile, or no Profile at all
// We also need an empty profile Config to record the properties that are not on the active profile
builder = ConfigUtils.emptyConfigBuilder();
+ // Do not use a profile, so we can record both profile properties and main properties of the active profile
+ builder.getProfiles().add("");
builder.getSources().clear();
builder.getSourceProviders().clear();
builder.setAddDefaultSources(false)
.withInterceptors(ConfigCompatibility.FrontEnd.nonLoggingInstance(), ConfigCompatibility.BackEnd.instance())
.addDiscoveredCustomizers()
- .withSources(sourceProperties)
- .withSources(new MapBackedConfigSource(
- "Reset Profile",
- Map.of("quarkus.profile", "",
- "quarkus.config.profile.parent", "",
- "quarkus.test.profile", "",
- SMALLRYE_CONFIG_PROFILE, "",
- SMALLRYE_CONFIG_PROFILE_PARENT, "",
- Config.PROFILE, ""),
- Integer.MAX_VALUE) {
- @Override
- public Set getPropertyNames() {
- return Collections.emptySet();
- }
- });
+ .withSources(sourceProperties);
List profiles = config.getProfiles();
for (String property : builder.build().getPropertyNames()) {
String activeProperty = ProfileConfigSourceInterceptor.activeName(property, profiles);
// keep the profile parent in the original form; if we use the active profile it may mess the profile ordering
- if (activeProperty.equals("quarkus.config.profile.parent")) {
- if (!activeProperty.equals(property)) {
- properties.remove(activeProperty);
- properties.add(property);
- continue;
- }
+ if (activeProperty.equals("quarkus.config.profile.parent") && !activeProperty.equals(property)) {
+ properties.remove(activeProperty);
}
- properties.add(activeProperty);
+ properties.add(property);
}
return properties;
@@ -1147,13 +1116,14 @@ public Set getPropertyNames() {
*/
private SmallRyeConfig getConfigForRuntimeRecording() {
SmallRyeConfigBuilder builder = ConfigUtils.emptyConfigBuilder();
+ // Do not use a profile, so we can record both profile properties and main properties of the active profile
+ builder.getProfiles().add("");
builder.getSources().clear();
builder.getSourceProviders().clear();
builder.setAddDefaultSources(false)
// Customizers may duplicate sources, but not much we can do about it, we need to run them
.addDiscoveredCustomizers()
- // Read microprofile-config.properties, because we disabled the default sources
- .withSources(classPathSources(META_INF_MICROPROFILE_CONFIG_PROPERTIES, classLoader));
+ .addPropertiesSources();
// TODO - Should we reset quarkus.config.location to not record from these sources?
for (ConfigSource configSource : config.getConfigSources()) {
@@ -1188,7 +1158,7 @@ public String getValue(final String propertyName) {
return config.getConfigValue(propertyName).getValue();
}
return null;
- };
+ }
});
return builder.build();
}
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/configuration/ClassLoadingConfig.java b/core/deployment/src/main/java/io/quarkus/deployment/configuration/ClassLoadingConfig.java
index 9f6c050e6bf055..3eb7b693f46ecb 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/configuration/ClassLoadingConfig.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/configuration/ClassLoadingConfig.java
@@ -11,6 +11,8 @@
import io.quarkus.runtime.annotations.ConfigRoot;
/**
+ * Class loading
+ *
* WARNING: This is not normal quarkus config, this is only read from application.properties.
*
* This is because it is needed before any of the config infrastructure is set up.
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/configuration/ConfigCompatibility.java b/core/deployment/src/main/java/io/quarkus/deployment/configuration/ConfigCompatibility.java
index 8710a0211c4cb8..07cf447e6c9180 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/configuration/ConfigCompatibility.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/configuration/ConfigCompatibility.java
@@ -61,12 +61,6 @@ public final class ConfigCompatibility {
ConfigCompatibility::quarkusPackageDecompilerEnabled),
entry(List.of("quarkus", "package", "decompiler", "jar-directory"),
ConfigCompatibility::quarkusPackageDecompilerJarDirectory),
- entry(List.of("quarkus", "package", "vineflower", "version"),
- ConfigCompatibility::quarkusPackageDecompilerVersion),
- entry(List.of("quarkus", "package", "vineflower", "enabled"),
- ConfigCompatibility::quarkusPackageDecompilerEnabled),
- entry(List.of("quarkus", "package", "vineflower", "jar-directory"),
- ConfigCompatibility::quarkusPackageDecompilerJarDirectory),
entry(List.of("quarkus", "package", "manifest", "attributes", "*"),
ConfigCompatibility::quarkusPackageManifestAttributes),
entry(List.of("quarkus", "package", "manifest", "sections", "*", "*"),
@@ -285,12 +279,12 @@ private static List quarkusPackageDecompilerVersion(ConfigSourceIntercep
private static List quarkusPackageDecompilerEnabled(ConfigSourceInterceptorContext ctxt, NameIterator ni) {
// simple mapping to a new name
- return List.of("quarkus.package.decompiler.enabled");
+ return List.of("quarkus.package.jar.decompiler.enabled");
}
private static List quarkusPackageDecompilerJarDirectory(ConfigSourceInterceptorContext ctxt, NameIterator ni) {
// simple mapping to a new name
- return List.of("quarkus.package.decompiler.jar-directory");
+ return List.of("quarkus.package.jar.decompiler.jar-directory");
}
private static List quarkusPackageManifestAttributes(ConfigSourceInterceptorContext ctxt, NameIterator ni) {
@@ -510,11 +504,7 @@ private static ConfigValue quarkusPackageJarManifestAddImplementationEntries(Con
private static ConfigValue quarkusPackageJarDecompilerEnabled(ConfigSourceInterceptorContext ctxt, NameIterator ni) {
ConfigValue oldVal = ctxt.restart("quarkus.package.decompiler.enabled");
if (oldVal == null) {
- oldVal = ctxt.restart("quarkus.package.vineflower.enabled");
- if (oldVal == null) {
- // on to the default value
- return ctxt.proceed(ni.getName());
- }
+ return ctxt.proceed(ni.getName());
}
// map old name to new name
return oldVal.withName(ni.getName());
@@ -523,11 +513,7 @@ private static ConfigValue quarkusPackageJarDecompilerEnabled(ConfigSourceInterc
private static ConfigValue quarkusPackageJarDecompilerJarDirectory(ConfigSourceInterceptorContext ctxt, NameIterator ni) {
ConfigValue oldVal = ctxt.restart("quarkus.package.decompiler.jar-directory");
if (oldVal == null) {
- oldVal = ctxt.restart("quarkus.package.vineflower.jar-directory");
- if (oldVal == null) {
- // on to the default value
- return ctxt.proceed(ni.getName());
- }
+ return ctxt.proceed(ni.getName());
}
// map old name to new name
return oldVal.withName(ni.getName());
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/configuration/ConfigMappingUtils.java b/core/deployment/src/main/java/io/quarkus/deployment/configuration/ConfigMappingUtils.java
index 293ef9e3b3dbc9..546572ed3ef283 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/configuration/ConfigMappingUtils.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/configuration/ConfigMappingUtils.java
@@ -119,10 +119,13 @@ private static void processConfigClass(
classBytes));
additionalConstrainedClasses.produce(AdditionalConstrainedClassBuildItem.of(mappingMetadata.getClassName(),
classBytes));
- reflectiveClasses.produce(ReflectiveClassBuildItem.builder(mappingMetadata.getClassName()).constructors().build());
- reflectiveMethods
- .produce(new ReflectiveMethodBuildItem(mappingMetadata.getClassName(), "getDefaults", new String[0]));
- reflectiveMethods.produce(new ReflectiveMethodBuildItem(mappingMetadata.getClassName(), "getNames", new String[0]));
+ reflectiveClasses.produce(ReflectiveClassBuildItem.builder(mappingMetadata.getClassName())
+ .reason(ConfigMappingUtils.class.getName())
+ .build());
+ reflectiveMethods.produce(new ReflectiveMethodBuildItem(ConfigMappingUtils.class.getName(),
+ mappingMetadata.getClassName(), "getDefaults", new String[0]));
+ reflectiveMethods.produce(new ReflectiveMethodBuildItem(ConfigMappingUtils.class.getName(),
+ mappingMetadata.getClassName(), "getNames", new String[0]));
configComponentInterfaces.add(mappingMetadata.getInterfaceType());
@@ -141,6 +144,8 @@ private static void processProperties(
ConfigMappingInterface mapping = ConfigMappingLoader.getConfigMapping(configClass);
for (Property property : mapping.getProperties()) {
Class> returnType = property.getMethod().getReturnType();
+ String reason = ConfigMappingUtils.class.getSimpleName() + " Required to process property "
+ + property.getPropertyName();
if (property.hasConvertWith()) {
Class extends Converter>> convertWith;
@@ -149,39 +154,44 @@ private static void processProperties(
} else {
convertWith = property.asPrimitive().getConvertWith();
}
- reflectiveClasses.produce(ReflectiveClassBuildItem.builder(convertWith).build());
+ reflectiveClasses.produce(ReflectiveClassBuildItem.builder(convertWith).reason(reason).build());
}
- registerImplicitConverter(property, reflectiveClasses);
+ registerImplicitConverter(property, reason, reflectiveClasses);
if (property.isMap()) {
MapProperty mapProperty = property.asMap();
if (mapProperty.hasKeyConvertWith()) {
- reflectiveClasses.produce(ReflectiveClassBuildItem.builder(mapProperty.getKeyConvertWith()).build());
+ reflectiveClasses
+ .produce(ReflectiveClassBuildItem.builder(mapProperty.getKeyConvertWith()).reason(reason).build());
} else {
- reflectiveClasses.produce(ReflectiveClassBuildItem.builder(mapProperty.getKeyRawType()).build());
+ reflectiveClasses
+ .produce(ReflectiveClassBuildItem.builder(mapProperty.getKeyRawType()).reason(reason).build());
}
- registerImplicitConverter(mapProperty.getValueProperty(), reflectiveClasses);
+ registerImplicitConverter(mapProperty.getValueProperty(), reason, reflectiveClasses);
}
}
}
private static void registerImplicitConverter(
Property property,
- BuildProducer reflectiveClasses) {
+ String reason, BuildProducer reflectiveClasses) {
if (property.isLeaf() && !property.isOptional()) {
LeafProperty leafProperty = property.asLeaf();
if (leafProperty.hasConvertWith()) {
- reflectiveClasses.produce(ReflectiveClassBuildItem.builder(leafProperty.getConvertWith()).build());
+ reflectiveClasses
+ .produce(ReflectiveClassBuildItem.builder(leafProperty.getConvertWith()).reason(reason).build());
} else {
- reflectiveClasses.produce(ReflectiveClassBuildItem.builder(leafProperty.getValueRawType()).methods().build());
+ reflectiveClasses
+ .produce(ReflectiveClassBuildItem.builder(leafProperty.getValueRawType()).reason(reason).methods()
+ .build());
}
} else if (property.isOptional()) {
- registerImplicitConverter(property.asOptional().getNestedProperty(), reflectiveClasses);
+ registerImplicitConverter(property.asOptional().getNestedProperty(), reason, reflectiveClasses);
} else if (property.isCollection()) {
- registerImplicitConverter(property.asCollection().getElement(), reflectiveClasses);
+ registerImplicitConverter(property.asCollection().getElement(), reason, reflectiveClasses);
}
}
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/configuration/tracker/ConfigTrackingConfig.java b/core/deployment/src/main/java/io/quarkus/deployment/configuration/tracker/ConfigTrackingConfig.java
index 6508e33023b89c..225b27d3db5876 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/configuration/tracker/ConfigTrackingConfig.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/configuration/tracker/ConfigTrackingConfig.java
@@ -13,6 +13,8 @@
import io.smallrye.config.WithDefault;
/**
+ * Configuration tracking and dumping
+ *
* Configuration options for application build time configuration usage tracking
* and dumping.
*/
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/configuration/tracker/ConfigTrackingInterceptor.java b/core/deployment/src/main/java/io/quarkus/deployment/configuration/tracker/ConfigTrackingInterceptor.java
index 3e5f92866492ad..0b341494da8b34 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/configuration/tracker/ConfigTrackingInterceptor.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/configuration/tracker/ConfigTrackingInterceptor.java
@@ -62,7 +62,7 @@ public Map getReadOptions() {
* @param config configuration instance
*/
public void configure(Config config) {
- enabled = config.getValue("quarkus.config-tracking.enabled", boolean.class);
+ enabled = config.getOptionalValue("quarkus.config-tracking.enabled", boolean.class).orElse(false);
if (enabled) {
readOptions = new ConcurrentHashMap<>();
}
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/console/ConsoleConfig.java b/core/deployment/src/main/java/io/quarkus/deployment/console/ConsoleConfig.java
index 433c9129d4f8da..e5b683ebd966d2 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/console/ConsoleConfig.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/console/ConsoleConfig.java
@@ -3,6 +3,9 @@
import io.quarkus.runtime.annotations.ConfigItem;
import io.quarkus.runtime.annotations.ConfigRoot;
+/**
+ * Console
+ */
@ConfigRoot
public class ConsoleConfig {
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/ClassComparisonUtil.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/ClassComparisonUtil.java
index a7f18fb788e720..8c87e8f7249161 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/dev/ClassComparisonUtil.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/ClassComparisonUtil.java
@@ -6,6 +6,7 @@
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;
@@ -19,6 +20,10 @@
import org.jboss.jandex.Type;
public class ClassComparisonUtil {
+ private static final Set IGNORED_ANNOTATIONS = Set.of(
+ DotName.createSimple("kotlin.jvm.internal.SourceDebugExtension"),
+ DotName.createSimple("kotlin.Metadata"));
+
static boolean isSameStructure(ClassInfo clazz, ClassInfo old) {
if (clazz.flags() != old.flags()) {
return false;
@@ -161,6 +166,9 @@ private static void methodMap(Collection b, List valuesA = a.values();
List valuesB = b.values();
if (valuesA.size() != valuesB.size()) {
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/DevModeMain.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/DevModeMain.java
index 02bfdcd3405e51..6377b9c3b908a5 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/dev/DevModeMain.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/DevModeMain.java
@@ -40,7 +40,7 @@ public class DevModeMain implements Closeable {
private final DevModeContext context;
- private static volatile CuratedApplication curatedApplication;
+ private volatile CuratedApplication curatedApplication;
private Closeable realCloseable;
public DevModeMain(DevModeContext context) {
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 0fbd24bd9f3b7b..890a586828c5e1 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
@@ -15,6 +15,7 @@
import java.util.ServiceLoader;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
@@ -29,14 +30,12 @@
import io.quarkus.bootstrap.app.CuratedApplication;
import io.quarkus.bootstrap.app.RunningQuarkusApplication;
import io.quarkus.bootstrap.app.StartupAction;
-import io.quarkus.bootstrap.classloading.ClassPathElement;
import io.quarkus.bootstrap.classloading.QuarkusClassLoader;
import io.quarkus.bootstrap.logging.InitialConfigurator;
import io.quarkus.bootstrap.runner.Timing;
import io.quarkus.builder.BuildChainBuilder;
import io.quarkus.builder.BuildContext;
import io.quarkus.builder.BuildStep;
-import io.quarkus.commons.classloading.ClassloadHelper;
import io.quarkus.deployment.builditem.ApplicationClassPredicateBuildItem;
import io.quarkus.deployment.console.ConsoleCommand;
import io.quarkus.deployment.console.ConsoleStateManager;
@@ -61,16 +60,16 @@ public class IsolatedDevModeMain implements BiConsumer hotReplacementSetups = new ArrayList<>();
- private static volatile RunningQuarkusApplication runner;
- static volatile Throwable deploymentProblem;
- private static volatile CuratedApplication curatedApplication;
- private static volatile AugmentAction augmentAction;
- private static volatile boolean restarting;
- private static volatile boolean firstStartCompleted;
- private static final CountDownLatch shutdownLatch = new CountDownLatch(1);
+ private volatile RunningQuarkusApplication runner;
+ final AtomicReference deploymentProblem = new AtomicReference<>();
+ private volatile CuratedApplication curatedApplication;
+ private volatile AugmentAction augmentAction;
+ private volatile boolean restarting;
+ private volatile boolean firstStartCompleted;
+ private final CountDownLatch shutdownLatch = new CountDownLatch(1);
private Thread shutdownThread;
private CodeGenWatcher codeGenWatcher;
- private static volatile ConsoleStateManager.ConsoleContext consoleContext;
+ private volatile ConsoleStateManager.ConsoleContext consoleContext;
private final List listeners = new ArrayList<>();
private synchronized void firstStart() {
@@ -83,38 +82,18 @@ private synchronized void firstStart() {
//this is a bit yuck, but we need replace the default
//exit handler in the runtime class loader
//TODO: look at implementing a common core classloader, that removes the need for this sort of crappy hack
- curatedApplication.getBaseRuntimeClassLoader().loadClass(ApplicationLifecycleManager.class.getName())
+ curatedApplication.getOrCreateBaseRuntimeClassLoader().loadClass(ApplicationLifecycleManager.class.getName())
.getMethod("setDefaultExitCodeHandler", Consumer.class)
- .invoke(null, new Consumer() {
- @Override
- public void accept(Integer integer) {
- if (restarting || ApplicationLifecycleManager.isVmShuttingDown()
- || context.isAbortOnFailedStart() ||
- context.isTest()) {
- return;
- }
- if (consoleContext == null) {
- consoleContext = ConsoleStateManager.INSTANCE
- .createContext("Completed Application");
- }
- //this sucks, but when we get here logging is gone
- //so we just setup basic console logging
- InitialConfigurator.DELAYED_HANDLER.addHandler(new ConsoleHandler(
- ConsoleHandler.Target.SYSTEM_OUT,
- new ColorPatternFormatter("%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p [%c{3.}] (%t) %s%e%n")));
- consoleContext.reset(new ConsoleCommand(' ', "Restarts the application", "to restart", 0, null,
- () -> {
- consoleContext.reset();
- RuntimeUpdatesProcessor.INSTANCE.doScan(true, true);
- }));
- }
- });
+ .invoke(null, getExitCodeHandler());
StartupAction start = augmentAction.createInitialRuntimeApplication();
runner = start.runMainClass(context.getArgs());
- RuntimeUpdatesProcessor.INSTANCE.setConfiguredInstrumentationEnabled(
- runner.getConfigValue("quarkus.live-reload.instrumentation", Boolean.class).orElse(false));
+ RuntimeUpdatesProcessor.INSTANCE
+ .setConfiguredInstrumentationEnabled(
+ runner.getConfigValue("quarkus.live-reload.instrumentation", Boolean.class).orElse(false))
+ .setLiveReloadEnabled(
+ runner.getConfigValue("quarkus.live-reload.enabled", Boolean.class).orElse(false));
firstStartCompleted = true;
notifyListenersAfterStart();
@@ -124,7 +103,7 @@ public void accept(Integer integer) {
rootCause = rootCause.getCause();
}
if (!(rootCause instanceof BindException)) {
- deploymentProblem = t;
+ deploymentProblem.set(t);
if (!context.isAbortOnFailedStart()) {
//we need to set this here, while we still have the correct TCCL
//this is so the config is still valid, and we can read HTTP config from application.properties
@@ -136,7 +115,8 @@ public void accept(Integer integer) {
ApplicationStateNotification.notifyStartupFailed(t);
if (RuntimeUpdatesProcessor.INSTANCE != null) {
- Thread.currentThread().setContextClassLoader(curatedApplication.getBaseRuntimeClassLoader());
+ Thread.currentThread()
+ .setContextClassLoader(curatedApplication.getOrCreateBaseRuntimeClassLoader());
try {
if (!InitialConfigurator.DELAYED_HANDLER.isActivated()) {
Class> cl = Thread.currentThread().getContextClassLoader()
@@ -170,6 +150,35 @@ public void accept(Integer integer) {
}
}
+ private Consumer getExitCodeHandler() {
+ if (context.isTest() || context.isAbortOnFailedStart()) {
+ return TestExitCodeHandler.INSTANCE;
+ }
+
+ return new Consumer() {
+ @Override
+ public void accept(Integer integer) {
+ if (restarting || ApplicationLifecycleManager.isVmShuttingDown()) {
+ return;
+ }
+ if (consoleContext == null) {
+ consoleContext = ConsoleStateManager.INSTANCE
+ .createContext("Completed Application");
+ }
+ //this sucks, but when we get here logging is gone
+ //so we just setup basic console logging
+ InitialConfigurator.DELAYED_HANDLER.addHandler(new ConsoleHandler(
+ ConsoleHandler.Target.SYSTEM_OUT,
+ new ColorPatternFormatter("%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p [%c{3.}] (%t) %s%e%n")));
+ consoleContext.reset(new ConsoleCommand(' ', "Restarts the application", "to restart", 0, null,
+ () -> {
+ consoleContext.reset();
+ RuntimeUpdatesProcessor.INSTANCE.doScan(true, true);
+ }));
+ }
+ };
+ }
+
public void restartCallback(Set changedResources, ClassScanResult result) {
restartApp(changedResources,
new ClassChangeInformation(result.changedClassNames, result.deletedClassNames, result.addedClassNames));
@@ -181,8 +190,8 @@ public synchronized void restartApp(Set changedResources, ClassChangeInf
consoleContext.reset();
}
stop();
- Timing.restart(curatedApplication.getAugmentClassLoader());
- deploymentProblem = null;
+ Timing.restart(curatedApplication.getOrCreateAugmentClassLoader());
+ deploymentProblem.set(null);
ClassLoader old = Thread.currentThread().getContextClassLoader();
try {
@@ -196,14 +205,14 @@ public synchronized void restartApp(Set changedResources, ClassChangeInf
firstStartCompleted = true;
}
} catch (Throwable t) {
- deploymentProblem = t;
+ deploymentProblem.set(t);
Throwable rootCause = t;
while (rootCause.getCause() != null) {
rootCause = rootCause.getCause();
}
if (!(rootCause instanceof BindException)) {
log.error("Failed to start quarkus", t);
- Thread.currentThread().setContextClassLoader(curatedApplication.getAugmentClassLoader());
+ Thread.currentThread().setContextClassLoader(curatedApplication.getOrCreateAugmentClassLoader());
LoggingSetupRecorder.handleFailedStart();
}
}
@@ -249,22 +258,22 @@ private RuntimeUpdatesProcessor setupRuntimeCompilation(DevModeContext context,
public byte[] apply(String s, byte[] bytes) {
return ClassTransformingBuildStep.transform(s, bytes);
}
- }, testSupport);
+ }, testSupport, deploymentProblem);
for (HotReplacementSetup service : ServiceLoader.load(HotReplacementSetup.class,
- curatedApplication.getBaseRuntimeClassLoader())) {
+ curatedApplication.getOrCreateBaseRuntimeClassLoader())) {
hotReplacementSetups.add(service);
service.setupHotDeployment(processor);
processor.addHotReplacementSetup(service);
}
for (DeploymentFailedStartHandler service : ServiceLoader.load(DeploymentFailedStartHandler.class,
- curatedApplication.getAugmentClassLoader())) {
+ curatedApplication.getOrCreateAugmentClassLoader())) {
processor.addDeploymentFailedStartHandler(new Runnable() {
@Override
public void run() {
ClassLoader old = Thread.currentThread().getContextClassLoader();
try {
- Thread.currentThread().setContextClassLoader(curatedApplication.getAugmentClassLoader());
+ Thread.currentThread().setContextClassLoader(curatedApplication.getOrCreateAugmentClassLoader());
service.handleFailedInitialStart();
} finally {
Thread.currentThread().setContextClassLoader(old);
@@ -307,6 +316,7 @@ public void close() {
restarting = true;
if (codeGenWatcher != null) {
codeGenWatcher.shutdown();
+ codeGenWatcher = null;
}
for (int i = listeners.size() - 1; i >= 0; i--) {
@@ -316,6 +326,7 @@ public void close() {
log.warn("Unable to invoke 'beforeShutdown' of " + listeners.get(i).getClass(), e);
}
}
+ listeners.clear();
try {
stop();
@@ -337,10 +348,14 @@ public void close() {
for (HotReplacementSetup i : hotReplacementSetups) {
i.close();
}
+ hotReplacementSetups.clear();
} finally {
try {
DevConsoleManager.close();
curatedApplication.close();
+ curatedApplication = null;
+ augmentAction = null;
+ deploymentProblem.set(null);
} finally {
if (shutdownThread != null) {
try {
@@ -362,7 +377,7 @@ public void accept(CuratedApplication o, Map params) {
//setup the dev mode thread pool for NIO
System.setProperty("java.nio.channels.DefaultThreadPool.threadFactory",
"io.quarkus.dev.io.NioThreadPoolThreadFactory");
- Timing.staticInitStarted(o.getBaseRuntimeClassLoader(), false);
+ Timing.staticInitStarted(o.getOrCreateBaseRuntimeClassLoader(), false);
//https://github.com/quarkusio/quarkus/issues/9748
//if you have an app with all daemon threads then the app thread
//may be the only thread keeping the JVM alive
@@ -397,29 +412,7 @@ public void run() {
}
augmentAction = new AugmentActionImpl(curatedApplication,
- List.of(new Consumer() {
- @Override
- public void accept(BuildChainBuilder buildChainBuilder) {
- buildChainBuilder.addBuildStep(new BuildStep() {
- @Override
- public void execute(BuildContext context) {
- //we need to make sure all hot reloadable classes are application classes
- context.produce(new ApplicationClassPredicateBuildItem(new Predicate() {
- @Override
- public boolean test(String s) {
- QuarkusClassLoader cl = (QuarkusClassLoader) Thread.currentThread()
- .getContextClassLoader();
- String resourceName = ClassloadHelper.fromClassNameToResourceName(s);
- //if the class file is present in this (and not the parent) CL then it is an application class
- List res = cl
- .getElementsWithResource(resourceName, true);
- return !res.isEmpty();
- }
- }));
- }
- }).produces(ApplicationClassPredicateBuildItem.class).build();
- }
- }),
+ List.of(new AddApplicationClassPredicateBuildStep()),
List.of());
// code generators should be initialized before the runtime compilation is setup to properly configure the sources directories
@@ -435,10 +428,11 @@ public boolean test(String s) {
firstStart();
// doStart(false, Collections.emptySet());
- if (deploymentProblem != null || RuntimeUpdatesProcessor.INSTANCE.getCompileProblem() != null) {
+ if (deploymentProblem.get() != null || RuntimeUpdatesProcessor.INSTANCE.getCompileProblem() != null) {
if (context.isAbortOnFailedStart()) {
- Throwable throwable = deploymentProblem == null ? RuntimeUpdatesProcessor.INSTANCE.getCompileProblem()
- : deploymentProblem;
+ Throwable throwable = deploymentProblem.get() == null
+ ? RuntimeUpdatesProcessor.INSTANCE.getCompileProblem()
+ : deploymentProblem.get();
throw (throwable instanceof RuntimeException ? (RuntimeException) throwable
: new RuntimeException(throwable));
@@ -471,4 +465,33 @@ public void run() {
throw toThrow;
}
}
+
+ private static class AddApplicationClassPredicateBuildStep implements Consumer {
+
+ @Override
+ public void accept(BuildChainBuilder buildChainBuilder) {
+ buildChainBuilder.addBuildStep(new BuildStep() {
+ @Override
+ public void execute(BuildContext context) {
+ //we need to make sure all hot reloadable classes are application classes
+ context.produce(new ApplicationClassPredicateBuildItem(new Predicate() {
+ @Override
+ public boolean test(String className) {
+ return QuarkusClassLoader.isApplicationClass(className);
+ }
+ }));
+ }
+ }).produces(ApplicationClassPredicateBuildItem.class).build();
+ }
+ }
+
+ private static class TestExitCodeHandler implements Consumer {
+
+ private static final TestExitCodeHandler INSTANCE = new TestExitCodeHandler();
+
+ @Override
+ public void accept(Integer exitCode) {
+ // do nothing
+ }
+ }
}
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/IsolatedRemoteDevModeMain.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/IsolatedRemoteDevModeMain.java
index 1ec369cd140fbf..17d4b5e547fb81 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/dev/IsolatedRemoteDevModeMain.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/IsolatedRemoteDevModeMain.java
@@ -21,6 +21,7 @@
import java.util.Optional;
import java.util.ServiceLoader;
import java.util.Set;
+import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Function;
@@ -57,7 +58,7 @@ public class IsolatedRemoteDevModeMain implements BiConsumer hotReplacementSetups = new ArrayList<>();
- static volatile Throwable deploymentProblem;
+ private AtomicReference deploymentProblem = new AtomicReference<>();
static volatile RemoteDevClient remoteDevClient;
static volatile Closeable remoteDevClientSession;
private static volatile CuratedApplication curatedApplication;
@@ -68,7 +69,7 @@ public class IsolatedRemoteDevModeMain implements BiConsumer providers = ServiceLoader.load(RemoteDevClientProvider.class,
- curatedApplication.getAugmentClassLoader());
+ curatedApplication.getOrCreateAugmentClassLoader());
RemoteDevClient client = null;
for (RemoteDevClientProvider provider : providers) {
Optional opt = provider.getClient();
@@ -99,7 +100,7 @@ private synchronized JarResult generateApplication() {
curatedApplication.getApplicationModel(), null);
return start.getJar();
} catch (Throwable t) {
- deploymentProblem = t;
+ deploymentProblem.set(t);
log.error("Failed to generate Quarkus application", t);
return null;
}
@@ -137,22 +138,22 @@ public void accept(DevModeContext.ModuleInfo moduleInfo, String s) {
public byte[] apply(String s, byte[] bytes) {
return ClassTransformingBuildStep.transform(s, bytes);
}
- }, null);
+ }, null, deploymentProblem);
for (HotReplacementSetup service : ServiceLoader.load(HotReplacementSetup.class,
- curatedApplication.getBaseRuntimeClassLoader())) {
+ curatedApplication.getOrCreateBaseRuntimeClassLoader())) {
hotReplacementSetups.add(service);
service.setupHotDeployment(processor);
processor.addHotReplacementSetup(service);
}
for (DeploymentFailedStartHandler service : ServiceLoader.load(DeploymentFailedStartHandler.class,
- curatedApplication.getAugmentClassLoader())) {
+ curatedApplication.getOrCreateAugmentClassLoader())) {
processor.addDeploymentFailedStartHandler(new Runnable() {
@Override
public void run() {
ClassLoader old = Thread.currentThread().getContextClassLoader();
try {
- Thread.currentThread().setContextClassLoader(curatedApplication.getAugmentClassLoader());
+ Thread.currentThread().setContextClassLoader(curatedApplication.getOrCreateAugmentClassLoader());
service.handleFailedInitialStart();
} finally {
Thread.currentThread().setContextClassLoader(old);
@@ -189,6 +190,7 @@ public void close() {
}
}
} finally {
+ deploymentProblem.set(null);
curatedApplication.close();
}
@@ -198,7 +200,7 @@ public void close() {
@Override
public void accept(CuratedApplication o, Map o2) {
LoggingSetupRecorder.handleFailedStart(); //we are not going to actually run an app
- Timing.staticInitStarted(o.getBaseRuntimeClassLoader(), false);
+ Timing.staticInitStarted(o.getOrCreateBaseRuntimeClassLoader(), false);
try {
curatedApplication = o;
Object potentialContext = o2.get(DevModeContext.class.getName());
@@ -248,7 +250,7 @@ public void run() {
}
private Closeable doConnect() {
- return remoteDevClient.sendConnectRequest(new RemoteDevState(currentHashes, deploymentProblem),
+ return remoteDevClient.sendConnectRequest(new RemoteDevState(currentHashes, deploymentProblem.get()),
new Function, Map>() {
@Override
public Map apply(Set fileNames) {
@@ -283,6 +285,7 @@ private RemoteDevClient.SyncResult runSync() {
Set removed = new HashSet<>();
Map changed = new HashMap<>();
try {
+ deploymentProblem.set(null);
boolean scanResult = RuntimeUpdatesProcessor.INSTANCE.doScan(true);
if (!scanResult && !copiedStaticResources.isEmpty()) {
scanResult = true;
@@ -305,7 +308,7 @@ private RemoteDevClient.SyncResult runSync() {
currentHashes = newHashes;
}
} catch (IOException e) {
- deploymentProblem = e;
+ deploymentProblem.set(e);
}
return new RemoteDevClient.SyncResult() {
@Override
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/IsolatedTestModeMain.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/IsolatedTestModeMain.java
index e58029cd79cf26..9fa94f1ff6aecd 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/dev/IsolatedTestModeMain.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/IsolatedTestModeMain.java
@@ -36,7 +36,6 @@ public class IsolatedTestModeMain extends IsolatedDevModeMain {
private volatile DevModeContext context;
private final List hotReplacementSetups = new ArrayList<>();
- static volatile Throwable deploymentProblem;
private static volatile CuratedApplication curatedApplication;
private static volatile AugmentAction augmentAction;
@@ -68,10 +67,10 @@ public void accept(DevModeContext.ModuleInfo moduleInfo, String s) {
public byte[] apply(String s, byte[] bytes) {
return ClassTransformingBuildStep.transform(s, bytes);
}
- }, testSupport);
+ }, testSupport, deploymentProblem);
for (HotReplacementSetup service : ServiceLoader.load(HotReplacementSetup.class,
- curatedApplication.getBaseRuntimeClassLoader())) {
+ curatedApplication.getOrCreateBaseRuntimeClassLoader())) {
hotReplacementSetups.add(service);
service.setupHotDeployment(processor);
processor.addHotReplacementSetup(service);
@@ -107,7 +106,7 @@ public void close() {
public void accept(CuratedApplication o, Map params) {
System.setProperty("java.nio.channels.DefaultThreadPool.threadFactory",
"io.quarkus.dev.io.NioThreadPoolThreadFactory");
- Timing.staticInitStarted(o.getBaseRuntimeClassLoader(), false);
+ Timing.staticInitStarted(o.getOrCreateBaseRuntimeClassLoader(), false);
try {
curatedApplication = o;
Object potentialContext = params.get(DevModeContext.class.getName());
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 580506a736255f..d5e2b05b68da44 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
@@ -85,12 +85,6 @@ public B debug(String debug) {
return (B) this;
}
- @SuppressWarnings("unchecked")
- public B debugPortOk(Boolean debugPortOk) {
- QuarkusDevModeLauncher.this.debugPortOk = debugPortOk;
- return (B) this;
- }
-
@SuppressWarnings("unchecked")
public B suspend(String suspend) {
QuarkusDevModeLauncher.this.suspend = suspend;
@@ -303,10 +297,10 @@ public R build() throws Exception {
private List args = new ArrayList<>(0);
private String debug;
- private Boolean debugPortOk;
private String suspend;
private String debugHost = "localhost";
private String debugPort = "5005";
+ private String actualDebugPort;
private File projectDir;
private File buildDir;
private File outputDir;
@@ -390,12 +384,13 @@ protected void prepare() throws Exception {
if (debug != null && debug.equalsIgnoreCase("client")) {
args.add("-agentlib:jdwp=transport=dt_socket,address=" + debugHost + ":" + port + ",server=n,suspend=" + suspend);
+ actualDebugPort = String.valueOf(port);
} else if (debug == null || !debug.equalsIgnoreCase("false")) {
// if the debug port is used, we want to make an effort to pick another one
// if we can't find an open port, we don't fail the process launch, we just don't enable debugging
// Furthermore, we don't check this on restarts, as the previous process is still running
boolean warnAboutChange = false;
- if (debugPortOk == null) {
+ if (actualDebugPort == null) {
int tries = 0;
while (true) {
boolean isPortUsed;
@@ -408,20 +403,19 @@ protected void prepare() throws Exception {
isPortUsed = false;
}
if (!isPortUsed) {
- debugPortOk = true;
+ actualDebugPort = String.valueOf(port);
break;
}
if (++tries >= 5) {
- debugPortOk = false;
break;
} else {
port = getRandomPort();
}
}
}
- if (debugPortOk) {
+ if (actualDebugPort != null) {
if (warnAboutChange) {
- warn("Changed debug port to " + port + " because of a port conflict");
+ warn("Changed debug port to " + actualDebugPort + " because of a port conflict");
}
args.add("-agentlib:jdwp=transport=dt_socket,address=" + debugHost + ":" + port + ",server=y,suspend="
+ suspend);
@@ -547,8 +541,8 @@ public List args() {
return args;
}
- public Boolean getDebugPortOk() {
- return debugPortOk;
+ public String getActualDebugPort() {
+ return actualDebugPort;
}
protected abstract boolean isDebugEnabled();
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 46b3ba3b1862c0..d69f80e7cf25fd 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
@@ -40,6 +40,7 @@
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.BiConsumer;
@@ -91,6 +92,7 @@ public class RuntimeUpdatesProcessor implements HotReplacementContext, Closeable
volatile Throwable compileProblem;
volatile Throwable testCompileProblem;
volatile Throwable hotReloadProblem;
+ private final AtomicReference deploymentProblem;
private volatile Predicate disableInstrumentationForClassPredicate = new AlwaysFalsePredicate<>();
private volatile Predicate disableInstrumentationForIndexPredicate = new AlwaysFalsePredicate<>();
@@ -141,7 +143,7 @@ public RuntimeUpdatesProcessor(Path applicationRoot, DevModeContext context, Qua
DevModeType devModeType, BiConsumer, ClassScanResult> restartCallback,
BiConsumer copyResourceNotification,
BiFunction classTransformers,
- TestSupport testSupport) {
+ TestSupport testSupport, AtomicReference deploymentProblem) {
this.applicationRoot = applicationRoot;
this.context = context;
this.compiler = compiler;
@@ -180,6 +182,7 @@ public void testsDisabled() {
}
});
}
+ this.deploymentProblem = deploymentProblem;
}
public TestSupport getTestSupport() {
@@ -187,12 +190,13 @@ public TestSupport getTestSupport() {
}
@Override
- public Path getClassesDir() {
- //TODO: fix all these
- for (DevModeContext.ModuleInfo i : context.getAllModules()) {
- return Paths.get(i.getMain().getClassesPath());
+ public List getClassesDir() {
+ final List allModules = context.getAllModules();
+ final List paths = new ArrayList<>(allModules.size());
+ for (DevModeContext.ModuleInfo i : allModules) {
+ paths.add(Path.of(i.getMain().getClassesPath()));
}
- return null;
+ return paths;
}
@Override
@@ -245,13 +249,17 @@ public void handleChanges(Collection changes) {
periodicTestCompile();
}
};
+ // monitor .env as it can impact test execution
+ testClassChangeWatcher.watchFiles(Path.of(context.getApplicationRoot().getProjectDirectory()),
+ List.of(Path.of(".env")),
+ callback);
Set nonExistent = new HashSet<>();
for (DevModeContext.ModuleInfo module : context.getAllModules()) {
for (Path path : module.getMain().getSourcePaths()) {
- testClassChangeWatcher.watchPath(path.toFile(), callback);
+ testClassChangeWatcher.watchDirectoryRecursively(path, callback);
}
for (Path path : module.getMain().getResourcePaths()) {
- testClassChangeWatcher.watchPath(path.toFile(), callback);
+ testClassChangeWatcher.watchDirectoryRecursively(path, callback);
}
}
for (DevModeContext.ModuleInfo module : context.getAllModules()) {
@@ -260,14 +268,14 @@ public void handleChanges(Collection changes) {
if (!Files.isDirectory(path)) {
nonExistent.add(path);
} else {
- testClassChangeWatcher.watchPath(path.toFile(), callback);
+ testClassChangeWatcher.watchDirectoryRecursively(path, callback);
}
}
for (Path path : module.getTest().get().getResourcePaths()) {
if (!Files.isDirectory(path)) {
nonExistent.add(path);
} else {
- testClassChangeWatcher.watchPath(path.toFile(), callback);
+ testClassChangeWatcher.watchDirectoryRecursively(path, callback);
}
}
}
@@ -283,7 +291,7 @@ public void run() {
Path i = iterator.next();
if (Files.isDirectory(i)) {
iterator.remove();
- testClassChangeWatcher.watchPath(i.toFile(), callback);
+ testClassChangeWatcher.watchDirectoryRecursively(i, callback);
added = true;
}
@@ -391,7 +399,7 @@ public List getResourcesDir() {
public Throwable getDeploymentProblem() {
//we differentiate between these internally, however for the error reporting they are the same
return compileProblem != null ? compileProblem
- : IsolatedDevModeMain.deploymentProblem != null ? IsolatedDevModeMain.deploymentProblem
+ : deploymentProblem.get() != null ? deploymentProblem.get()
: hotReloadProblem;
}
@@ -534,7 +542,7 @@ public boolean doScan(boolean userInitiated, boolean forceRestart) {
//all broken we just assume the reason that they have refreshed is because they have fixed something
//trying to watch all resource files is complex and this is likely a good enough solution for what is already an edge case
boolean restartNeeded = !instrumentationChange && (changedClassResults.isChanged()
- || (IsolatedDevModeMain.deploymentProblem != null && userInitiated) || fileRestartNeeded);
+ || (deploymentProblem.get() != null && userInitiated) || fileRestartNeeded);
if (restartNeeded) {
String changeString = changedFilesForRestart.stream().map(Path::getFileName).map(Object::toString)
.collect(Collectors.joining(", "));
@@ -618,6 +626,11 @@ public boolean instrumentationEnabled() {
return configuredInstrumentationEnabled;
}
+ public RuntimeUpdatesProcessor setLiveReloadEnabled(boolean liveReloadEnabled) {
+ this.liveReloadEnabled = liveReloadEnabled;
+ return this;
+ }
+
public RuntimeUpdatesProcessor setConfiguredInstrumentationEnabled(boolean configuredInstrumentationEnabled) {
this.configuredInstrumentationEnabled = configuredInstrumentationEnabled;
return this;
@@ -1203,11 +1216,32 @@ private RuntimeUpdatesProcessor setWatchedFilePathsInternal(Map
// Then process glob patterns
for (Entry e : watchedFilePaths.entrySet()) {
String watchedFilePath = e.getKey();
- Path path = Paths.get(watchedFilePath);
- if (!path.isAbsolute() && !watchedRootPaths.contains(e.getKey()) && maybeGlobPattern(watchedFilePath)) {
- Path resolvedPath = root.resolve(watchedFilePath);
- for (WatchedPath extra : expandGlobPattern(root, resolvedPath, watchedFilePath, e.getValue())) {
- timestamps.watchedPaths.put(extra.filePath, extra);
+ Path path = Paths.get(sanitizedPattern(watchedFilePath));
+ if (!path.isAbsolute() && !watchedRootPaths.contains(e.getKey())
+ && maybeGlobPattern(watchedFilePath)) {
+ try {
+ final PathMatcher matcher = FileSystems.getDefault().getPathMatcher("glob:" + watchedFilePath);
+ Files.walkFileTree(root, new SimpleFileVisitor() {
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
+ Path relativePath = root.relativize(file);
+ if (matcher.matches(relativePath)) {
+ log.debugf("Glob pattern [%s] matched %s from %s", watchedFilePath, relativePath,
+ root);
+ WatchedPath extra = new WatchedPath(file, relativePath, e.getValue(),
+ attrs.lastModifiedTime().toMillis());
+ timestamps.watchedPaths.put(extra.filePath, extra);
+ }
+ return FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult visitFileFailed(Path file, IOException exc) {
+ return FileVisitResult.CONTINUE;
+ }
+ });
+ } catch (IOException ex) {
+ throw new UncheckedIOException(ex);
}
}
}
@@ -1218,8 +1252,9 @@ private RuntimeUpdatesProcessor setWatchedFilePathsInternal(Map
// Finally process watched absolute paths
for (Entry e : watchedFilePaths.entrySet()) {
String watchedFilePath = e.getKey();
- Path path = Paths.get(watchedFilePath);
+ Path path = Paths.get(sanitizedPattern(watchedFilePath));
if (path.isAbsolute()) {
+ path = Paths.get(watchedFilePath);
log.debugf("Watch %s", path);
if (Files.exists(path)) {
putLastModifiedTime(path, path, e.getValue(), timestamps);
@@ -1234,6 +1269,10 @@ private RuntimeUpdatesProcessor setWatchedFilePathsInternal(Map
return this;
}
+ private String sanitizedPattern(String pattern) {
+ return pattern.replaceAll("[*?]", "");
+ }
+
private boolean maybeGlobPattern(String path) {
return path.contains("*") || path.contains("?");
}
@@ -1281,32 +1320,6 @@ public void close() throws IOException {
}
}
- private List expandGlobPattern(Path root, Path path, String pattern, boolean restart) {
- PathMatcher pathMatcher = FileSystems.getDefault().getPathMatcher("glob:" + path.toString());
- List files = new ArrayList<>();
- try {
- Files.walkFileTree(root, new SimpleFileVisitor() {
- @Override
- public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
- if (pathMatcher.matches(file)) {
- Path relativePath = root.relativize(file);
- log.debugf("Glob pattern [%s] matched %s from %s", pattern, relativePath, root);
- files.add(new WatchedPath(file, relativePath, restart, attrs.lastModifiedTime().toMillis()));
- }
- return FileVisitResult.CONTINUE;
- }
-
- @Override
- public FileVisitResult visitFileFailed(Path file, IOException exc) {
- return FileVisitResult.CONTINUE;
- }
- });
- } catch (IOException e) {
- throw new UncheckedIOException(e);
- }
- return files;
- }
-
public boolean toggleInstrumentation() {
instrumentationEnabled = !instrumentationEnabled();
if (instrumentationEnabled) {
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/devservices/DevServiceDescriptionBuildItem.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/devservices/DevServiceDescriptionBuildItem.java
index c5b7651297c0e5..e1898f49dee2c8 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/dev/devservices/DevServiceDescriptionBuildItem.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/devservices/DevServiceDescriptionBuildItem.java
@@ -9,14 +9,22 @@
public final class DevServiceDescriptionBuildItem extends MultiBuildItem {
private String name;
+ private String description;
private ContainerInfo containerInfo;
private Map configs;
public DevServiceDescriptionBuildItem() {
}
- public DevServiceDescriptionBuildItem(String name, ContainerInfo containerInfo, Map configs) {
+ public DevServiceDescriptionBuildItem(String name, ContainerInfo containerInfo,
+ Map configs) {
+ this(name, null, containerInfo, configs);
+ }
+
+ public DevServiceDescriptionBuildItem(String name, String description, ContainerInfo containerInfo,
+ Map configs) {
this.name = name;
+ this.description = description;
this.containerInfo = containerInfo;
this.configs = configs instanceof SortedMap ? configs : new TreeMap<>(configs);
}
@@ -29,6 +37,10 @@ public String getName() {
return name;
}
+ public String getDescription() {
+ return description;
+ }
+
public ContainerInfo getContainerInfo() {
return containerInfo;
}
@@ -41,6 +53,10 @@ public void setName(String name) {
this.name = name;
}
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
public void setContainerInfo(ContainerInfo containerInfo) {
this.containerInfo = containerInfo;
}
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/devservices/GlobalDevServicesConfig.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/devservices/GlobalDevServicesConfig.java
index 12102e2d700954..147e4bf0295228 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/dev/devservices/GlobalDevServicesConfig.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/devservices/GlobalDevServicesConfig.java
@@ -7,6 +7,9 @@
import io.quarkus.runtime.annotations.ConfigItem;
import io.quarkus.runtime.annotations.ConfigRoot;
+/**
+ * Dev Services
+ */
@ConfigRoot(name = "devservices")
public class GlobalDevServicesConfig {
@@ -17,7 +20,7 @@ public class GlobalDevServicesConfig {
boolean enabled;
/**
- * Global flag that can be used to force the attachmment of Dev Services to shared netxork. Default is false.
+ * Global flag that can be used to force the attachmment of Dev Services to shared network. Default is false.
*/
@ConfigItem(defaultValue = "false")
public boolean launchOnSharedNetwork;
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/filesystem/QuarkusFileManager.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/filesystem/QuarkusFileManager.java
index 4ac5314804078e..71bd65e54830db 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/dev/filesystem/QuarkusFileManager.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/filesystem/QuarkusFileManager.java
@@ -22,6 +22,8 @@ protected QuarkusFileManager(StandardJavaFileManager fileManager, Context contex
this.fileManager.setLocation(StandardLocation.SOURCE_OUTPUT, List.of(context.getGeneratedSourcesDirectory()));
}
if (context.getAnnotationProcessorPaths() != null) {
+ // Paths might be missing! (see: https://github.com/quarkusio/quarkus/issues/42908)
+ ensureDirectories(context.getAnnotationProcessorPaths());
this.fileManager.setLocation(StandardLocation.ANNOTATION_PROCESSOR_PATH, context.getAnnotationProcessorPaths());
}
} catch (IOException e) {
@@ -39,6 +41,8 @@ public void reset(Context context) {
this.fileManager.setLocation(StandardLocation.SOURCE_OUTPUT, List.of(context.getGeneratedSourcesDirectory()));
}
if (context.getAnnotationProcessorPaths() != null) {
+ // Paths might be missing! (see: https://github.com/quarkusio/quarkus/issues/42908)
+ ensureDirectories(context.getAnnotationProcessorPaths());
this.fileManager.setLocation(StandardLocation.ANNOTATION_PROCESSOR_PATH, context.getAnnotationProcessorPaths());
}
} catch (IOException e) {
@@ -46,6 +50,17 @@ public void reset(Context context) {
}
}
+ private void ensureDirectories(Iterable directories) {
+ for (File directory : directories) {
+ if (!directory.exists()) {
+ final boolean success = directory.mkdirs();
+ if (!success) {
+ throw new RuntimeException("Cannot create directory " + directory);
+ }
+ }
+ }
+ }
+
@Override
public void close() throws IOException {
super.close();
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/filesystem/ReloadableFileManager.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/filesystem/ReloadableFileManager.java
index f3ae3a718453bf..f2b6043d06244c 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/dev/filesystem/ReloadableFileManager.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/filesystem/ReloadableFileManager.java
@@ -1,6 +1,6 @@
package io.quarkus.deployment.dev.filesystem;
-import static io.quarkus.commons.classloading.ClassloadHelper.fromClassNameToResourceName;
+import static io.quarkus.commons.classloading.ClassLoaderHelper.fromClassNameToResourceName;
import java.io.File;
import java.io.IOException;
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/filesystem/StaticFileManager.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/filesystem/StaticFileManager.java
index d3706c1e133e54..acfad174712378 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/dev/filesystem/StaticFileManager.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/filesystem/StaticFileManager.java
@@ -31,8 +31,9 @@ public Iterable extends JavaFileObject> getJavaSources(Iterable extends File
@Override
public JavaFileObject getJavaFileForInput(Location location, String className, JavaFileObject.Kind kind)
throws IOException {
+ JavaFileObject file = this.fileManager.getJavaFileForInput(location, className, kind);
// Ignore the module info of the application in dev mode.
- if (context.ignoreModuleInfo() && "CLASS_OUTPUT".equalsIgnoreCase(location.getName())
+ if (file != null && context.ignoreModuleInfo() && "CLASS_OUTPUT".equalsIgnoreCase(location.getName())
&& "module-info".equalsIgnoreCase(className)) {
if (once.compareAndSet(false, true)) {
Logger.getLogger(StaticFileManager.class).info("Ignoring module-info.java in dev mode, " +
@@ -40,7 +41,7 @@ public JavaFileObject getJavaFileForInput(Location location, String className, J
}
return null;
}
- return this.fileManager.getJavaFileForInput(location, className, kind);
+ return file;
}
}
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/filesystem/watch/FileChangeEvent.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/filesystem/watch/FileChangeEvent.java
index 33468a891627c1..a8085072917a8d 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/dev/filesystem/watch/FileChangeEvent.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/filesystem/watch/FileChangeEvent.java
@@ -1,6 +1,6 @@
package io.quarkus.deployment.dev.filesystem.watch;
-import java.io.File;
+import java.nio.file.Path;
/**
* The event object that is fired when a file system change is detected.
@@ -10,7 +10,7 @@
*/
public class FileChangeEvent {
- private final File file;
+ private final Path file;
private final Type type;
/**
@@ -19,7 +19,7 @@ public class FileChangeEvent {
* @param file the file which is being watched
* @param type the type of event that was encountered
*/
- public FileChangeEvent(File file, Type type) {
+ public FileChangeEvent(Path file, Type type) {
this.file = file;
this.type = type;
}
@@ -29,7 +29,7 @@ public FileChangeEvent(File file, Type type) {
*
* @return the file which was being watched
*/
- public File getFile() {
+ public Path getFile() {
return file;
}
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/filesystem/watch/WatchServiceFileSystemWatcher.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/filesystem/watch/WatchServiceFileSystemWatcher.java
index cfd21f6f1940e5..de2459b4f75997 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/dev/filesystem/watch/WatchServiceFileSystemWatcher.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/filesystem/watch/WatchServiceFileSystemWatcher.java
@@ -4,12 +4,12 @@
import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE;
import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;
-import java.io.File;
import java.io.IOException;
+import java.io.UncheckedIOException;
import java.nio.file.ClosedWatchServiceException;
import java.nio.file.FileSystems;
+import java.nio.file.Files;
import java.nio.file.Path;
-import java.nio.file.Paths;
import java.nio.file.StandardWatchEventKinds;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
@@ -26,6 +26,8 @@
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
import org.jboss.logging.Logger;
@@ -43,9 +45,9 @@ public class WatchServiceFileSystemWatcher implements Runnable {
private static final AtomicInteger threadIdCounter = new AtomicInteger(0);
private WatchService watchService;
- private final Map files = Collections.synchronizedMap(new HashMap());
+ private final Map monitoredDirectories = Collections.synchronizedMap(new HashMap<>());
private final Map pathDataByKey = Collections
- .synchronizedMap(new IdentityHashMap());
+ .synchronizedMap(new IdentityHashMap<>());
private volatile boolean stopped = false;
private final Thread watchThread;
@@ -70,19 +72,19 @@ public void run() {
try {
PathData pathData = pathDataByKey.get(key);
if (pathData != null) {
- final List results = new ArrayList();
+ final List results = new ArrayList<>();
List> events = key.pollEvents();
- final Set addedFiles = new HashSet();
- final Set deletedFiles = new HashSet();
+ final Set addedFiles = new HashSet<>();
+ final Set deletedFiles = new HashSet<>();
for (WatchEvent> event : events) {
Path eventPath = (Path) event.context();
- File targetFile = ((Path) key.watchable()).resolve(eventPath).toFile();
+ Path targetFile = ((Path) key.watchable()).resolve(eventPath).toAbsolutePath();
FileChangeEvent.Type type;
if (event.kind() == StandardWatchEventKinds.ENTRY_CREATE) {
type = FileChangeEvent.Type.ADDED;
addedFiles.add(targetFile);
- if (targetFile.isDirectory()) {
+ if (Files.isDirectory(targetFile)) {
try {
addWatchedDirectory(pathData, targetFile);
} catch (IOException e) {
@@ -107,6 +109,12 @@ public void run() {
Iterator it = results.iterator();
while (it.hasNext()) {
FileChangeEvent event = it.next();
+
+ if (!pathData.isMonitored(event.getFile())) {
+ it.remove();
+ continue;
+ }
+
if (event.getType() == FileChangeEvent.Type.MODIFIED) {
if (addedFiles.contains(event.getFile()) &&
deletedFiles.contains(event.getFile())) {
@@ -134,7 +142,7 @@ public void run() {
}
if (!results.isEmpty()) {
- for (FileChangeCallback callback : pathData.callbacks) {
+ for (FileChangeCallback callback : pathData.getCallbacks()) {
invokeCallback(callback, results);
}
}
@@ -142,7 +150,7 @@ public void run() {
} finally {
//if the key is no longer valid remove it from the files list
if (!key.reset()) {
- files.remove(key.watchable());
+ monitoredDirectories.remove(key.watchable());
}
}
}
@@ -156,39 +164,59 @@ public void run() {
}
}
- public synchronized void watchPath(File file, FileChangeCallback callback) {
+ public synchronized void watchDirectoryRecursively(Path directory, FileChangeCallback callback) {
try {
- PathData data = files.get(file);
+ Path absoluteDirectory = directory.toAbsolutePath();
+ PathData data = monitoredDirectories.get(absoluteDirectory);
if (data == null) {
- Set allDirectories = doScan(file).keySet();
- Path path = Paths.get(file.toURI());
- data = new PathData(path);
- for (File dir : allDirectories) {
+ Set allDirectories = doScan(absoluteDirectory).keySet();
+ data = new PathData(absoluteDirectory, List.of());
+ for (Path dir : allDirectories) {
addWatchedDirectory(data, dir);
}
- files.put(file, data);
+ monitoredDirectories.put(absoluteDirectory, data);
+ }
+ data.addCallback(callback);
+
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * @param directory a directory that will be watched
+ * @param monitoredFiles list of monitored files relative to directory. An empty list will monitor all files.
+ * @param callback callback called when a file is changed
+ */
+ public synchronized void watchFiles(Path directory, List monitoredFiles, FileChangeCallback callback) {
+ try {
+ Path absoluteDirectory = directory.toAbsolutePath();
+ PathData data = monitoredDirectories.get(absoluteDirectory);
+ if (data == null) {
+ data = new PathData(absoluteDirectory, monitoredFiles);
+ addWatchedDirectory(data, absoluteDirectory);
+ monitoredDirectories.put(absoluteDirectory, data);
}
- data.callbacks.add(callback);
+ data.addCallback(callback);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
- private void addWatchedDirectory(PathData data, File dir) throws IOException {
- Path path = Paths.get(dir.toURI());
- WatchKey key = path.register(watchService, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
+ private void addWatchedDirectory(PathData data, Path dir) throws IOException {
+ WatchKey key = dir.register(watchService, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
pathDataByKey.put(key, data);
- data.keys.add(key);
+ data.addWatchKey(key);
}
- public synchronized void unwatchPath(File file, final FileChangeCallback callback) {
- PathData data = files.get(file);
+ public synchronized void unwatchPath(Path directory, final FileChangeCallback callback) {
+ PathData data = monitoredDirectories.get(directory);
if (data != null) {
- data.callbacks.remove(callback);
- if (data.callbacks.isEmpty()) {
- files.remove(file);
- for (WatchKey key : data.keys) {
+ data.removeCallback(callback);
+ if (data.getCallbacks().isEmpty()) {
+ monitoredDirectories.remove(directory);
+ for (WatchKey key : data.getWatchKeys()) {
key.cancel();
pathDataByKey.remove(key);
}
@@ -205,20 +233,21 @@ public void close() throws IOException {
}
}
- private static Map doScan(File file) {
- final Map results = new HashMap();
+ private static Map doScan(Path directory) {
+ final Map results = new HashMap<>();
- final Deque toScan = new ArrayDeque();
- toScan.add(file);
+ final Deque toScan = new ArrayDeque<>();
+ toScan.add(directory);
while (!toScan.isEmpty()) {
- File next = toScan.pop();
- if (next.isDirectory()) {
- results.put(next, next.lastModified());
- File[] list = next.listFiles();
- if (list != null) {
- for (File f : list) {
- toScan.push(new File(f.getAbsolutePath()));
+ Path next = toScan.pop();
+ if (Files.isDirectory(next)) {
+ try {
+ results.put(next, Files.getLastModifiedTime(directory).toMillis());
+ try (Stream list = Files.list(next)) {
+ list.forEach(p -> toScan.push(p.toAbsolutePath()));
}
+ } catch (IOException e) {
+ throw new UncheckedIOException("Unable to scan: " + next, e);
}
}
}
@@ -234,12 +263,52 @@ private static void invokeCallback(FileChangeCallback callback, List callbacks = new ArrayList();
- final List keys = new ArrayList();
- private PathData(Path path) {
+ private final Path path;
+ private final List callbacks = new ArrayList<>();
+ private final List watchKeys = new ArrayList<>();
+ private final List monitoredFiles;
+
+ private PathData(Path path, List monitoredFiles) {
this.path = path;
+ this.monitoredFiles = monitoredFiles.stream().map(p -> path.resolve(p).toAbsolutePath())
+ .collect(Collectors.toList());
+ }
+
+ private void addWatchKey(WatchKey key) {
+ this.watchKeys.add(key);
+ }
+
+ private void addCallback(FileChangeCallback callback) {
+ this.callbacks.add(callback);
+ }
+
+ private void removeCallback(FileChangeCallback callback) {
+ this.callbacks.remove(callback);
+ }
+
+ private List getCallbacks() {
+ return callbacks;
+ }
+
+ private List getWatchKeys() {
+ return watchKeys;
+ }
+
+ private boolean isMonitored(Path file) {
+ if (monitoredFiles.isEmpty()) {
+ return true;
+ }
+
+ Path absolutePath = file.isAbsolute() ? file : file.toAbsolutePath();
+
+ for (Path monitoredFile : monitoredFiles) {
+ if (monitoredFile.equals(absolutePath)) {
+ return true;
+ }
+ }
+
+ return false;
}
}
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/JunitTestRunner.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/JunitTestRunner.java
index d1b59bbb95935a..6f0f4bce6ea974 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/JunitTestRunner.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/JunitTestRunner.java
@@ -1,6 +1,6 @@
package io.quarkus.deployment.dev.testing;
-import static io.quarkus.commons.classloading.ClassloadHelper.fromClassNameToResourceName;
+import static io.quarkus.commons.classloading.ClassLoaderHelper.fromClassNameToResourceName;
import java.io.IOException;
import java.io.InputStream;
@@ -46,6 +46,7 @@
import org.junit.platform.engine.TestDescriptor;
import org.junit.platform.engine.TestExecutionResult;
import org.junit.platform.engine.TestSource;
+import org.junit.platform.engine.TestTag;
import org.junit.platform.engine.UniqueId;
import org.junit.platform.engine.discovery.DiscoverySelectors;
import org.junit.platform.engine.reporting.ReportEntry;
@@ -258,8 +259,9 @@ public void executionSkipped(TestIdentifier testIdentifier, String reason) {
if (testClass != null) {
Map results = resultsByClass.computeIfAbsent(testClass.getName(),
s -> new HashMap<>());
- TestResult result = new TestResult(displayName, testClass.getName(), id,
- TestExecutionResult.aborted(null),
+ TestResult result = new TestResult(displayName, testClass.getName(),
+ toTagList(testIdentifier),
+ id, TestExecutionResult.aborted(null),
logHandler.captureOutput(), testIdentifier.isTest(), runId, 0, true);
results.put(id, result);
if (result.isTest()) {
@@ -312,8 +314,9 @@ public void executionFinished(TestIdentifier testIdentifier,
}
Map results = resultsByClass.computeIfAbsent(testClassName,
s -> new HashMap<>());
- TestResult result = new TestResult(displayName, testClassName, id,
- testExecutionResult,
+ TestResult result = new TestResult(displayName, testClassName,
+ toTagList(testIdentifier),
+ id, testExecutionResult,
logHandler.captureOutput(), testIdentifier.isTest(), runId,
System.currentTimeMillis() - startTimes.get(testIdentifier), true);
if (!results.containsKey(id)) {
@@ -332,6 +335,7 @@ public void executionFinished(TestIdentifier testIdentifier,
results.put(id,
new TestResult(currentNonDynamicTest.get().getDisplayName(),
result.getTestClass(),
+ toTagList(testIdentifier),
currentNonDynamicTest.get().getUniqueIdObject(),
TestExecutionResult.failed(failure), List.of(), false, runId, 0,
false));
@@ -349,6 +353,7 @@ public void executionFinished(TestIdentifier testIdentifier,
for (TestIdentifier child : children) {
UniqueId childId = UniqueId.parse(child.getUniqueId());
result = new TestResult(child.getDisplayName(), testClassName,
+ toTagList(testIdentifier),
childId,
testExecutionResult,
logHandler.captureOutput(), child.isTest(), runId,
@@ -419,6 +424,15 @@ public void reportingEntryPublished(TestIdentifier testIdentifier, ReportEntry e
}
}
+ private static List toTagList(TestIdentifier testIdentifier) {
+ return testIdentifier
+ .getTags()
+ .stream()
+ .map(TestTag::getName)
+ .sorted()
+ .toList();
+ }
+
private Class> getTestClassFromSource(Optional optionalTestSource) {
if (optionalTestSource.isPresent()) {
var testSource = optionalTestSource.get();
@@ -652,7 +666,7 @@ public String apply(Class> aClass) {
//this is a lot more complex
//we need to transform the classes to make the tracing magic work
QuarkusClassLoader deploymentClassLoader = (QuarkusClassLoader) Thread.currentThread().getContextClassLoader();
- Set classesToTransform = new HashSet<>(deploymentClassLoader.getLocalClassNames());
+ Set classesToTransform = new HashSet<>(deploymentClassLoader.getReloadableClassNames());
Map transformedClasses = new HashMap<>();
for (String i : classesToTransform) {
try {
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/ModuleTestRunner.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/ModuleTestRunner.java
index be0ca21445bf00..228665b40573f7 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/ModuleTestRunner.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/ModuleTestRunner.java
@@ -40,7 +40,7 @@ public synchronized void abort() {
Runnable prepare(ClassScanResult classScanResult, boolean reRunFailures, long runId, TestRunListener listener) {
var old = Thread.currentThread().getContextClassLoader();
- Thread.currentThread().setContextClassLoader(testApplication.getAugmentClassLoader());
+ Thread.currentThread().setContextClassLoader(testApplication.getOrCreateAugmentClassLoader());
try {
synchronized (this) {
if (runner != null) {
@@ -84,7 +84,7 @@ public FilterResult apply(TestDescriptor testDescriptor) {
@Override
public void run() {
var old = Thread.currentThread().getContextClassLoader();
- Thread.currentThread().setContextClassLoader(testApplication.getAugmentClassLoader());
+ Thread.currentThread().setContextClassLoader(testApplication.getOrCreateAugmentClassLoader());
try {
prepared.run();
} finally {
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestConfig.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestConfig.java
index 5c82f54fe447d0..edb4f110f223bb 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestConfig.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestConfig.java
@@ -11,6 +11,8 @@
import io.quarkus.runtime.annotations.ConfigRoot;
/**
+ * Testing
+ *
* This is used currently only to suppress warnings about unknown properties
* when the user supplies something like: -Dquarkus.test.profile=someProfile or -Dquarkus.test.native-image-profile=someProfile
*
@@ -226,6 +228,7 @@ public class TestConfig {
* most parent first classes it will just cause problems.
*/
@ConfigItem(defaultValue = "java\\..*")
+ @Deprecated(forRemoval = true)
String classClonePattern;
/**
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestResult.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestResult.java
index 4250d332492dc1..4f5025391a0b3a 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestResult.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestResult.java
@@ -11,6 +11,7 @@ public class TestResult {
final String displayName;
final String testClass;
+ final List tags;
final UniqueId uniqueId;
final TestExecutionResult testExecutionResult;
final List logOutput;
@@ -20,10 +21,12 @@ public class TestResult {
final List problems;
final boolean reportable;
- public TestResult(String displayName, String testClass, UniqueId uniqueId, TestExecutionResult testExecutionResult,
+ public TestResult(String displayName, String testClass, List tags, UniqueId uniqueId,
+ TestExecutionResult testExecutionResult,
List logOutput, boolean test, long runId, long time, boolean reportable) {
this.displayName = displayName;
this.testClass = testClass;
+ this.tags = tags;
this.uniqueId = uniqueId;
this.testExecutionResult = testExecutionResult;
this.logOutput = logOutput;
@@ -58,6 +61,10 @@ public String getTestClass() {
return testClass;
}
+ public List getTags() {
+ return tags;
+ }
+
public UniqueId getUniqueId() {
return uniqueId;
}
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestSupport.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestSupport.java
index 61bb2d278d1c26..b27ba0042b125a 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestSupport.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestSupport.java
@@ -1,7 +1,6 @@
package io.quarkus.deployment.dev.testing;
import java.io.IOException;
-import java.io.InputStream;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -13,7 +12,6 @@
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
-import java.util.Properties;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicLong;
@@ -42,7 +40,8 @@
import io.quarkus.dev.testing.TestWatchedFiles;
import io.quarkus.maven.dependency.ResolvedDependency;
import io.quarkus.paths.PathList;
-import io.smallrye.config.Converters;
+import io.smallrye.config.SmallRyeConfig;
+import io.smallrye.config.SmallRyeConfigBuilder;
public class TestSupport implements TestController {
@@ -76,13 +75,13 @@ public class TestSupport implements TestController {
private Throwable compileProblem;
private volatile boolean firstRun = true;
- String appPropertiesIncludeTags;
- String appPropertiesExcludeTags;
+ List appPropertiesIncludeTags;
+ List appPropertiesExcludeTags;
String appPropertiesIncludePattern;
String appPropertiesExcludePattern;
- String appPropertiesIncludeEngines;
- String appPropertiesExcludeEngines;
- String appPropertiesTestType;
+ List appPropertiesIncludeEngines;
+ List appPropertiesExcludeEngines;
+ TestType appPropertiesTestType;
private TestConfig config;
private volatile boolean closed;
@@ -222,7 +221,7 @@ public void init() {
+ curatedApplication.getClassLoaderNameSuffix(),
getClass().getClassLoader().getParent(), false);
}
- clBuilder.addElement(ClassPathElement.fromDependency(d));
+ clBuilder.addNormalPriorityElement(ClassPathElement.fromDependency(d));
}
}
@@ -509,90 +508,68 @@ public void addListener(TestListener listener) {
* We also can't apply this as part of the test startup, as it is too
* late and the filters have already been resolved.
*
- * We manually check for application.properties changes and apply them.
+ * We manually check for configuration changes and apply them.
*/
private void handleApplicationPropertiesChange() {
- for (Path rootPath : curatedApplication.getQuarkusBootstrap().getApplicationRoot()) {
- Path appProps = rootPath.resolve("application.properties");
- if (Files.exists(appProps)) {
- Properties p = new Properties();
- try (InputStream in = Files.newInputStream(appProps)) {
- p.load(in);
- } catch (IOException e) {
- throw new RuntimeException(e);
+ SmallRyeConfig updatedConfig = getMinimalConfig();
+
+ List includeTags = getTrimmedListFromConfig(updatedConfig, "quarkus.test.include-tags").orElse(null);
+ List excludeTags = getTrimmedListFromConfig(updatedConfig, "quarkus.test.exclude-tags").orElse(null);
+ String includePattern = updatedConfig.getOptionalValue("quarkus.test.include-pattern", String.class).orElse(null);
+ String excludePattern = updatedConfig.getOptionalValue("quarkus.test.exclude-pattern", String.class).orElse(null);
+ List includeEngines = getTrimmedListFromConfig(updatedConfig, "quarkus.test.include-engines").orElse(null);
+ List excludeEngines = getTrimmedListFromConfig(updatedConfig, "quarkus.test.exclude-engines").orElse(null);
+ TestType testType = updatedConfig.getOptionalValue("quarkus.test.type", TestType.class).orElse(TestType.ALL);
+
+ if (!firstRun) {
+ if (!Objects.equals(includeTags, appPropertiesIncludeTags)) {
+ this.includeTags = Objects.requireNonNullElse(includeTags, Collections.emptyList());
+ }
+ if (!Objects.equals(excludeTags, appPropertiesExcludeTags)) {
+ this.excludeTags = Objects.requireNonNullElse(excludeTags, Collections.emptyList());
+ }
+ if (!Objects.equals(includePattern, appPropertiesIncludePattern)) {
+ if (includePattern == null) {
+ this.include = null;
+ } else {
+ this.include = Pattern.compile(includePattern);
}
- String includeTags = p.getProperty("quarkus.test.include-tags");
- String excludeTags = p.getProperty("quarkus.test.exclude-tags");
- String includePattern = p.getProperty("quarkus.test.include-pattern");
- String excludePattern = p.getProperty("quarkus.test.exclude-pattern");
- String includeEngines = p.getProperty("quarkus.test.include-engines");
- String excludeEngines = p.getProperty("quarkus.test.exclude-engines");
- String testType = p.getProperty("quarkus.test.type");
- if (!firstRun) {
- if (!Objects.equals(includeTags, appPropertiesIncludeTags)) {
- if (includeTags == null) {
- this.includeTags = Collections.emptyList();
- } else {
- this.includeTags = Arrays.stream(includeTags.split(",")).map(String::trim)
- .collect(Collectors.toList());
- }
- }
- if (!Objects.equals(excludeTags, appPropertiesExcludeTags)) {
- if (excludeTags == null) {
- this.excludeTags = Collections.emptyList();
- } else {
- this.excludeTags = Arrays.stream(excludeTags.split(",")).map(String::trim)
- .collect(Collectors.toList());
- }
- }
- if (!Objects.equals(includePattern, appPropertiesIncludePattern)) {
- if (includePattern == null) {
- include = null;
- } else {
- include = Pattern.compile(includePattern);
- }
- }
- if (!Objects.equals(excludePattern, appPropertiesExcludePattern)) {
- if (excludePattern == null) {
- exclude = null;
- } else {
- exclude = Pattern.compile(excludePattern);
- }
- }
- if (!Objects.equals(includeEngines, appPropertiesIncludeEngines)) {
- if (includeEngines == null) {
- this.includeEngines = Collections.emptyList();
- } else {
- this.includeEngines = Arrays.stream(includeEngines.split(",")).map(String::trim)
- .collect(Collectors.toList());
- }
- }
- if (!Objects.equals(excludeEngines, appPropertiesExcludeEngines)) {
- if (excludeEngines == null) {
- this.excludeEngines = Collections.emptyList();
- } else {
- this.excludeEngines = Arrays.stream(excludeEngines.split(",")).map(String::trim)
- .collect(Collectors.toList());
- }
- }
- if (!Objects.equals(testType, appPropertiesTestType)) {
- if (testType == null) {
- this.testType = TestType.ALL;
- } else {
- this.testType = Converters.getImplicitConverter(TestType.class).convert(testType);
- }
- }
+ }
+ if (!Objects.equals(excludePattern, appPropertiesExcludePattern)) {
+ if (excludePattern == null) {
+ this.exclude = null;
+ } else {
+ this.exclude = Pattern.compile(excludePattern);
}
- appPropertiesIncludeTags = includeTags;
- appPropertiesExcludeTags = excludeTags;
- appPropertiesIncludePattern = includePattern;
- appPropertiesExcludePattern = excludePattern;
- appPropertiesIncludeEngines = includeEngines;
- appPropertiesExcludeEngines = excludeEngines;
- appPropertiesTestType = testType;
- break;
+ }
+ if (!Objects.equals(includeEngines, appPropertiesIncludeEngines)) {
+ this.includeEngines = Objects.requireNonNullElse(includeEngines, Collections.emptyList());
+ }
+ if (!Objects.equals(excludeEngines, appPropertiesExcludeEngines)) {
+ this.excludeEngines = Objects.requireNonNullElse(excludeEngines, Collections.emptyList());
+ }
+ if (!Objects.equals(testType, appPropertiesTestType)) {
+ this.testType = testType;
}
}
+
+ appPropertiesIncludeTags = includeTags;
+ appPropertiesExcludeTags = excludeTags;
+ appPropertiesIncludePattern = includePattern;
+ appPropertiesExcludePattern = excludePattern;
+ appPropertiesIncludeEngines = includeEngines;
+ appPropertiesExcludeEngines = excludeEngines;
+ appPropertiesTestType = testType;
+ }
+
+ private static SmallRyeConfig getMinimalConfig() {
+ return new SmallRyeConfigBuilder().addDefaultSources().build();
+ }
+
+ private Optional> getTrimmedListFromConfig(SmallRyeConfig updatedConfig, String property) {
+ return updatedConfig.getOptionalValue(property, String.class)
+ .map(t -> Arrays.stream(t.split(",")).map(String::trim)
+ .collect(Collectors.toList()));
}
public boolean isStarted() {
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestTracingProcessor.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestTracingProcessor.java
index 8ff20a9bcf92da..fead5a43bbdf08 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestTracingProcessor.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestTracingProcessor.java
@@ -25,7 +25,6 @@
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
-import io.quarkus.bootstrap.classloading.ClassPathElement;
import io.quarkus.bootstrap.classloading.QuarkusClassLoader;
import io.quarkus.deployment.IsDevelopment;
import io.quarkus.deployment.IsNormal;
@@ -155,13 +154,8 @@ public ServiceStartBuildItem searchForTags(CombinedIndexBuildItem combinedIndexB
return null;
}
- public boolean isAppClass(String theClassName) {
- QuarkusClassLoader cl = (QuarkusClassLoader) Thread.currentThread()
- .getContextClassLoader();
- //if the class file is present in this (and not the parent) CL then it is an application class
- List res = cl
- .getElementsWithResource(theClassName.replace(".", "/") + ".class", true);
- return !res.isEmpty();
+ public boolean isAppClass(String className) {
+ return QuarkusClassLoader.isApplicationClass(className);
}
public static class TracingClassVisitor extends ClassVisitor {
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/ide/IdeConfig.java b/core/deployment/src/main/java/io/quarkus/deployment/ide/IdeConfig.java
index 4bbc0aa105d52e..f98cf00ca5ab17 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/ide/IdeConfig.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/ide/IdeConfig.java
@@ -3,6 +3,9 @@
import io.quarkus.runtime.annotations.ConfigItem;
import io.quarkus.runtime.annotations.ConfigRoot;
+/**
+ * IDE
+ */
@ConfigRoot
public class IdeConfig {
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/images/ContainerImages.java b/core/deployment/src/main/java/io/quarkus/deployment/images/ContainerImages.java
new file mode 100644
index 00000000000000..7d1be878aa593b
--- /dev/null
+++ b/core/deployment/src/main/java/io/quarkus/deployment/images/ContainerImages.java
@@ -0,0 +1,114 @@
+package io.quarkus.deployment.images;
+
+import io.quarkus.deployment.pkg.builditem.CompiledJavaVersionBuildItem;
+
+/**
+ * This class is used to define the container images that are used by Quarkus.
+ *
+ * For each image, the image name and version are defined as constants:
+ *
+ * - {@code x_IMAGE_NAME} - the name of the image without the version (e.g. {@code registry.access.redhat.com/ubi8/ubi-minimal})
+ * - {@code x_VERSION} - the version of the image (e.g. {@code 8.10})
+ * - {@code x} - the full image name (e.g. {@code registry.access.redhat.com/ubi8/ubi-minimal:8.10})
+ */
+public class ContainerImages {
+
+ // Global versions
+
+ /**
+ * UBI 8 version
+ */
+ public static final String UBI8_VERSION = "8.10";
+
+ /**
+ * UBI 8 version
+ */
+ public static final String UBI9_VERSION = "9.4";
+
+ /**
+ * Version used for more UBI Java images.
+ */
+ public static final String UBI8_JAVA_VERSION = "1.20";
+
+ /**
+ * Version uses for the native builder image.
+ */
+ public static final String NATIVE_BUILDER_VERSION = "jdk-21";
+
+ // === Runtime images for containers (native)
+
+ // UBI 8 Minimal - https://catalog.redhat.com/software/containers/ubi8/ubi-minimal/5c359a62bed8bd75a2c3fba8
+ public static final String UBI8_MINIMAL_IMAGE_NAME = "registry.access.redhat.com/ubi8/ubi-minimal";
+ public static final String UBI8_MINIMAL_VERSION = UBI8_VERSION;
+ public static final String UBI8_MINIMAL = UBI8_MINIMAL_IMAGE_NAME + ":" + UBI8_MINIMAL_VERSION;
+
+ // UBI 9 Minimal - https://catalog.redhat.com/software/containers/ubi9-minimal/61832888c0d15aff4912fe0d
+ public static final String UBI9_MINIMAL_IMAGE_NAME = "registry.access.redhat.com/ubi9/ubi-minimal";
+ public static final String UBI9_MINIMAL_VERSION = UBI9_VERSION;
+ public static final String UBI9_MINIMAL = UBI9_MINIMAL_IMAGE_NAME + ":" + UBI9_MINIMAL_VERSION;
+
+ // Quarkus Micro image - https://quay.io/repository/quarkus/quarkus-micro-image?tab=tags
+ public static final String QUARKUS_MICRO_IMAGE_NAME = "quay.io/quarkus/quarkus-micro-image";
+ public static final String QUARKUS_MICRO_VERSION = "2.0";
+ public static final String QUARKUS_MICRO_IMAGE = QUARKUS_MICRO_IMAGE_NAME + ":" + QUARKUS_MICRO_VERSION;
+
+ // === Runtime images for containers (JVM)
+
+ // UBI 8 OpenJDK 17 Runtime - https://catalog.redhat.com/software/containers/ubi8/openjdk-17-runtime/618bdc5f843af1624c4e4ba8
+ public static final String UBI8_JAVA_17_IMAGE_NAME = "registry.access.redhat.com/ubi8/openjdk-17-runtime";
+ public static final String UBI8_JAVA_17_VERSION = UBI8_JAVA_VERSION;
+ public static final String UBI8_JAVA_17 = UBI8_JAVA_17_IMAGE_NAME + ":" + UBI8_JAVA_17_VERSION;
+
+ // UBI 8 OpenJDK 21 Runtime - https://catalog.redhat.com/software/containers/ubi8/openjdk-21-runtime/653fd184292263c0a2f14d69
+ public static final String UBI8_JAVA_21_IMAGE_NAME = "registry.access.redhat.com/ubi8/openjdk-21-runtime";
+ public static final String UBI8_JAVA_21_VERSION = UBI8_JAVA_VERSION;
+ public static final String UBI8_JAVA_21 = UBI8_JAVA_21_IMAGE_NAME + ":" + UBI8_JAVA_21_VERSION;
+
+ // UBI 9 OpenJDK 17 Runtime - https://catalog.redhat.com/software/containers/ubi9/openjdk-17-runtime/61ee7d45384a3eb331996bee
+ public static final String UBI9_JAVA_17_IMAGE_NAME = "registry.access.redhat.com/ubi9/openjdk-17-runtime";
+ public static final String UBI9_JAVA_17_VERSION = UBI8_JAVA_VERSION;
+ public static final String UBI9_JAVA_17 = UBI9_JAVA_17_IMAGE_NAME + ":" + UBI9_JAVA_17_VERSION;
+
+ // UBI 9 OpenJDK 21 Runtime - https://catalog.redhat.com/software/containers/ubi9/openjdk-21-runtime/6501ce769a0d86945c422d5f
+ public static final String UBI9_JAVA_21_IMAGE_NAME = "registry.access.redhat.com/ubi9/openjdk-21-runtime";
+ public static final String UBI9_JAVA_21_VERSION = UBI8_JAVA_VERSION;
+ public static final String UBI9_JAVA_21 = UBI9_JAVA_21_IMAGE_NAME + ":" + UBI9_JAVA_21_VERSION;
+
+ // === Source To Image images
+
+ // Quarkus Binary Source To Image - https://quay.io/repository/quarkus/ubi-quarkus-native-binary-s2i?tab=tags
+ public static final String QUARKUS_BINARY_S2I_IMAGE_NAME = "quay.io/quarkus/ubi-quarkus-native-binary-s2i";
+ public static final String QUARKUS_BINARY_S2I_VERSION = "2.0";
+ public static final String QUARKUS_BINARY_S2I = QUARKUS_BINARY_S2I_IMAGE_NAME + ":" + QUARKUS_BINARY_S2I_VERSION;
+
+ // Java 17 Source To Image - https://catalog.redhat.com/software/containers/ubi8/openjdk-17/618bdbf34ae3739687568813
+ public static final String S2I_JAVA_17_IMAGE_NAME = "registry.access.redhat.com/ubi8/openjdk-17";
+ public static final String S2I_JAVA_17_VERSION = UBI8_JAVA_VERSION;
+ public static final String S2I_JAVA_17 = S2I_JAVA_17_IMAGE_NAME + ":" + S2I_JAVA_17_VERSION;
+
+ // Java Source To Image - https://catalog.redhat.com/software/containers/ubi8/openjdk-21/653fb7e21b2ec10f7dfc10d0?q=openjdk%2021&architecture=amd64&image=66bcc007a3857fbc34f4dce1
+ public static final String S2I_JAVA_21_IMAGE_NAME = "registry.access.redhat.com/ubi8/openjdk-21";
+ public static final String S2I_JAVA_21_VERSION = UBI8_JAVA_VERSION;
+ public static final String S2I_JAVA_21 = S2I_JAVA_21_IMAGE_NAME + ":" + S2I_JAVA_21_VERSION;
+
+ // === Native Builder images
+
+ // Mandrel Builder Image - https://quay.io/repository/quarkus/ubi-quarkus-mandrel-builder-image?tab=tags
+ public static final String MANDREL_BUILDER_IMAGE_NAME = "quay.io/quarkus/ubi-quarkus-mandrel-builder-image";
+ public static final String MANDREL_BUILDER_VERSION = NATIVE_BUILDER_VERSION;
+ public static final String MANDREL_BUILDER = MANDREL_BUILDER_IMAGE_NAME + ":" + MANDREL_BUILDER_VERSION;
+
+ // GraalVM CE Builder Image - https://quay.io/repository/quarkus/ubi-quarkus-graalvmce-builder-image?tab=tags
+ public static final String GRAALVM_BUILDER_IMAGE_NAME = "quay.io/quarkus/ubi-quarkus-graalvmce-builder-image";
+ public static final String GRAALVM_BUILDER_VERSION = NATIVE_BUILDER_VERSION;
+ public static final String GRAALVM_BUILDER = GRAALVM_BUILDER_IMAGE_NAME + ":" + GRAALVM_BUILDER_VERSION;
+
+ public static String getDefaultJvmImage(CompiledJavaVersionBuildItem.JavaVersion version) {
+ switch (version.isJava21OrHigher()) {
+ case TRUE:
+ return UBI8_JAVA_21;
+ default:
+ return UBI8_JAVA_17;
+ }
+ }
+}
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 285fa0051a1aa0..619976d52461e4 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
@@ -56,6 +56,9 @@ public class ApplicationArchiveBuildStep {
IndexDependencyConfiguration config;
+ /**
+ * Indexing
+ */
@ConfigRoot(phase = ConfigPhase.BUILD_TIME)
static final class IndexDependencyConfiguration {
/**
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/index/IndexWrapper.java b/core/deployment/src/main/java/io/quarkus/deployment/index/IndexWrapper.java
index 03d59b48f2d258..3ad7a589dbb010 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/index/IndexWrapper.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/index/IndexWrapper.java
@@ -1,6 +1,6 @@
package io.quarkus.deployment.index;
-import static io.quarkus.commons.classloading.ClassloadHelper.fromClassNameToResourceName;
+import static io.quarkus.commons.classloading.ClassLoaderHelper.fromClassNameToResourceName;
import java.io.IOException;
import java.io.InputStream;
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 f0289037eea196..9d94bcac054817 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
@@ -40,104 +40,109 @@ public class JBangAugmentorImpl implements BiConsumer resultMap) {
- QuarkusClassLoader classLoader = curatedApplication.getAugmentClassLoader();
+ QuarkusClassLoader classLoader = curatedApplication.getOrCreateAugmentClassLoader();
- QuarkusBootstrap quarkusBootstrap = curatedApplication.getQuarkusBootstrap();
- QuarkusAugmentor.Builder builder = QuarkusAugmentor.builder()
- .setRoot(quarkusBootstrap.getApplicationRoot())
- .setClassLoader(classLoader)
- .addFinal(ApplicationClassNameBuildItem.class)
- .setTargetDir(quarkusBootstrap.getTargetDirectory())
- .setDeploymentClassLoader(curatedApplication.createDeploymentClassLoader())
- .setBuildSystemProperties(quarkusBootstrap.getBuildSystemProperties())
- .setEffectiveModel(curatedApplication.getApplicationModel());
- if (quarkusBootstrap.getBaseName() != null) {
- builder.setBaseName(quarkusBootstrap.getBaseName());
- }
- if (quarkusBootstrap.getOriginalBaseName() != null) {
- builder.setOriginalBaseName(quarkusBootstrap.getOriginalBaseName());
- }
-
- boolean auxiliaryApplication = curatedApplication.getQuarkusBootstrap().isAuxiliaryApplication();
- builder.setAuxiliaryApplication(auxiliaryApplication);
- builder.setAuxiliaryDevModeType(
- curatedApplication.getQuarkusBootstrap().isHostApplicationIsTestOnly() ? DevModeType.TEST_ONLY
- : (auxiliaryApplication ? DevModeType.LOCAL : null));
- builder.setLaunchMode(LaunchMode.NORMAL);
- builder.setRebuild(quarkusBootstrap.isRebuild());
- builder.setLiveReloadState(
- new LiveReloadBuildItem(false, Collections.emptySet(), new HashMap<>(), null));
- for (AdditionalDependency i : quarkusBootstrap.getAdditionalApplicationArchives()) {
- //this gets added to the class path either way
- //but we only need to add it to the additional app archives
- //if it is forced as an app archive
- if (i.isForceApplicationArchive()) {
- builder.addAdditionalApplicationArchive(i.getResolvedPaths());
+ try (QuarkusClassLoader deploymentClassLoader = curatedApplication.createDeploymentClassLoader()) {
+ QuarkusBootstrap quarkusBootstrap = curatedApplication.getQuarkusBootstrap();
+ QuarkusAugmentor.Builder builder = QuarkusAugmentor.builder()
+ .setRoot(quarkusBootstrap.getApplicationRoot())
+ .setClassLoader(classLoader)
+ .addFinal(ApplicationClassNameBuildItem.class)
+ .setTargetDir(quarkusBootstrap.getTargetDirectory())
+ .setDeploymentClassLoader(curatedApplication.createDeploymentClassLoader())
+ .setBuildSystemProperties(quarkusBootstrap.getBuildSystemProperties())
+ .setRuntimeProperties(quarkusBootstrap.getRuntimeProperties())
+ .setEffectiveModel(curatedApplication.getApplicationModel());
+ if (quarkusBootstrap.getBaseName() != null) {
+ builder.setBaseName(quarkusBootstrap.getBaseName());
}
- }
- builder.addBuildChainCustomizer(new Consumer() {
- @Override
- public void accept(BuildChainBuilder builder) {
- final BuildStepBuilder stepBuilder = builder.addBuildStep((ctx) -> {
- ctx.produce(new ProcessInheritIODisabledBuildItem());
- });
- stepBuilder.produces(ProcessInheritIODisabledBuildItem.class).build();
+ if (quarkusBootstrap.getOriginalBaseName() != null) {
+ builder.setOriginalBaseName(quarkusBootstrap.getOriginalBaseName());
}
- });
- builder.excludeFromIndexing(quarkusBootstrap.getExcludeFromClassPath());
- builder.addFinal(GeneratedClassBuildItem.class);
- builder.addFinal(MainClassBuildItem.class);
- builder.addFinal(GeneratedResourceBuildItem.class);
- builder.addFinal(TransformedClassesBuildItem.class);
- builder.addFinal(DeploymentResultBuildItem.class);
- // note: quarkus.package.type is deprecated
- boolean nativeRequested = "native".equals(System.getProperty("quarkus.package.type"))
- || "true".equals(System.getProperty("quarkus.native.enabled"));
- boolean containerBuildRequested = Boolean.getBoolean("quarkus.container-image.build");
- if (nativeRequested) {
- builder.addFinal(NativeImageBuildItem.class);
- }
- if (containerBuildRequested) {
- //TODO: this is a bit ugly
- //we don't necessarily need these artifacts
- //but if we include them it does mean that you can auto create docker images
- //and deploy to kube etc
- //for an ordinary build with no native and no docker this is a waste
- builder.addFinal(ArtifactResultBuildItem.class);
- }
- try {
- BuildResult buildResult = builder.build().run();
- Map result = new HashMap<>();
- for (GeneratedClassBuildItem i : buildResult.consumeMulti(GeneratedClassBuildItem.class)) {
- result.put(i.getName().replace(".", "/") + ".class", i.getClassData());
+ boolean auxiliaryApplication = curatedApplication.getQuarkusBootstrap().isAuxiliaryApplication();
+ builder.setAuxiliaryApplication(auxiliaryApplication);
+ builder.setAuxiliaryDevModeType(
+ curatedApplication.getQuarkusBootstrap().isHostApplicationIsTestOnly() ? DevModeType.TEST_ONLY
+ : (auxiliaryApplication ? DevModeType.LOCAL : null));
+ builder.setLaunchMode(LaunchMode.NORMAL);
+ builder.setRebuild(quarkusBootstrap.isRebuild());
+ builder.setLiveReloadState(
+ new LiveReloadBuildItem(false, Collections.emptySet(), new HashMap<>(), null));
+ for (AdditionalDependency i : quarkusBootstrap.getAdditionalApplicationArchives()) {
+ //this gets added to the class path either way
+ //but we only need to add it to the additional app archives
+ //if it is forced as an app archive
+ if (i.isForceApplicationArchive()) {
+ builder.addAdditionalApplicationArchive(i.getResolvedPaths());
+ }
+ }
+ builder.addBuildChainCustomizer(new Consumer() {
+ @Override
+ public void accept(BuildChainBuilder builder) {
+ final BuildStepBuilder stepBuilder = builder.addBuildStep((ctx) -> {
+ ctx.produce(new ProcessInheritIODisabledBuildItem());
+ });
+ stepBuilder.produces(ProcessInheritIODisabledBuildItem.class).build();
+ }
+ });
+ builder.excludeFromIndexing(quarkusBootstrap.getExcludeFromClassPath());
+ builder.addFinal(GeneratedClassBuildItem.class);
+ builder.addFinal(MainClassBuildItem.class);
+ builder.addFinal(GeneratedResourceBuildItem.class);
+ builder.addFinal(TransformedClassesBuildItem.class);
+ builder.addFinal(DeploymentResultBuildItem.class);
+ // note: quarkus.package.type is deprecated
+ boolean nativeRequested = "native".equals(System.getProperty("quarkus.package.type"))
+ || "true".equals(System.getProperty("quarkus.native.enabled"));
+ boolean containerBuildRequested = Boolean.getBoolean("quarkus.container-image.build");
+ if (nativeRequested) {
+ builder.addFinal(NativeImageBuildItem.class);
}
- for (GeneratedResourceBuildItem i : buildResult.consumeMulti(GeneratedResourceBuildItem.class)) {
- result.put(i.getName(), i.getData());
+ if (containerBuildRequested) {
+ //TODO: this is a bit ugly
+ //we don't necessarily need these artifacts
+ //but if we include them it does mean that you can auto create docker images
+ //and deploy to kube etc
+ //for an ordinary build with no native and no docker this is a waste
+ builder.addFinal(ArtifactResultBuildItem.class);
}
- for (Map.Entry> entry : buildResult
- .consume(TransformedClassesBuildItem.class).getTransformedClassesByJar().entrySet()) {
- for (TransformedClassesBuildItem.TransformedClass transformed : entry.getValue()) {
- if (transformed.getData() != null) {
- result.put(transformed.getFileName(), transformed.getData());
- } else {
- log.warn("Unable to remove resource " + transformed.getFileName()
- + " as this is not supported in JBangf");
+
+ try {
+ BuildResult buildResult = builder.build().run();
+ Map result = new HashMap<>();
+ for (GeneratedClassBuildItem i : buildResult.consumeMulti(GeneratedClassBuildItem.class)) {
+ result.put(i.getName().replace(".", "/") + ".class", i.getClassData());
+ }
+ for (GeneratedResourceBuildItem i : buildResult.consumeMulti(GeneratedResourceBuildItem.class)) {
+ result.put(i.getName(), i.getData());
+ }
+ for (Map.Entry> entry : buildResult
+ .consume(TransformedClassesBuildItem.class).getTransformedClassesByJar().entrySet()) {
+ for (TransformedClassesBuildItem.TransformedClass transformed : entry.getValue()) {
+ if (transformed.getData() != null) {
+ result.put(transformed.getFileName(), transformed.getData());
+ } else {
+ log.warn("Unable to remove resource " + transformed.getFileName()
+ + " as this is not supported in JBangf");
+ }
}
}
+ resultMap.put("files", result);
+ final List javaargs = new ArrayList<>();
+ javaargs.add("-Djava.util.logging.manager=org.jboss.logmanager.LogManager");
+ javaargs.add(
+ "-Djava.util.concurrent.ForkJoinPool.common.threadFactory=io.quarkus.bootstrap.forkjoin.QuarkusForkJoinWorkerThreadFactory");
+ resultMap.put("java-args", javaargs);
+ resultMap.put("main-class", buildResult.consume(MainClassBuildItem.class).getClassName());
+ if (nativeRequested) {
+ resultMap.put("native-image", buildResult.consume(NativeImageBuildItem.class).getPath());
+ }
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
}
- resultMap.put("files", result);
- final List javaargs = new ArrayList<>();
- javaargs.add("-Djava.util.logging.manager=org.jboss.logmanager.LogManager");
- javaargs.add(
- "-Djava.util.concurrent.ForkJoinPool.common.threadFactory=io.quarkus.bootstrap.forkjoin.QuarkusForkJoinWorkerThreadFactory");
- resultMap.put("java-args", javaargs);
- resultMap.put("main-class", buildResult.consume(MainClassBuildItem.class).getClassName());
- if (nativeRequested) {
- resultMap.put("native-image", buildResult.consume(NativeImageBuildItem.class).getPath());
- }
- } catch (Exception e) {
- throw new RuntimeException(e);
}
}
}
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/logging/LoggingDecorateBuildItem.java b/core/deployment/src/main/java/io/quarkus/deployment/logging/LoggingDecorateBuildItem.java
new file mode 100644
index 00000000000000..500a84f90b0f17
--- /dev/null
+++ b/core/deployment/src/main/java/io/quarkus/deployment/logging/LoggingDecorateBuildItem.java
@@ -0,0 +1,45 @@
+package io.quarkus.deployment.logging;
+
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.jboss.jandex.ClassInfo;
+import org.jboss.jandex.CompositeIndex;
+
+import io.quarkus.builder.item.SimpleBuildItem;
+
+/**
+ * Contains information to decorate the Log output. Can be used by extensions that output the log / stacktraces,
+ * for example the error page.
+ *
+ * Also see io.quarkus.runtime.logging.DecorateStackUtil to assist with the decoration
+ */
+public final class LoggingDecorateBuildItem extends SimpleBuildItem {
+ private final Path srcMainJava;
+ private final CompositeIndex knowClassesIndex;
+
+ public LoggingDecorateBuildItem(Path srcMainJava, CompositeIndex knowClassesIndex) {
+ this.srcMainJava = srcMainJava;
+ this.knowClassesIndex = knowClassesIndex;
+ }
+
+ public Path getSrcMainJava() {
+ return srcMainJava;
+ }
+
+ public CompositeIndex getKnowClassesIndex() {
+ return knowClassesIndex;
+ }
+
+ public List getKnowClasses() {
+ List knowClasses = new ArrayList<>();
+ Collection knownClasses = knowClassesIndex.getKnownClasses();
+ for (ClassInfo ci : knownClasses) {
+ knowClasses.add(ci.name().toString());
+ }
+ return knowClasses;
+ }
+
+}
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/logging/LoggingResourceProcessor.java b/core/deployment/src/main/java/io/quarkus/deployment/logging/LoggingResourceProcessor.java
index 4bc1ee15c7e94f..cec9fc34fd9e15 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/logging/LoggingResourceProcessor.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/logging/LoggingResourceProcessor.java
@@ -1,7 +1,10 @@
package io.quarkus.deployment.logging;
import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
@@ -39,12 +42,15 @@
import org.jboss.jandex.DotName;
import org.jboss.jandex.IndexView;
import org.jboss.logging.Logger;
+import org.jboss.logmanager.ExtLogRecord;
import org.jboss.logmanager.LogContextInitializer;
import org.jboss.logmanager.LogManager;
import org.objectweb.asm.Opcodes;
import io.quarkus.bootstrap.classloading.QuarkusClassLoader;
import io.quarkus.bootstrap.logging.InitialConfigurator;
+import io.quarkus.bootstrap.model.ApplicationModel;
+import io.quarkus.bootstrap.workspace.WorkspaceModule;
import io.quarkus.deployment.ApplicationArchive;
import io.quarkus.deployment.GeneratedClassGizmoAdaptor;
import io.quarkus.deployment.IsNormal;
@@ -86,6 +92,8 @@
import io.quarkus.deployment.metrics.MetricsCapabilityBuildItem;
import io.quarkus.deployment.metrics.MetricsFactoryConsumerBuildItem;
import io.quarkus.deployment.pkg.builditem.BuildSystemTargetBuildItem;
+import io.quarkus.deployment.pkg.builditem.CurateOutcomeBuildItem;
+import io.quarkus.deployment.pkg.builditem.OutputTargetBuildItem;
import io.quarkus.deployment.pkg.steps.NativeOrNativeSourcesBuild;
import io.quarkus.deployment.recording.RecorderContext;
import io.quarkus.deployment.util.JandexUtil;
@@ -102,11 +110,13 @@
import io.quarkus.gizmo.MethodDescriptor;
import io.quarkus.gizmo.ResultHandle;
import io.quarkus.logging.LoggingFilter;
+import io.quarkus.runtime.LaunchMode;
import io.quarkus.runtime.RuntimeValue;
import io.quarkus.runtime.configuration.ConfigInstantiator;
import io.quarkus.runtime.console.ConsoleRuntimeConfig;
import io.quarkus.runtime.logging.CategoryBuildTimeConfig;
import io.quarkus.runtime.logging.CleanupFilterConfig;
+import io.quarkus.runtime.logging.DecorateStackUtil;
import io.quarkus.runtime.logging.DiscoveredLogComponents;
import io.quarkus.runtime.logging.InheritableLevel;
import io.quarkus.runtime.logging.LogBuildTimeConfig;
@@ -215,6 +225,7 @@ void miscSetup(
Consumer provider) {
runtimeInit.accept(new RuntimeReinitializedClassBuildItem(ConsoleHandler.class.getName()));
runtimeInit.accept(new RuntimeReinitializedClassBuildItem("io.smallrye.common.ref.References$ReaperThread"));
+ runtimeInit.accept(new RuntimeReinitializedClassBuildItem("io.smallrye.common.os.Process"));
systemProp
.accept(new NativeImageSystemPropertyBuildItem("java.util.logging.manager", "org.jboss.logmanager.LogManager"));
provider.accept(
@@ -282,7 +293,7 @@ LoggingSetupBuildItem setupLoggingRuntimeInit(RecorderContext context, LoggingSe
if (!discoveredLogComponents.getNameToFilterClass().isEmpty()) {
reflectiveClassBuildItemBuildProducer.produce(
ReflectiveClassBuildItem.builder(discoveredLogComponents.getNameToFilterClass().values().toArray(
- EMPTY_STRING_ARRAY)).build());
+ EMPTY_STRING_ARRAY)).reason(getClass().getName()).build());
serviceProviderBuildItemBuildProducer
.produce(ServiceProviderBuildItem.allProvidersFromClassPath(LogFilterFactory.class.getName()));
}
@@ -370,14 +381,25 @@ private DiscoveredLogComponents discoverLogComponents(IndexView index) {
void setupStackTraceFormatter(ApplicationArchivesBuildItem item, EffectiveIdeBuildItem ideSupport,
BuildSystemTargetBuildItem buildSystemTargetBuildItem,
List exceptionNotificationBuildItems,
- CuratedApplicationShutdownBuildItem curatedApplicationShutdownBuildItem) {
+ CuratedApplicationShutdownBuildItem curatedApplicationShutdownBuildItem,
+ CurateOutcomeBuildItem curateOutcomeBuildItem,
+ OutputTargetBuildItem outputTargetBuildItem,
+ LaunchModeBuildItem launchMode,
+ LogBuildTimeConfig logBuildTimeConfig,
+ BuildProducer loggingDecorateProducer) {
List indexList = new ArrayList<>();
for (ApplicationArchive i : item.getAllApplicationArchives()) {
if (i.getResolvedPaths().isSinglePath() && Files.isDirectory(i.getResolvedPaths().getSinglePath())) {
indexList.add(i.getIndex());
}
}
+ Path srcMainJava = getSourceRoot(curateOutcomeBuildItem.getApplicationModel(),
+ outputTargetBuildItem.getOutputDirectory());
+
CompositeIndex index = CompositeIndex.create(indexList);
+
+ loggingDecorateProducer.produce(new LoggingDecorateBuildItem(srcMainJava, index));
+
//awesome/horrible hack
//we know from the index which classes are part of the current application
//we add ANSI codes for bold and underline to their names to display them more prominently
@@ -393,6 +415,47 @@ public void accept(LogRecord logRecord, Consumer logRecordConsumer) {
var elem = stackTrace[i];
if (index.getClassByName(DotName.createSimple(elem.getClassName())) != null) {
lastUserCode = stackTrace[i];
+
+ if (launchMode.getLaunchMode().equals(LaunchMode.DEVELOPMENT)
+ && logBuildTimeConfig.decorateStacktraces) {
+
+ String decoratedString = DecorateStackUtil.getDecoratedString(srcMainJava, elem);
+ if (decoratedString != null) {
+ if (logRecord instanceof ExtLogRecord elr) {
+ switch (elr.getFormatStyle()) {
+ case MESSAGE_FORMAT -> {
+ Object[] p = elr.getParameters(); // can be null
+ Object[] np = p != null ? Arrays.copyOf(p, p.length + 1) : new Object[1];
+ np[np.length - 1] = decoratedString;
+ elr.setParameters(np);
+ elr.setMessage(elr.getMessage() + "\n\n{" + (np.length - 1) + "}\n\n");
+ }
+ case PRINTF -> {
+ Object[] p = elr.getParameters(); // can be null
+ Object[] np = p != null ? Arrays.copyOf(p, p.length + 1) : new Object[1];
+ np[np.length - 1] = decoratedString;
+ elr.setParameters(np);
+ elr.setMessage(elr.getMessage() + "\n\n%" + (np.length - 1) + "$s",
+ ExtLogRecord.FormatStyle.PRINTF);
+ }
+ case NO_FORMAT -> {
+ elr.setParameters(new Object[] {
+ elr.getMessage(),
+ decoratedString
+ });
+ elr.setMessage("{0}\n\n{1}\n\n");
+ }
+ }
+ } else {
+ Object[] p = logRecord.getParameters(); // can be null
+ Object[] np = p != null ? Arrays.copyOf(p, p.length + 1) : new Object[1];
+ np[np.length - 1] = decoratedString;
+ logRecord.setParameters(np);
+ logRecord.setMessage(logRecord.getMessage() + "\n\n{" + (np.length - 1) + "}\n\n");
+ }
+ }
+ }
+
stackTrace[i] = new StackTraceElement(elem.getClassLoaderName(), elem.getModuleName(),
elem.getModuleVersion(),
MessageFormat.UNDERLINE + MessageFormat.BOLD + elem.getClassName()
@@ -665,6 +728,24 @@ ConsoleCommandBuildItem logConsoleCommand() {
return new ConsoleCommandBuildItem(new LogCommand());
}
+ private Path getSourceRoot(ApplicationModel applicationModel, Path target) {
+ WorkspaceModule workspaceModule = applicationModel.getAppArtifact().getWorkspaceModule();
+ if (workspaceModule != null) {
+ return workspaceModule.getModuleDir().toPath().resolve(SRC_MAIN_JAVA);
+ }
+
+ if (target != null) {
+ var baseDir = target.getParent();
+ if (baseDir == null) {
+ baseDir = target;
+ }
+ return baseDir.resolve(SRC_MAIN_JAVA);
+ }
+ return Paths.get(SRC_MAIN_JAVA);
+ }
+
+ private static final String SRC_MAIN_JAVA = "src/main/java";
+
@GroupCommandDefinition(name = "log", description = "Logging Commands")
public static class LogCommand implements GroupCommand {
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/naming/NamingConfig.java b/core/deployment/src/main/java/io/quarkus/deployment/naming/NamingConfig.java
index 976482c146f3f4..e764ec31c1daf2 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/naming/NamingConfig.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/naming/NamingConfig.java
@@ -3,6 +3,9 @@
import io.quarkus.runtime.annotations.ConfigItem;
import io.quarkus.runtime.annotations.ConfigRoot;
+/**
+ * Naming
+ */
@ConfigRoot
public class NamingConfig {
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/pkg/NativeConfig.java b/core/deployment/src/main/java/io/quarkus/deployment/pkg/NativeConfig.java
index 310090fd7c1eeb..12c4728038d71a 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/pkg/NativeConfig.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/pkg/NativeConfig.java
@@ -5,6 +5,7 @@
import java.util.Optional;
import java.util.OptionalInt;
+import io.quarkus.deployment.images.ContainerImages;
import io.quarkus.deployment.util.ContainerRuntimeUtil;
import io.quarkus.runtime.annotations.ConfigDocDefault;
import io.quarkus.runtime.annotations.ConfigGroup;
@@ -16,13 +17,13 @@
import io.smallrye.config.WithDefault;
import io.smallrye.config.WithParentName;
+/**
+ * Native executables
+ */
@ConfigRoot(phase = ConfigPhase.BUILD_TIME)
@ConfigMapping(prefix = "quarkus.native")
public interface NativeConfig {
- String DEFAULT_GRAALVM_BUILDER_IMAGE = "quay.io/quarkus/ubi-quarkus-graalvmce-builder-image:jdk-21";
- String DEFAULT_MANDREL_BUILDER_IMAGE = "quay.io/quarkus/ubi-quarkus-mandrel-builder-image:jdk-21";
-
/**
* Set to enable native-image building using GraalVM.
*/
@@ -122,7 +123,12 @@ public interface NativeConfig {
String fileEncoding();
/**
- * If all character sets should be added to the native image. This increases image size
+ * If all character sets should be added to the native executable.
+ *
+ * Note that some extensions (e.g. the Oracle JDBC driver) also take this setting into account to enable support for all
+ * charsets at the extension level.
+ *
+ * This increases image size.
*/
@WithDefault("false")
boolean addAllCharsets();
@@ -270,9 +276,9 @@ interface BuilderImageConfig {
default String getEffectiveImage() {
final String builderImageName = this.image().toUpperCase();
if (builderImageName.equals(BuilderImageProvider.GRAALVM.name())) {
- return DEFAULT_GRAALVM_BUILDER_IMAGE;
+ return ContainerImages.GRAALVM_BUILDER;
} else if (builderImageName.equals(BuilderImageProvider.MANDREL.name())) {
- return DEFAULT_MANDREL_BUILDER_IMAGE;
+ return ContainerImages.MANDREL_BUILDER;
} else {
return this.image();
}
@@ -337,6 +343,11 @@ default String getEffectiveImage() {
* If errors should be reported at runtime. This is a more relaxed setting, however it is not recommended as it
* means
* your application may fail at runtime if an unsupported feature is used by accident.
+ *
+ * Note that the use of this flag may result in build time failures due to {@code ClassNotFoundException}s.
+ * Reason most likely being that the Quarkus extension already optimized it away or do not actually need it.
+ * In such cases you should explicitly add the corresponding dependency providing the missing classes as a
+ * dependency to your project.
*/
@WithDefault("false")
boolean reportErrorsAtRuntime();
@@ -481,11 +492,30 @@ interface Debug {
@WithDefault("false")
boolean enableDashboardDump();
+ /**
+ * Include a reasons entries in the generated json configuration files.
+ */
+ @WithDefault("false")
+ boolean includeReasonsInConfigFiles();
+
/**
* Configure native executable compression using UPX.
*/
Compression compression();
+ /**
+ * Configuration files generated by the Quarkus build, using native image agent, are informative by default.
+ * In other words, the generated configuration files are presented in the build log but are not applied.
+ * When this option is set to true, generated configuration files are applied to the native executable building process.
+ *
+ * Enabling this option should be done with care, because it can make native image configuration and/or behaviour
+ * dependant on other non-obvious factors. For example, if the native image agent generated configuration was generated
+ * from running JVM unit tests, disabling test(s) can result in a different native image configuration being generated,
+ * which in turn can misconfigure the native executable or affect its behaviour in unintended ways.
+ */
+ @WithDefault("false")
+ boolean agentConfigurationApply();
+
@ConfigGroup
interface Compression {
/**
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/pkg/PackageConfig.java b/core/deployment/src/main/java/io/quarkus/deployment/pkg/PackageConfig.java
index 57c9f320391135..0e7594bf521a5f 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/pkg/PackageConfig.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/pkg/PackageConfig.java
@@ -16,6 +16,8 @@
import io.smallrye.config.WithDefault;
/**
+ * Packaging the application
+ *
* Configuration relating to creating a packaged output.
*/
@ConfigMapping(prefix = "quarkus.package")
@@ -344,11 +346,19 @@ public static JarType fromString(String value) {
@ConfigGroup
interface DecompilerConfig {
/**
- * Enable decompilation of generated and transformed bytecode into the `decompiled` directory.
+ * Enable decompilation of generated and transformed bytecode into a filesystem.
*/
@WithDefault("false")
boolean enabled();
+ /**
+ * The directory into which to save the decompilation output.
+ *
+ * A relative path is understood as relative to the build directory.
+ */
+ @WithDefault("decompiler")
+ String outputDirectory();
+
/**
* The directory into which to save the decompilation tool if it doesn't exist locally.
*/
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/pkg/builditem/ArtifactResultBuildItem.java b/core/deployment/src/main/java/io/quarkus/deployment/pkg/builditem/ArtifactResultBuildItem.java
index a96468ab8b83ae..1c1b60fafc88b1 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/pkg/builditem/ArtifactResultBuildItem.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/pkg/builditem/ArtifactResultBuildItem.java
@@ -4,6 +4,7 @@
import java.util.Map;
import io.quarkus.builder.item.MultiBuildItem;
+import io.quarkus.sbom.ApplicationManifestConfig;
/**
* Represents a runnable artifact, such as an uberjar or thin jar.
@@ -17,11 +18,18 @@ public final class ArtifactResultBuildItem extends MultiBuildItem {
private final Path path;
private final String type;
private final Map metadata;
+ private final ApplicationManifestConfig manifestConfig;
public ArtifactResultBuildItem(Path path, String type, Map metadata) {
+ this(path, type, metadata, null);
+ }
+
+ public ArtifactResultBuildItem(Path path, String type, Map metadata,
+ ApplicationManifestConfig manifestConfig) {
this.path = path;
this.type = type;
this.metadata = metadata;
+ this.manifestConfig = manifestConfig;
}
public Path getPath() {
@@ -32,6 +40,10 @@ public String getType() {
return type;
}
+ public ApplicationManifestConfig getManifestConfig() {
+ return manifestConfig;
+ }
+
public Map getMetadata() {
return metadata;
}
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/pkg/builditem/JarBuildItem.java b/core/deployment/src/main/java/io/quarkus/deployment/pkg/builditem/JarBuildItem.java
index 8eb4a30d84d435..ba5a0e5601bb37 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/pkg/builditem/JarBuildItem.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/pkg/builditem/JarBuildItem.java
@@ -3,10 +3,13 @@
import static io.quarkus.deployment.pkg.PackageConfig.JarConfig.JarType.*;
import java.nio.file.Path;
+import java.util.Collection;
import io.quarkus.bootstrap.app.JarResult;
+import io.quarkus.bootstrap.app.SbomResult;
import io.quarkus.builder.item.SimpleBuildItem;
import io.quarkus.deployment.pkg.PackageConfig;
+import io.quarkus.sbom.ApplicationManifestConfig;
public final class JarBuildItem extends SimpleBuildItem {
@@ -15,14 +18,21 @@ public final class JarBuildItem extends SimpleBuildItem {
private final Path libraryDir;
private final PackageConfig.JarConfig.JarType type;
private final String classifier;
+ private final ApplicationManifestConfig manifestConfig;
public JarBuildItem(Path path, Path originalArtifact, Path libraryDir, PackageConfig.JarConfig.JarType type,
String classifier) {
+ this(path, originalArtifact, libraryDir, type, classifier, null);
+ }
+
+ public JarBuildItem(Path path, Path originalArtifact, Path libraryDir, PackageConfig.JarConfig.JarType type,
+ String classifier, ApplicationManifestConfig manifestConfig) {
this.path = path;
this.originalArtifact = originalArtifact;
this.libraryDir = libraryDir;
this.type = type;
this.classifier = classifier;
+ this.manifestConfig = manifestConfig;
}
public boolean isUberJar() {
@@ -49,8 +59,16 @@ public String getClassifier() {
return classifier;
}
+ public ApplicationManifestConfig getManifestConfig() {
+ return manifestConfig;
+ }
+
public JarResult toJarResult() {
+ return toJarResult(null);
+ }
+
+ public JarResult toJarResult(Collection sboms) {
return new JarResult(path, originalArtifact, libraryDir, type == MUTABLE_JAR,
- classifier);
+ classifier, sboms);
}
}
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/pkg/builditem/NativeImageBuildItem.java b/core/deployment/src/main/java/io/quarkus/deployment/pkg/builditem/NativeImageBuildItem.java
index 8a140099907ff5..24c78b3f2c2784 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/pkg/builditem/NativeImageBuildItem.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/pkg/builditem/NativeImageBuildItem.java
@@ -10,10 +10,12 @@ public final class NativeImageBuildItem extends SimpleBuildItem {
private final Path path;
private final GraalVMVersion graalVMVersion;
+ private final boolean reused;
- public NativeImageBuildItem(Path path, GraalVMVersion graalVMVersion) {
+ public NativeImageBuildItem(Path path, GraalVMVersion graalVMVersion, boolean reused) {
this.path = path;
this.graalVMVersion = graalVMVersion;
+ this.reused = reused;
}
public Path getPath() {
@@ -24,6 +26,10 @@ public GraalVMVersion getGraalVMInfo() {
return graalVMVersion;
}
+ public boolean isReused() {
+ return reused;
+ }
+
public static class GraalVMVersion {
private final String fullVersion;
private final String version;
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/GraalVM.java b/core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/GraalVM.java
index 734575f2f0333b..2aa16d5165c0c7 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/GraalVM.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/GraalVM.java
@@ -15,6 +15,7 @@ public final class GraalVM {
// Implements version parsing after https://github.com/oracle/graal/pull/6302
static final class VersionParseHelper {
+ private static final String EA_BUILD_PREFIX = "-ea";
private static final String JVMCI_BUILD_PREFIX = "jvmci-";
private static final String MANDREL_VERS_PREFIX = "Mandrel-";
@@ -103,11 +104,10 @@ private static String libericaVersion(String vendorVersion) {
if (vendorVersion == null) {
return null;
}
- int idx = vendorVersion.indexOf(LIBERICA_NIK_VERS_PREFIX);
- if (idx < 0) {
+ final String version = buildVersion(vendorVersion, LIBERICA_NIK_VERS_PREFIX);
+ if (version == null) {
return null;
}
- String version = vendorVersion.substring(idx + LIBERICA_NIK_VERS_PREFIX.length());
return matchVersion(version);
}
@@ -122,11 +122,10 @@ private static String mandrelVersion(String vendorVersion) {
if (vendorVersion == null) {
return null;
}
- int idx = vendorVersion.indexOf(MANDREL_VERS_PREFIX);
- if (idx < 0) {
+ final String version = buildVersion(vendorVersion, MANDREL_VERS_PREFIX);
+ if (version == null) {
return null;
}
- String version = vendorVersion.substring(idx + MANDREL_VERS_PREFIX.length());
return matchVersion(version);
}
@@ -142,11 +141,13 @@ private static String graalVersion(String buildInfo, int jdkFeature) {
if (buildInfo == null) {
return null;
}
- int idx = buildInfo.indexOf(JVMCI_BUILD_PREFIX);
- if (idx < 0) {
- return null;
+ String version = buildVersion(buildInfo, JVMCI_BUILD_PREFIX);
+ if (version == null) {
+ version = buildVersion(buildInfo, EA_BUILD_PREFIX);
+ if (version == null) {
+ return null;
+ }
}
- String version = buildInfo.substring(idx + JVMCI_BUILD_PREFIX.length());
Matcher versMatcher = VERSION_PATTERN.matcher(version);
if (versMatcher.find()) {
return matchVersion(version);
@@ -154,6 +155,14 @@ private static String graalVersion(String buildInfo, int jdkFeature) {
return GRAAL_MAPPING.get(jdkFeature);
}
}
+
+ private static String buildVersion(String buildInfo, String buildPrefix) {
+ int idx = buildInfo.indexOf(buildPrefix);
+ if (idx < 0) {
+ return null;
+ }
+ return buildInfo.substring(idx + buildPrefix.length());
+ }
}
// Temporarily work around https://github.com/quarkusio/quarkus/issues/36246,
@@ -161,8 +170,8 @@ private static String graalVersion(String buildInfo, int jdkFeature) {
// https://github.com/quarkusio/quarkus/issues/34161
private static final Map GRAAL_MAPPING = Map.of(22, "24.0",
23, "24.1",
- 24, "25.0",
- 25, "25.1");
+ 24, "24.2",
+ 25, "25.0");
public static final class Version implements Comparable {
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 5f37c1a83446de..fdf1ed22632daa 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
@@ -1,7 +1,9 @@
package io.quarkus.deployment.pkg.steps;
-import static io.quarkus.commons.classloading.ClassloadHelper.fromClassNameToResourceName;
-import static io.quarkus.deployment.pkg.PackageConfig.JarConfig.JarType.*;
+import static io.quarkus.commons.classloading.ClassLoaderHelper.fromClassNameToResourceName;
+import static io.quarkus.deployment.pkg.PackageConfig.JarConfig.JarType.LEGACY_JAR;
+import static io.quarkus.deployment.pkg.PackageConfig.JarConfig.JarType.MUTABLE_JAR;
+import static io.quarkus.deployment.pkg.PackageConfig.JarConfig.JarType.UBER_JAR;
import java.io.BufferedInputStream;
import java.io.BufferedWriter;
@@ -86,8 +88,11 @@
import io.quarkus.maven.dependency.DependencyFlags;
import io.quarkus.maven.dependency.GACT;
import io.quarkus.maven.dependency.ResolvedDependency;
+import io.quarkus.maven.dependency.ResolvedDependencyBuilder;
import io.quarkus.paths.PathVisit;
import io.quarkus.paths.PathVisitor;
+import io.quarkus.sbom.ApplicationComponent;
+import io.quarkus.sbom.ApplicationManifestConfig;
import io.quarkus.utilities.JavaBinFinder;
/**
@@ -154,7 +159,7 @@ public boolean test(String path) {
public static final String DEFAULT_FAST_JAR_DIRECTORY_NAME = "quarkus-app";
public static final String MP_CONFIG_FILE = "META-INF/microprofile-config.properties";
- private static final String VINEFLOWER_VERSION = "1.9.3";
+ private static final String VINEFLOWER_VERSION = "1.10.1";
@BuildStep
OutputTargetBuildItem outputTarget(BuildSystemTargetBuildItem bst, PackageConfig packageConfig) {
@@ -175,12 +180,10 @@ OutputTargetBuildItem outputTarget(BuildSystemTargetBuildItem bst, PackageConfig
@BuildStep(onlyIf = JarRequired.class)
ArtifactResultBuildItem jarOutput(JarBuildItem jarBuildItem) {
- if (jarBuildItem.getLibraryDir() != null) {
- return new ArtifactResultBuildItem(jarBuildItem.getPath(), "jar",
- Collections.singletonMap("library-dir", jarBuildItem.getLibraryDir().toString()));
- } else {
- return new ArtifactResultBuildItem(jarBuildItem.getPath(), "jar", Collections.emptyMap());
- }
+ return new ArtifactResultBuildItem(jarBuildItem.getPath(), "jar",
+ jarBuildItem.getLibraryDir() == null ? Map.of()
+ : Map.of("library-dir", jarBuildItem.getLibraryDir().toString()),
+ jarBuildItem.getManifestConfig());
}
@SuppressWarnings("deprecation") // JarType#LEGACY_JAR
@@ -310,8 +313,31 @@ private JarBuildItem buildUberJar(CurateOutcomeBuildItem curateOutcomeBuildItem,
.resolve(outputTargetBuildItem.getOriginalBaseName() + DOT_JAR);
final Path originalJar = Files.exists(standardJar) ? standardJar : null;
+ ResolvedDependency appArtifact = curateOutcomeBuildItem.getApplicationModel().getAppArtifact();
+ final String classifier = suffixToClassifier(packageConfig.computedRunnerSuffix());
+ if (classifier != null && !classifier.isEmpty()) {
+ appArtifact = ResolvedDependencyBuilder.newInstance()
+ .setGroupId(appArtifact.getGroupId())
+ .setArtifactId(appArtifact.getArtifactId())
+ .setClassifier(classifier)
+ .setType(appArtifact.getType())
+ .setVersion(appArtifact.getVersion())
+ .setResolvedPaths(appArtifact.getResolvedPaths())
+ .addDependencies(appArtifact.getDependencies())
+ .setWorkspaceModule(appArtifact.getWorkspaceModule())
+ .setFlags(appArtifact.getFlags())
+ .build();
+ }
+ final ApplicationManifestConfig manifestConfig = ApplicationManifestConfig.builder()
+ .setApplicationModel(curateOutcomeBuildItem.getApplicationModel())
+ .setMainComponent(ApplicationComponent.builder()
+ .setPath(runnerJar)
+ .setResolvedDependency(appArtifact)
+ .build())
+ .setRunnerPath(runnerJar)
+ .build();
return new JarBuildItem(runnerJar, originalJar, null, UBER_JAR,
- suffixToClassifier(packageConfig.computedRunnerSuffix()));
+ suffixToClassifier(packageConfig.computedRunnerSuffix()), manifestConfig);
}
private String suffixToClassifier(String suffix) {
@@ -356,16 +382,14 @@ public boolean test(String path) {
}
};
- final Collection appDeps = curateOutcomeBuildItem.getApplicationModel()
- .getRuntimeDependencies();
-
ResolvedDependency appArtifact = curateOutcomeBuildItem.getApplicationModel().getAppArtifact();
+
// the manifest needs to be the first entry in the jar, otherwise JarInputStream does not work properly
// see https://bugs.openjdk.java.net/browse/JDK-8031748
generateManifest(runnerZipFs, "", packageConfig, appArtifact, mainClassBuildItem.getClassName(),
applicationInfo);
- for (ResolvedDependency appDep : appDeps) {
+ for (ResolvedDependency appDep : curateOutcomeBuildItem.getApplicationModel().getRuntimeDependencies()) {
// Exclude files that are not jars (typically, we can have XML files here, see https://github.com/quarkusio/quarkus/issues/2852)
// and are not part of the optional dependencies to include
@@ -570,6 +594,9 @@ private JarBuildItem buildThinJar(CurateOutcomeBuildItem curateOutcomeBuildItem,
buildDir = outputTargetBuildItem.getOutputDirectory().resolve(DEFAULT_FAST_JAR_DIRECTORY_NAME);
}
+ final ApplicationManifestConfig.Builder manifestConfig = ApplicationManifestConfig.builder()
+ .setApplicationModel(curateOutcomeBuildItem.getApplicationModel())
+ .setDistributionDirectory(buildDir);
//unmodified 3rd party dependencies
Path libDir = buildDir.resolve(LIB);
Path mainLib = libDir.resolve(MAIN);
@@ -608,7 +635,7 @@ private JarBuildItem buildThinJar(CurateOutcomeBuildItem curateOutcomeBuildItem,
Decompiler decompiler = null;
PackageConfig.DecompilerConfig decompilerConfig = packageConfig.jar().decompiler();
if (decompilerConfig.enabled()) {
- decompiledOutputDir = buildDir.getParent().resolve("decompiled");
+ decompiledOutputDir = buildDir.getParent().resolve(decompilerConfig.outputDirectory());
FileUtil.deleteDirectory(decompiledOutputDir);
Files.createDirectory(decompiledOutputDir);
decompiler = new Decompiler.VineflowerDecompiler();
@@ -680,7 +707,6 @@ private JarBuildItem buildThinJar(CurateOutcomeBuildItem curateOutcomeBuildItem,
if (!rebuild) {
Predicate ignoredEntriesPredicate = getThinJarIgnoredEntriesPredicate(packageConfig);
-
try (FileSystem runnerZipFs = createNewZip(runnerJar, packageConfig)) {
copyFiles(applicationArchivesBuildItem.getRootArchive(), runnerZipFs, null, ignoredEntriesPredicate);
}
@@ -693,7 +719,7 @@ private JarBuildItem buildThinJar(CurateOutcomeBuildItem curateOutcomeBuildItem,
if (!rebuild) {
copyDependency(parentFirstKeys, outputTargetBuildItem, copiedArtifacts, mainLib, baseLib,
fastJarJarsBuilder::addDep, true,
- classPath, appDep, transformedClasses, removed, packageConfig);
+ classPath, appDep, transformedClasses, removed, packageConfig, manifestConfig);
} else if (includeAppDep(appDep, outputTargetBuildItem.getIncludedOptionalDependencies(), removed)) {
appDep.getResolvedPaths().forEach(fastJarJarsBuilder::addDep);
}
@@ -750,6 +776,8 @@ private JarBuildItem buildThinJar(CurateOutcomeBuildItem curateOutcomeBuildItem,
runnerJar.toFile().setReadable(true, false);
Path initJar = buildDir.resolve(QUARKUS_RUN_JAR);
+ manifestConfig.setMainComponent(ApplicationComponent.builder().setPath(initJar))
+ .setRunnerPath(initJar);
boolean mutableJar = packageConfig.jar().type() == MUTABLE_JAR;
if (mutableJar) {
//we output the properties in a reproducible manner, so we remove the date comment
@@ -761,6 +789,7 @@ private JarBuildItem buildThinJar(CurateOutcomeBuildItem curateOutcomeBuildItem,
List lines = Arrays.stream(out.toString(StandardCharsets.UTF_8).split("\n"))
.filter(s -> !s.startsWith("#")).sorted().collect(Collectors.toList());
Path buildSystemProps = quarkus.resolve(BUILD_SYSTEM_PROPERTIES);
+ manifestConfig.addComponent(ApplicationComponent.builder().setPath(buildSystemProps).setDevelopmentScope());
try (OutputStream fileOutput = Files.newOutputStream(buildSystemProps)) {
fileOutput.write(String.join("\n", lines).getBytes(StandardCharsets.UTF_8));
}
@@ -778,10 +807,9 @@ private JarBuildItem buildThinJar(CurateOutcomeBuildItem curateOutcomeBuildItem,
Path deploymentLib = libDir.resolve(DEPLOYMENT_LIB);
Files.createDirectories(deploymentLib);
for (ResolvedDependency appDep : curateOutcomeBuildItem.getApplicationModel().getDependencies()) {
- copyDependency(parentFirstKeys, outputTargetBuildItem, copiedArtifacts, deploymentLib, baseLib, (p) -> {
- },
- false, classPath,
- appDep, new TransformedClassesBuildItem(Map.of()), removed, packageConfig); //we don't care about transformation here, so just pass in an empty item
+ copyDependency(parentFirstKeys, outputTargetBuildItem, copiedArtifacts, deploymentLib, baseLib, p -> {
+ }, false, classPath, appDep, new TransformedClassesBuildItem(Map.of()), removed, packageConfig,
+ manifestConfig); //we don't care about transformation here, so just pass in an empty item
}
Map> relativePaths = new HashMap<>();
for (Map.Entry> e : copiedArtifacts.entrySet()) {
@@ -797,6 +825,7 @@ private JarBuildItem buildThinJar(CurateOutcomeBuildItem curateOutcomeBuildItem,
curateOutcomeBuildItem.getApplicationModel(),
packageConfig.jar().userProvidersDirectory().orElse(null), buildDir.relativize(runnerJar).toString());
Path appmodelDat = deploymentLib.resolve(APPMODEL_DAT);
+ manifestConfig.addComponent(ApplicationComponent.builder().setPath(appmodelDat).setDevelopmentScope());
try (OutputStream out = Files.newOutputStream(appmodelDat)) {
ObjectOutputStream obj = new ObjectOutputStream(out);
obj.writeObject(model);
@@ -807,6 +836,7 @@ private JarBuildItem buildThinJar(CurateOutcomeBuildItem curateOutcomeBuildItem,
//as we don't really have a resolved bootstrap CP
//once we have the app model it will all be done in QuarkusClassLoader anyway
Path deploymentCp = deploymentLib.resolve(DEPLOYMENT_CLASS_PATH_DAT);
+ manifestConfig.addComponent(ApplicationComponent.builder().setPath(deploymentCp).setDevelopmentScope());
try (OutputStream out = Files.newOutputStream(deploymentCp)) {
ObjectOutputStream obj = new ObjectOutputStream(out);
List paths = new ArrayList<>();
@@ -842,7 +872,7 @@ public void accept(Path path) {
}
});
}
- return new JarBuildItem(initJar, null, libDir, packageConfig.jar().type(), null);
+ return new JarBuildItem(initJar, null, libDir, packageConfig.jar().type(), null, manifestConfig.build());
}
/**
@@ -883,7 +913,7 @@ private void copyDependency(Set parentFirstArtifacts, OutputTargetB
Map