Describe the bug
When building a dev-jar from profile the build fails with an NullPointerException
Expected behavior
Build builds correctly.
Actual behavior
NullpointerException:
Caused by: org.apache.maven.plugin.MojoExecutionException: Failed to build quarkus application
at io.quarkus.maven.BuildMojo.execute (BuildMojo.java:208)
at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo (DefaultBuildPluginManager.java:137)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:210)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:156)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:148)
at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:117)
at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:81)
at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build (SingleThreadedBuilder.java:56)
at org.apache.maven.lifecycle.internal.LifecycleStarter.execute (LifecycleStarter.java:128)
at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:305)
at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:192)
at org.apache.maven.DefaultMaven.execute (DefaultMaven.java:105)
at org.apache.maven.cli.MavenCli.execute (MavenCli.java:957)
at org.apache.maven.cli.MavenCli.doMain (MavenCli.java:289)
at org.apache.maven.cli.MavenCli.main (MavenCli.java:193)
at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0 (Native Method)
at jdk.internal.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62)
at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke (Method.java:566)
at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced (Launcher.java:282)
at org.codehaus.plexus.classworlds.launcher.Launcher.launch (Launcher.java:225)
at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode (Launcher.java:406)
at org.codehaus.plexus.classworlds.launcher.Launcher.main (Launcher.java:347)
Caused by: java.lang.NullPointerException
at io.quarkus.maven.BuildMojo.execute (BuildMojo.java:174)
at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo (DefaultBuildPluginManager.java:137)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:210)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:156)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:148)
at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:117)
at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:81)
at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build (SingleThreadedBuilder.java:56)
at org.apache.maven.lifecycle.internal.LifecycleStarter.execute (LifecycleStarter.java:128)
at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:305)
at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:192)
at org.apache.maven.DefaultMaven.execute (DefaultMaven.java:105)
at org.apache.maven.cli.MavenCli.execute (MavenCli.java:957)
at org.apache.maven.cli.MavenCli.doMain (MavenCli.java:289)
at org.apache.maven.cli.MavenCli.main (MavenCli.java:193)
at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0 (Native Method)
at jdk.internal.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62)
at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke (Method.java:566)
at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced (Launcher.java:282)
at org.codehaus.plexus.classworlds.launcher.Launcher.launch (Launcher.java:225)
at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode (Launcher.java:406)
at org.codehaus.plexus.classworlds.launcher.Launcher.main (Launcher.java:347)
To Reproduce
Steps to reproduce the behavior:
clone https://github.com/tkalmar/quarkus-reproduce-9546/tree/reproduce_npe_profile_build
mvn -Pqjar-h2 -f server -X
Configuration
# Add your application.properties here, if applicable.
Screenshots
(If applicable, add screenshots to help explain your problem.)
Environment (please complete the following information):
uname -a or ver: MINGW64_NT-10.0-18363 XXXX 3.0.7-338.x86_64 2019-11-21 23:07 UTC x86_64 Msysjava -version:mvnw --version or gradlew --version):Maybe unrelated but : mvn clean install; mvn quarkus:dev -f server produces:
Exception in thread "main" java.lang.RuntimeException: java.lang.NullPointerException
at io.quarkus.deployment.dev.DevModeMain.start(DevModeMain.java:130)
at io.quarkus.deployment.dev.DevModeMain.main(DevModeMain.java:56)
Caused by: java.lang.NullPointerException
at java.base/sun.nio.fs.WindowsPathParser.parse(WindowsPathParser.java:98)
at java.base/sun.nio.fs.WindowsPathParser.parse(WindowsPathParser.java:77)
at java.base/sun.nio.fs.WindowsPath.parse(WindowsPath.java:92)
at java.base/sun.nio.fs.WindowsFileSystem.getPath(WindowsFileSystem.java:229)
at java.base/java.nio.file.Path.of(Path.java:147)
at java.base/java.nio.file.Paths.get(Paths.java:69)
at io.quarkus.deployment.dev.DevModeMain.start(DevModeMain.java:84)
but: mvn quarkus:dev -f server works after that until next clean install
cc @famod
1.5.2Final (works in 1.4.2Final
This part is easy to miss so in all clarity: This is a regression!
@tkalmar It seems you copied the wrong version for quarkus-jdbc-h2:
https://github.com/tkalmar/quarkus-reproduce-9546/blob/reproduce_npe_profile_build/server/pom.xml#L51
But even without this version (so that 1.5.2.Final is used) the problem persists.
The code fails here:
https://github.com/quarkusio/quarkus/blob/1.5.2.Final/devtools/maven/src/main/java/io/quarkus/maven/BuildMojo.java#L174
projectArtifact.getFile() returns null and therefore .toPath() fails with a NPE.
@stuartwdouglas Since you added this line: Do you have any idea what is going on?
Thanks!
cc @aloubyansky
Do you have any idea why getFile is returning null? Is there something different about this project?
@stuartwdouglas I'm not sure who you wanted to adress with your question but from my POV the only special thing here is that the h2 dependency is just present in a profile.
It looks like it's related to the fact the server has neither sources nor resources, so it will end up being packaged an empty JAR. But until the packaging phase, there is literally no real content. So that may explain the null and why mvn -f server package works.
@famod @aloubyansky The dependency is not the problem, even if you remove this dependency from the profile getFile is null. Perhaps the maven model is built different for profiles than for "normal" runs? Even if i dumb down the example to a single module with one rest resource i get the NPE when building from profile ... So even if an non empty jar exists ...
Could you push that single module example somewhere on github? Or zip it and attach to this issue? Thanks @tkalmar
In this case it hasn't been compiled. If you do compile quarkus:build it'll work
or
diff --git a/pom.xml b/pom.xml
index b871416..e5f3e0d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -56,7 +56,7 @@
<profile>
<id>qjar-h2</id>
<build>
- <defaultGoal>quarkus:build@default</defaultGoal>
+ <defaultGoal>compile quarkus:build@default</defaultGoal>^M
Indeed, it has nothing to do with profile :/ mvn quarkus:build without compile NPEs also, works with quarkus 1.4.2Final, so this is a regression as @famod stated.
It's not true though that it actually worked in 1.4.2.Final. What happened in that version the resolver would simply pick up your previously installed JAR from the local repo. It's easy to reproduce using your minimal example. Remove the server artifact from your local repo and re-run.
We never did automatic compilation in the BuildMojo (unlike in DevMojo).
You are right. The Errormessage is not optimal in both versions, but i think NullPointerExceptioninstead of ...Could not find artifact is no improvement.
Well, if we are going to play that game...:) What's better: to fail fast with an NPE or be fooled by running stale code? :D
We do agree it needs to be properly fixed. No doubt about that :)
I vote for fail fast ;)
BTW, while we certainly could copy "auto-compile" from the DevMojo to BuildMojo, I don't feel good about that idea. It has its limitations. I'd prefer throwing an error if a project hasn't been compiled yet instead in this case.
Just in case, here is a fix
diff --git a/devtools/maven/src/main/java/io/quarkus/maven/BuildMojo.java b/devtools/maven/src/main/java/io/quarkus/maven/BuildMojo.java
index ee9449942..423d790b6 100644
--- a/devtools/maven/src/main/java/io/quarkus/maven/BuildMojo.java
+++ b/devtools/maven/src/main/java/io/quarkus/maven/BuildMojo.java
@@ -9,6 +9,7 @@ import java.util.List;
import java.util.Properties;
import org.apache.maven.artifact.Artifact;
+import org.apache.maven.model.Resource;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Component;
@@ -172,7 +173,20 @@ public class BuildMojo extends AbstractMojo {
final AppArtifact appArtifact = new AppArtifact(projectArtifact.getGroupId(), projectArtifact.getArtifactId(),
projectArtifact.getClassifier(), projectArtifact.getArtifactHandler().getExtension(),
projectArtifact.getVersion());
- appArtifact.setPaths(PathsCollection.of(projectArtifact.getFile().toPath()));
+
+ File projectFile = projectArtifact.getFile();
+ if (projectFile == null) {
+ projectFile = new File(project.getBuild().getOutputDirectory());
+ if (!projectFile.exists()) {
+ if (hasSources(project)) {
+ throw new MojoExecutionException("Project " + project.getArtifact() + " has not been compiled yet");
+ }
+ if (!projectFile.mkdir()) {
+ throw new MojoExecutionException("Failed to create the output dir " + projectFile);
+ }
+ }
+ }
+ appArtifact.setPaths(PathsCollection.of(projectFile.toPath()));
QuarkusBootstrap.Builder builder = QuarkusBootstrap.builder()
.setAppArtifact(appArtifact)
@@ -223,4 +237,15 @@ public class BuildMojo extends AbstractMojo {
}
}
+ private static boolean hasSources(MavenProject project) {
+ if (new File(project.getBuild().getSourceDirectory()).exists()) {
+ return true;
+ }
+ for (Resource r : project.getBuild().getResources()) {
+ if (new File(r.getDirectory()).exists()) {
+ return true;
+ }
+ }
+ return false;
+ }
}
Okay, trying to catch up: So you are saying that the build goal depends on target/classes (which is created by resources plugin) even if this is more less empty? Am I missing something?
If there are no sources and no resources and the artifact hasn't been previously packaged, it's not resolvable.