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 4448a9223e7b6..0ccc9fa0812bd 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/SslProcessor.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/SslProcessor.java @@ -39,7 +39,7 @@ void runtime(BuildProducer reinitialized) { private void registerIfExists(BuildProducer reinitialized, String className) { try { - Class.forName(className); + Class.forName(className, false, Thread.currentThread().getContextClassLoader()); reinitialized.produce(new RuntimeReinitializedClassBuildItem(className)); } catch (ClassNotFoundException ignored) { 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 new file mode 100644 index 0000000000000..726434cd53e7f --- /dev/null +++ b/core/deployment/src/main/java/io/quarkus/deployment/jbang/JBangAugmentorImpl.java @@ -0,0 +1,156 @@ +package io.quarkus.deployment.jbang; + +import java.io.File; +import java.nio.file.Path; +import java.util.*; +import java.util.function.BiConsumer; +import java.util.function.Consumer; + +import org.jboss.logging.Logger; + +import io.quarkus.bootstrap.BootstrapGradleException; +import io.quarkus.bootstrap.app.AdditionalDependency; +import io.quarkus.bootstrap.app.CuratedApplication; +import io.quarkus.bootstrap.app.QuarkusBootstrap; +import io.quarkus.bootstrap.classloading.QuarkusClassLoader; +import io.quarkus.bootstrap.model.AppArtifactKey; +import io.quarkus.bootstrap.resolver.maven.workspace.LocalProject; +import io.quarkus.bootstrap.resolver.model.WorkspaceModule; +import io.quarkus.bootstrap.util.QuarkusModelHelper; +import io.quarkus.builder.BuildChainBuilder; +import io.quarkus.builder.BuildResult; +import io.quarkus.builder.BuildStepBuilder; +import io.quarkus.deployment.QuarkusAugmentor; +import io.quarkus.deployment.builditem.ApplicationClassNameBuildItem; +import io.quarkus.deployment.builditem.GeneratedClassBuildItem; +import io.quarkus.deployment.builditem.GeneratedResourceBuildItem; +import io.quarkus.deployment.builditem.LiveReloadBuildItem; +import io.quarkus.deployment.builditem.TransformedClassesBuildItem; +import io.quarkus.deployment.dev.DevModeContext; +import io.quarkus.deployment.dev.IDEDevModeMain; +import io.quarkus.deployment.pkg.builditem.ArtifactResultBuildItem; +import io.quarkus.deployment.pkg.builditem.NativeImageBuildItem; +import io.quarkus.deployment.pkg.builditem.ProcessInheritIODisabled; +import io.quarkus.runtime.LaunchMode; + +public class JBangAugmentorImpl implements BiConsumer> { + + private static final Logger log = Logger.getLogger(IDEDevModeMain.class.getName()); + + @Override + public void accept(CuratedApplication curatedApplication, Map resultMap) { + + QuarkusClassLoader classLoader = curatedApplication.getAugmentClassLoader(); + + 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.getAppModel()); + if (quarkusBootstrap.getBaseName() != null) { + builder.setBaseName(quarkusBootstrap.getBaseName()); + } + + builder.setLaunchMode(LaunchMode.NORMAL); + builder.setRebuild(quarkusBootstrap.isRebuild()); + builder.setLiveReloadState(new LiveReloadBuildItem(false, Collections.emptySet(), new HashMap<>())); + 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.getArchivePath()); + } + } + builder.addBuildChainCustomizer(new Consumer() { + @Override + public void accept(BuildChainBuilder builder) { + final BuildStepBuilder stepBuilder = builder.addBuildStep((ctx) -> { + ctx.produce(new ProcessInheritIODisabled()); + }); + stepBuilder.produces(ProcessInheritIODisabled.class).build(); + } + }); + builder.excludeFromIndexing(quarkusBootstrap.getExcludeFromClassPath()); + builder.addFinal(GeneratedClassBuildItem.class); + builder.addFinal(GeneratedResourceBuildItem.class); + builder.addFinal(TransformedClassesBuildItem.class); + boolean nativeRequested = "native".equals(System.getProperty("quarkus.package.type")); + 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 nessesarily 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()); + } + for (GeneratedResourceBuildItem i : buildResult.consumeMulti(GeneratedResourceBuildItem.class)) { + result.put(i.getName(), i.getClassData()); + } + for (Map.Entry> entry : buildResult + .consume(TransformedClassesBuildItem.class).getTransformedClassesByJar().entrySet()) { + for (TransformedClassesBuildItem.TransformedClass transformed : entry.getValue()) { + result.put(transformed.getFileName(), transformed.getData()); + } + } + resultMap.put("files", result); + List javaargs = new ArrayList(); + javaargs.add("-Djava.util.logging.manager=org.jboss.logmanager.LogManager"); + resultMap.put("java-args", javaargs); + if (nativeRequested) { + resultMap.put("native-image", buildResult.consume(NativeImageBuildItem.class).getPath()); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private DevModeContext.ModuleInfo toModule(WorkspaceModule module) throws BootstrapGradleException { + AppArtifactKey key = new AppArtifactKey(module.getArtifactCoords().getGroupId(), + module.getArtifactCoords().getArtifactId(), module.getArtifactCoords().getClassifier()); + + Set sourceDirectories = new HashSet<>(); + Set sourceParents = new HashSet<>(); + for (File srcDir : module.getSourceSourceSet().getSourceDirectories()) { + sourceDirectories.add(srcDir.getPath()); + sourceParents.add(srcDir.getParent()); + } + + return new DevModeContext.ModuleInfo(key, + module.getArtifactCoords().getArtifactId(), + module.getProjectRoot().getPath(), + sourceDirectories, + QuarkusModelHelper.getClassPath(module).toAbsolutePath().toString(), + module.getSourceSourceSet().getResourceDirectory().toString(), + module.getSourceSet().getResourceDirectory().getPath(), + sourceParents, + module.getBuildDir().toPath().resolve("generated-sources").toAbsolutePath().toString(), + module.getBuildDir().toString()); + } + + private DevModeContext.ModuleInfo toModule(LocalProject project) { + return new DevModeContext.ModuleInfo(project.getKey(), project.getArtifactId(), + project.getDir().toAbsolutePath().toString(), + Collections.singleton(project.getSourcesSourcesDir().toAbsolutePath().toString()), + project.getClassesDir().toAbsolutePath().toString(), + project.getResourcesSourcesDir().toAbsolutePath().toString(), + project.getSourcesDir().toString(), + project.getCodeGenOutputDir().toString(), + project.getOutputDir().toString()); + } +} diff --git a/core/launcher/src/main/java/io/quarkus/launcher/JBangIntegration.java b/core/launcher/src/main/java/io/quarkus/launcher/JBangIntegration.java new file mode 100644 index 0000000000000..2b04a7f8ab8d1 --- /dev/null +++ b/core/launcher/src/main/java/io/quarkus/launcher/JBangIntegration.java @@ -0,0 +1,92 @@ +package io.quarkus.launcher; + +import java.io.IOException; +import java.net.URL; +import java.nio.file.Path; +import java.util.Collections; +import java.util.Enumeration; +import java.util.List; +import java.util.Map; + +import io.quarkus.bootstrap.BootstrapConstants; + +public class JBangIntegration { + + public static final String CONFIG = "//Q:CONFIG"; + + public static Map postBuild(Path appClasses, Path pomFile, List> repositories, + List> dependencies, + List comments, boolean nativeImage) { + for (String comment : comments) { + //we allow config to be provided via //Q:CONFIG name=value + if (comment.startsWith(CONFIG)) { + String conf = comment.substring(CONFIG.length()).trim(); + int equals = conf.indexOf("="); + if (equals == -1) { + throw new RuntimeException("invalid config " + comment); + } + System.setProperty(conf.substring(0, equals), conf.substring(equals + 1)); + } + } + + ClassLoader old = Thread.currentThread().getContextClassLoader(); + try { + RuntimeLaunchClassLoader loader = new RuntimeLaunchClassLoader( + new ClassLoader(JBangIntegration.class.getClassLoader()) { + @Override + public Class loadClass(String name) throws ClassNotFoundException { + return loadClass(name, false); + } + + @Override + protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { + if (name.startsWith("org.")) { + //jbang has some but not all of the maven resolver classes we need on its + //class path. These all start with org. so we filter them out to make sure + //we get a complete class path + throw new ClassNotFoundException(); + } + return super.loadClass(name, resolve); + } + + @Override + public URL getResource(String name) { + if (name.startsWith("org/")) { + //jbang has some but not all of the maven resolver classes we need on its + //class path. These all start with org. so we filter them out to make sure + //we get a complete class path + return null; + } + return super.getResource(name); + } + + @Override + public Enumeration getResources(String name) throws IOException { + if (name.startsWith("org/")) { + //jbang has some but not all of the maven resolver classes we need on its + //class path. These all start with org. so we filter them out to make sure + //we get a complete class path + return Collections.emptyEnumeration(); + } + return super.getResources(name); + } + }); + Thread.currentThread().setContextClassLoader(loader); + Class launcher = loader.loadClass("io.quarkus.bootstrap.JBangBuilderImpl"); + return (Map) launcher + .getDeclaredMethod("postBuild", Path.class, Path.class, List.class, List.class, boolean.class).invoke( + null, + appClasses, + pomFile, + repositories, + dependencies, + nativeImage); + } catch (Exception e) { + throw new RuntimeException(e); + } finally { + System.clearProperty(BootstrapConstants.SERIALIZED_APP_MODEL); + Thread.currentThread().setContextClassLoader(old); + } + } + +} diff --git a/core/launcher/src/main/java/io/quarkus/launcher/QuarkusLauncher.java b/core/launcher/src/main/java/io/quarkus/launcher/QuarkusLauncher.java index d62c8154b75c8..e079387127836 100644 --- a/core/launcher/src/main/java/io/quarkus/launcher/QuarkusLauncher.java +++ b/core/launcher/src/main/java/io/quarkus/launcher/QuarkusLauncher.java @@ -1,12 +1,10 @@ package io.quarkus.launcher; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; +import java.net.JarURLConnection; +import java.net.URI; import java.net.URL; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import java.util.function.Consumer; @@ -33,7 +31,15 @@ public static void launch(String callingClass, String quarkusApplication, Consum path = path.substring(0, path.length() - classResource.length()); URL newResource = new URL(resource.getProtocol(), resource.getHost(), resource.getPort(), path); - Path appClasses = Paths.get(newResource.toURI()); + URI uri = newResource.toURI(); + Path appClasses; + if ("jar".equals(uri.getScheme())) { + JarURLConnection connection = (JarURLConnection) uri.toURL().openConnection(); + connection.setDefaultUseCaches(false); + appClasses = Paths.get(connection.getJarFileURL().toURI()); + } else { + appClasses = Paths.get(uri); + } if (quarkusApplication != null) { System.setProperty("quarkus.package.main-class", quarkusApplication); } @@ -42,7 +48,7 @@ public static void launch(String callingClass, String quarkusApplication, Consum context.put("app-classes", appClasses); context.put("args", args); - IDEClassLoader loader = new IDEClassLoader(QuarkusLauncher.class.getClassLoader()); + RuntimeLaunchClassLoader loader = new RuntimeLaunchClassLoader(QuarkusLauncher.class.getClassLoader()); Thread.currentThread().setContextClassLoader(loader); Class launcher = loader.loadClass("io.quarkus.bootstrap.IDELauncherImpl"); @@ -55,90 +61,4 @@ public static void launch(String callingClass, String quarkusApplication, Consum } } - public static class IDEClassLoader extends ClassLoader { - - static { - registerAsParallelCapable(); - } - - public IDEClassLoader(ClassLoader parent) { - super(parent); - } - - @Override - protected Class findClass(String name) throws ClassNotFoundException { - String resourceName = name.replace(".", "/") + ".class"; - try { - try (InputStream is = getResourceAsStream(resourceName)) { - if (is == null) { - throw new ClassNotFoundException(name); - } - definePackage(name); - byte[] buf = new byte[1024]; - int r; - ByteArrayOutputStream out = new ByteArrayOutputStream(); - while ((r = is.read(buf)) > 0) { - out.write(buf, 0, r); - } - byte[] bytes = out.toByteArray(); - - return defineClass(name, bytes, 0, bytes.length); - } - } catch (IOException e) { - throw new RuntimeException(e); - } - - } - - private void definePackage(String name) { - final String pkgName = getPackageNameFromClassName(name); - if ((pkgName != null) && getPackage(pkgName) == null) { - synchronized (getClassLoadingLock(pkgName)) { - if (getPackage(pkgName) == null) { - // this could certainly be improved to use the actual manifest - definePackage(pkgName, null, null, null, null, null, null, null); - } - } - } - } - - private String getPackageNameFromClassName(String className) { - final int index = className.lastIndexOf('.'); - if (index == -1) { - // we return null here since in this case no package is defined - // this is same behavior as Package.getPackage(clazz) exhibits - // when the class is in the default package - return null; - } - return className.substring(0, index); - } - - protected Class findClass(String moduleName, String name) { - try { - return findClass(name); - } catch (ClassNotFoundException e) { - return null; - } - } - - protected URL findResource(String moduleName, String name) throws IOException { - return findResource(name); - } - - @Override - protected URL findResource(String name) { - if (!name.startsWith("/")) { - name = "/" + name; - } - return getParent().getResource("META-INF/ide-deps" + name + ".ide-launcher-res"); - } - - @Override - protected Enumeration findResources(String name) throws IOException { - if (!name.startsWith("/")) { - name = "/" + name; - } - return getParent().getResources("META-INF/ide-deps" + name + ".ide-launcher-res"); - } - } } diff --git a/core/launcher/src/main/java/io/quarkus/launcher/RuntimeLaunchClassLoader.java b/core/launcher/src/main/java/io/quarkus/launcher/RuntimeLaunchClassLoader.java new file mode 100644 index 0000000000000..691afcc0f3c7b --- /dev/null +++ b/core/launcher/src/main/java/io/quarkus/launcher/RuntimeLaunchClassLoader.java @@ -0,0 +1,94 @@ +package io.quarkus.launcher; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.Enumeration; + +public class RuntimeLaunchClassLoader extends ClassLoader { + + static { + registerAsParallelCapable(); + } + + public RuntimeLaunchClassLoader(ClassLoader parent) { + super(parent); + } + + @Override + protected Class findClass(String name) throws ClassNotFoundException { + String resourceName = name.replace(".", "/") + ".class"; + try { + try (InputStream is = getResourceAsStream(resourceName)) { + if (is == null) { + throw new ClassNotFoundException(name); + } + definePackage(name); + byte[] buf = new byte[1024]; + int r; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + while ((r = is.read(buf)) > 0) { + out.write(buf, 0, r); + } + byte[] bytes = out.toByteArray(); + + return defineClass(name, bytes, 0, bytes.length); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + + } + + private void definePackage(String name) { + final String pkgName = getPackageNameFromClassName(name); + if ((pkgName != null) && getPackage(pkgName) == null) { + synchronized (getClassLoadingLock(pkgName)) { + if (getPackage(pkgName) == null) { + // this could certainly be improved to use the actual manifest + definePackage(pkgName, null, null, null, null, null, null, null); + } + } + } + } + + private String getPackageNameFromClassName(String className) { + final int index = className.lastIndexOf('.'); + if (index == -1) { + // we return null here since in this case no package is defined + // this is same behavior as Package.getPackage(clazz) exhibits + // when the class is in the default package + return null; + } + return className.substring(0, index); + } + + protected Class findClass(String moduleName, String name) { + try { + return findClass(name); + } catch (ClassNotFoundException e) { + return null; + } + } + + protected URL findResource(String moduleName, String name) throws IOException { + return findResource(name); + } + + @Override + protected URL findResource(String name) { + if (!name.startsWith("/")) { + name = "/" + name; + } + return getParent().getResource("META-INF/ide-deps" + name + ".ide-launcher-res"); + } + + @Override + protected Enumeration findResources(String name) throws IOException { + if (!name.startsWith("/")) { + name = "/" + name; + } + return getParent().getResources("META-INF/ide-deps" + name + ".ide-launcher-res"); + } +} diff --git a/core/launcher/src/main/resources/META-INF/jbang-integration.list b/core/launcher/src/main/resources/META-INF/jbang-integration.list new file mode 100644 index 0000000000000..8138163fea18c --- /dev/null +++ b/core/launcher/src/main/resources/META-INF/jbang-integration.list @@ -0,0 +1,3 @@ +#This integration allows JBang to run Quarkus + +io.quarkus.launcher.JBangIntegration #the integration class \ No newline at end of file diff --git a/extensions/container-image/util/src/main/java/io/quarkus/container/util/PathsUtil.java b/extensions/container-image/util/src/main/java/io/quarkus/container/util/PathsUtil.java index 1a6dad4c61afa..172d5ebaaf1c6 100644 --- a/extensions/container-image/util/src/main/java/io/quarkus/container/util/PathsUtil.java +++ b/extensions/container-image/util/src/main/java/io/quarkus/container/util/PathsUtil.java @@ -21,7 +21,7 @@ public static AbstractMap.SimpleEntry findMainSourcesRoot(Path outpu if (toCheck.toFile().exists()) { return new AbstractMap.SimpleEntry<>(toCheck, currentPath); } - if (Files.exists(currentPath.getParent())) { + if (currentPath.getParent() != null && Files.exists(currentPath.getParent())) { currentPath = currentPath.getParent(); } else { return null; diff --git a/extensions/infinispan-client/runtime/src/main/java/io/quarkus/infinispan/client/runtime/InfinispanClientProducer.java b/extensions/infinispan-client/runtime/src/main/java/io/quarkus/infinispan/client/runtime/InfinispanClientProducer.java index abca600c8d973..27db928910843 100644 --- a/extensions/infinispan-client/runtime/src/main/java/io/quarkus/infinispan/client/runtime/InfinispanClientProducer.java +++ b/extensions/infinispan-client/runtime/src/main/java/io/quarkus/infinispan/client/runtime/InfinispanClientProducer.java @@ -107,7 +107,8 @@ public static void replaceProperties(Properties properties) throws ClassNotFound // If you are changing this method, you will most likely have to change builderFromProperties as well String marshallerClassName = (String) properties.get(ConfigurationProperties.MARSHALLER); if (marshallerClassName != null) { - Class marshallerClass = Class.forName(marshallerClassName); + Class marshallerClass = Class.forName(marshallerClassName, false, + Thread.currentThread().getContextClassLoader()); properties.put(ConfigurationProperties.MARSHALLER, Util.getInstance(marshallerClass)); } else { // Default to proto stream marshaller if one is not provided diff --git a/extensions/jaxb/deployment/src/main/java/io/quarkus/jaxb/deployment/JaxbProcessor.java b/extensions/jaxb/deployment/src/main/java/io/quarkus/jaxb/deployment/JaxbProcessor.java index 60335cadd8991..8d17cc2158fb0 100644 --- a/extensions/jaxb/deployment/src/main/java/io/quarkus/jaxb/deployment/JaxbProcessor.java +++ b/extensions/jaxb/deployment/src/main/java/io/quarkus/jaxb/deployment/JaxbProcessor.java @@ -239,7 +239,7 @@ private void handleJaxbFile(Path p) { line = line.trim(); if (!line.isEmpty() && !line.startsWith("#")) { String clazz = pkg + line; - Class cl = Class.forName(clazz); + Class cl = Class.forName(clazz, false, Thread.currentThread().getContextClassLoader()); while (cl != Object.class) { addReflectiveClass(true, true, cl.getName()); diff --git a/extensions/kafka-client/deployment/src/main/java/io/quarkus/kafka/client/deployment/KafkaProcessor.java b/extensions/kafka-client/deployment/src/main/java/io/quarkus/kafka/client/deployment/KafkaProcessor.java index 043787637f6c4..666ca6457e70f 100644 --- a/extensions/kafka-client/deployment/src/main/java/io/quarkus/kafka/client/deployment/KafkaProcessor.java +++ b/extensions/kafka-client/deployment/src/main/java/io/quarkus/kafka/client/deployment/KafkaProcessor.java @@ -145,7 +145,8 @@ public void build(CombinedIndexBuildItem indexBuildItem, BuildProducer topCommand, private Class classForName(String name) { try { - return Class.forName(name); + return Class.forName(name, false, Thread.currentThread().getContextClassLoader()); } catch (ClassNotFoundException ex) { throw new IllegalArgumentException(ex); } diff --git a/extensions/quartz/deployment/src/main/java/io/quarkus/quartz/deployment/QuartzProcessor.java b/extensions/quartz/deployment/src/main/java/io/quarkus/quartz/deployment/QuartzProcessor.java index bc6d6fdc36696..ba84184f3cad8 100644 --- a/extensions/quartz/deployment/src/main/java/io/quarkus/quartz/deployment/QuartzProcessor.java +++ b/extensions/quartz/deployment/src/main/java/io/quarkus/quartz/deployment/QuartzProcessor.java @@ -176,7 +176,8 @@ private List getAdditionalConfigurationReflectiveClass List reflectiveClasses = new ArrayList<>(); for (QuartzAdditionalPropsConfig props : config.values()) { try { - if (!clazz.isAssignableFrom(Class.forName(props.clazz))) { + if (!clazz + .isAssignableFrom(Class.forName(props.clazz, false, Thread.currentThread().getContextClassLoader()))) { throw new IllegalArgumentException(String.format("%s does not implements %s", props.clazz, clazz)); } } catch (ClassNotFoundException e) { diff --git a/extensions/resteasy-common/deployment/src/main/java/io/quarkus/resteasy/common/deployment/ResteasyCommonProcessor.java b/extensions/resteasy-common/deployment/src/main/java/io/quarkus/resteasy/common/deployment/ResteasyCommonProcessor.java index a390ffdf887f6..85622ab4782a4 100644 --- a/extensions/resteasy-common/deployment/src/main/java/io/quarkus/resteasy/common/deployment/ResteasyCommonProcessor.java +++ b/extensions/resteasy-common/deployment/src/main/java/io/quarkus/resteasy/common/deployment/ResteasyCommonProcessor.java @@ -359,7 +359,8 @@ public static void categorizeProviders(Set availableProviders, MediaType Set otherProviders) { for (String availableProvider : availableProviders) { try { - Class providerClass = Class.forName(availableProvider); + Class providerClass = Class.forName(availableProvider, false, + Thread.currentThread().getContextClassLoader()); if (MessageBodyReader.class.isAssignableFrom(providerClass) || MessageBodyWriter.class.isAssignableFrom(providerClass)) { if (MessageBodyReader.class.isAssignableFrom(providerClass)) { diff --git a/extensions/resteasy-server-common/deployment/src/main/java/io/quarkus/resteasy/server/common/deployment/ResteasyServerCommonProcessor.java b/extensions/resteasy-server-common/deployment/src/main/java/io/quarkus/resteasy/server/common/deployment/ResteasyServerCommonProcessor.java index 0ea4d691f07cd..04ee03c83b483 100755 --- a/extensions/resteasy-server-common/deployment/src/main/java/io/quarkus/resteasy/server/common/deployment/ResteasyServerCommonProcessor.java +++ b/extensions/resteasy-server-common/deployment/src/main/java/io/quarkus/resteasy/server/common/deployment/ResteasyServerCommonProcessor.java @@ -725,7 +725,8 @@ private static void registerContextProxyDefinitions(IndexView index, } else { //might be a framework class, which should be loadable try { - Class typeClass = Class.forName(annotatedType.name().toString()); + Class typeClass = Class.forName(annotatedType.name().toString(), false, + Thread.currentThread().getContextClassLoader()); if (typeClass.isInterface()) { proxyDefinition.produce(new NativeImageProxyDefinitionBuildItem(annotatedType.name().toString())); } diff --git a/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/RESTEasyExtension.java b/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/RESTEasyExtension.java index 72f719799e86b..e15ea64f5b100 100644 --- a/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/RESTEasyExtension.java +++ b/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/RESTEasyExtension.java @@ -31,7 +31,8 @@ public RESTEasyExtension(IndexView index) { private void scanAsyncResponseProvidersFromServices() { try { - Class asyncResponseProvider = Class.forName("org.jboss.resteasy.spi.AsyncResponseProvider"); + Class asyncResponseProvider = Class.forName("org.jboss.resteasy.spi.AsyncResponseProvider", false, + Thread.currentThread().getContextClassLoader()); // can't use the ServiceLoader API because Providers is not an interface for (String provider : ServiceUtil.classNamesNamedIn(getClass().getClassLoader(), "META-INF/services/javax.ws.rs.ext.Providers")) { diff --git a/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/BootstrapAppModelFactory.java b/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/BootstrapAppModelFactory.java index 2593bcea18d3b..ad23e609e01fc 100644 --- a/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/BootstrapAppModelFactory.java +++ b/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/BootstrapAppModelFactory.java @@ -236,7 +236,9 @@ public CurationResult resolveAppModel() throws BootstrapException { } } - if (projectRoot != null && !Files.isDirectory(projectRoot)) { + // Massive hack to dected zipped/jar + if (projectRoot != null + && (!Files.isDirectory(projectRoot) || projectRoot.getFileSystem().getClass().getName().contains("Zip"))) { return createAppModelForJar(projectRoot); } @@ -381,6 +383,7 @@ private CurationResult createAppModelForJar(Path appArtifactPath) { initialDepsList = modelResolver.resolveModel(appArtifact); } } else { + //we need some way to figure out dependencies here initialDepsList = modelResolver.resolveManagedModel(appArtifact, Collections.emptyList(), managingProject, localArtifacts); } diff --git a/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/IDELauncherImpl.java b/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/IDELauncherImpl.java index 572e446a17817..b2fdf7e7f5717 100644 --- a/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/IDELauncherImpl.java +++ b/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/IDELauncherImpl.java @@ -30,7 +30,7 @@ public static void launch(Path projectRoot, Map context) { .setIsolateDeployment(true) .setMode(QuarkusBootstrap.Mode.DEV); - if (!BuildToolHelper.isMavenProject(projectRoot)) { + if (BuildToolHelper.isGradleProject(projectRoot)) { final QuarkusModel quarkusModel = BuildToolHelper.enableGradleAppModelForDevMode(projectRoot); context.put(QuarkusModelHelper.SERIALIZED_QUARKUS_MODEL, QuarkusModelHelper.serializeQuarkusModel(quarkusModel)); diff --git a/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/JBangBuilderImpl.java b/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/JBangBuilderImpl.java new file mode 100644 index 0000000000000..9321d5722ce24 --- /dev/null +++ b/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/JBangBuilderImpl.java @@ -0,0 +1,84 @@ +package io.quarkus.bootstrap; + +import io.quarkus.bootstrap.app.CuratedApplication; +import io.quarkus.bootstrap.app.QuarkusBootstrap; +import io.quarkus.bootstrap.model.AppArtifact; +import io.quarkus.bootstrap.model.AppDependency; +import io.quarkus.bootstrap.resolver.maven.BootstrapMavenContext; +import io.quarkus.bootstrap.resolver.maven.BootstrapMavenException; +import io.quarkus.bootstrap.resolver.maven.MavenArtifactResolver; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import org.eclipse.aether.repository.RemoteRepository; + +public class JBangBuilderImpl { + public static Map postBuild(Path appClasses, Path pomFile, List> repositories, + List> dependencies, + boolean nativeImage) { + final MavenArtifactResolver quarkusResolver; + try { + final BootstrapMavenContext mvnCtx = new BootstrapMavenContext(BootstrapMavenContext.config() + .setCurrentProject(pomFile.getParent().toString())); + final List remoteRepos = new ArrayList<>(mvnCtx.getRemoteRepositories()); + + repositories.forEach(repo -> { + remoteRepos.add(new RemoteRepository.Builder(repo.getKey(), "default", repo.getValue()).build()); + }); + + quarkusResolver = MavenArtifactResolver.builder() + .setRepositorySystem(mvnCtx.getRepositorySystem()) + .setRepositorySystemSession(mvnCtx.getRepositorySystemSession()) + .setRemoteRepositoryManager(mvnCtx.getRemoteRepositoryManager()) + .setRemoteRepositories(remoteRepos) + .build(); + } catch (BootstrapMavenException e) { + throw new IllegalStateException("Failed to initialize Quarkus bootstrap Maven resolver", e); + } + + try { + Path target = Files.createTempDirectory("quarkus-jbang"); + AppArtifact appArtifact = new AppArtifact("dev.jbang.user", "quarkus", null, "jar", "999-SNAPSHOT"); + appArtifact.setPath(appClasses); + final QuarkusBootstrap.Builder builder = QuarkusBootstrap.builder() + .setBaseClassLoader(JBangBuilderImpl.class.getClassLoader()) + .setMavenArtifactResolver(quarkusResolver) + .setProjectRoot(pomFile.getParent()) + .setTargetDirectory(target) + .setForcedDependencies(dependencies.stream().map(s -> { + String[] parts = s.getKey().split(":"); + AppArtifact artifact; + if (parts.length == 3) { + artifact = new AppArtifact(parts[0], parts[1], parts[2]); + } else if (parts.length == 4) { + artifact = new AppArtifact(parts[0], parts[1], null, parts[2], parts[3]); + } else if (parts.length == 5) { + artifact = new AppArtifact(parts[0], parts[1], parts[3], parts[2], parts[4]); + } else { + throw new RuntimeException("Invalid artifact " + s.getKey()); + } + artifact.setPath(s.getValue()); + return new AppDependency(artifact, "compile"); + }).collect(Collectors.toList())) + .setAppArtifact(appArtifact) + .setIsolateDeployment(true) + .setMode(QuarkusBootstrap.Mode.PROD); + + CuratedApplication app = builder + .build().bootstrap(); + + if (nativeImage) { + System.setProperty("quarkus.package.type", "native"); + } + Map output = new HashMap<>(); + app.runInAugmentClassLoader("io.quarkus.deployment.jbang.JBangAugmentorImpl", output); + return output; + } catch (Exception e) { + throw new RuntimeException(e); + } + } +} diff --git a/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/utils/BuildToolHelper.java b/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/utils/BuildToolHelper.java index ce18a1bdf888c..1da06e4f247cd 100644 --- a/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/utils/BuildToolHelper.java +++ b/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/utils/BuildToolHelper.java @@ -57,6 +57,20 @@ public static boolean isMavenProject(Path project) { return false; } + public static boolean isGradleProject(Path project) { + Path currentPath = project; + while (currentPath != null) { + if (BuildTool.MAVEN.exists(currentPath)) { + return false; + } + if (BuildTool.GRADLE.exists(currentPath)) { + return true; + } + currentPath = currentPath.getParent(); + } + return false; + } + public static Path getBuildFile(Path project, BuildTool tool) { Path currentPath = project; while (currentPath != null) { diff --git a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/workspace/ModelUtils.java b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/workspace/ModelUtils.java index ee78b8526ff6a..5a478fb72ffd1 100644 --- a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/workspace/ModelUtils.java +++ b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/workspace/ModelUtils.java @@ -71,10 +71,9 @@ public static AppArtifact getStateArtifact(AppArtifact appArtifact) { * @param deps POM model application dependencies * @param appDeps resolved application dependencies * @return dependencies that can be checked for updates - * @throws AppCreatorException in case of a failure */ public static List getUpdateCandidates(List deps, List appDeps, - Set groupIds) throws IOException { + Set groupIds) { final Map appDepMap = new LinkedHashMap<>(appDeps.size()); for (AppDependency appDep : appDeps) { final AppArtifact appArt = appDep.getArtifact(); @@ -121,15 +120,22 @@ public static AppArtifact resolveAppArtifact(Path appJar) throws IOException { final Path propsPath = artifactIdPath.resolve("pom.properties"); if (Files.exists(propsPath)) { final Properties props = loadPomProps(appJar, artifactIdPath); - return new AppArtifact(props.getProperty("groupId"), props.getProperty("artifactId"), + AppArtifact appArtifact = new AppArtifact(props.getProperty("groupId"), + props.getProperty("artifactId"), props.getProperty("version")); + appArtifact.setPath(appJar); + return appArtifact; } } } } } } - throw new IOException("Failed to located META-INF/maven///pom.properties in " + appJar); + AppArtifact appArtifact = new AppArtifact("unknown", "unknown", + "1.0-SNAPSHOT"); + appArtifact.setPath(appJar); + + return appArtifact; } }