4949import org .apache .maven .plugin .descriptor .PluginDescriptor ;
5050import org .apache .maven .plugins .annotations .Component ;
5151import org .apache .maven .plugins .annotations .Parameter ;
52+ import org .apache .maven .project .MavenProject ;
5253import org .apache .maven .toolchain .ToolchainManager ;
5354import org .codehaus .plexus .logging .Logger ;
5455import org .graalvm .buildtools .maven .config .ExcludeConfigConfiguration ;
7677import java .util .HashSet ;
7778import java .util .List ;
7879import java .util .Map ;
80+ import java .util .Objects ;
7981import java .util .Optional ;
8082import java .util .Set ;
8183import java .util .function .Consumer ;
@@ -306,16 +308,26 @@ protected Path processArtifact(Artifact artifact, String... artifactTypes) throw
306308
307309 if (artifactFile == null ) {
308310 logger .debug ("Missing artifact file for artifact " + artifact + " (type: " + artifact .getType () + ")" );
309- return null ;
311+ return resolveClassesDirectoryFromReactor ( artifact ). filter ( Files :: exists ). orElse ( null ) ;
310312 }
311313
312314 if (Arrays .stream (artifactTypes ).noneMatch (a -> a .equals (artifact .getType ()))) {
313315 logger .warn ("Ignoring ImageClasspath Entry '" + artifact + "' with unsupported type '" + artifact .getType () + "'" );
314316 return null ;
315317 }
318+
316319 if (!artifactFile .exists ()) {
317- throw new MojoExecutionException ("Missing jar-file for " + artifact + ". " +
318- "Ensure that " + plugin .getArtifactId () + " runs in package phase." );
320+ Optional <Path > reactorOutput = resolveClassesDirectoryFromReactor (artifact );
321+ if (reactorOutput .isPresent ()) {
322+ Path reactorPath = reactorOutput .get ();
323+ if (Files .exists (reactorPath )) {
324+ logger .debug ("ImageClasspath Entry: " + artifact + " (" + reactorPath .toUri () + ")" );
325+ return reactorPath ;
326+ } else {
327+ logger .debug ("Skipping artifact " + artifact + " because no packaged file or classes directory was found." );
328+ return null ;
329+ }
330+ }
319331 }
320332
321333 Path jarFilePath = artifactFile .toPath ();
@@ -325,6 +337,30 @@ protected Path processArtifact(Artifact artifact, String... artifactTypes) throw
325337 return jarFilePath ;
326338 }
327339
340+ /**
341+ * Resolves the physical output directory (classes or test-classes) for a given artifact
342+ * by searching the current Maven reactor.
343+ * <p>
344+ * This is used as a fallback when an artifact's JAR file has not yet been created,
345+ * allowing the plugin to use compiled class folders instead.
346+ *
347+ * @param artifact The dependency artifact to resolve within the reactor.
348+ * @return An Optional containing the {@link Path} to the output directory if found,
349+ * otherwise an empty Optional.
350+ */
351+ private Optional <Path > resolveClassesDirectoryFromReactor (Artifact artifact ) {
352+ return Optional .ofNullable (session )
353+ .flatMap (s -> s .getAllProjects ().stream ()
354+ .filter (project -> Objects .equals (project .getGroupId (), artifact .getGroupId ())
355+ && Objects .equals (project .getArtifactId (), artifact .getArtifactId ())
356+ && Objects .equals (project .getVersion (), artifact .getVersion ()))
357+ .map (MavenProject ::getBuild )
358+ .map (build -> "test-jar" .equals (artifact .getType ()) ? build .getTestOutputDirectory () : build .getOutputDirectory ())
359+ .filter (dir -> dir != null && !dir .isEmpty ())
360+ .map (Paths ::get )
361+ .findFirst ());
362+ }
363+
328364 protected void addArtifactToClasspath (Artifact artifact ) throws MojoExecutionException {
329365 if (!isExcluded (artifact )) {
330366 Optional .ofNullable (processSupportedArtifacts (artifact )).ifPresent (imageClasspath ::add );
@@ -378,13 +414,18 @@ protected void addDependenciesToClasspath() throws MojoExecutionException {
378414 Set <Artifact > collected = new HashSet <>();
379415 // Must keep classpath order is the same with surefire test
380416 for (Artifact dependency : project .getArtifacts ()) {
381- if (getDependencyScopes ().contains (dependency .getScope ()) && collected .add (dependency )) {
382- addArtifactToClasspath (dependency );
383- maybeAddDependencyMetadata (dependency , file -> {
384- buildArgs .add ("--exclude-config" );
385- buildArgs .add (Pattern .quote (dependency .getFile ().getAbsolutePath ()));
386- buildArgs .add ("^/META-INF/native-image/" );
387- });
417+ if (getDependencyScopes ().contains (dependency .getScope ()) && collected .add (dependency ) && !isExcluded (dependency )) {
418+ Path dependencyPath = processSupportedArtifacts (dependency );
419+ if (dependencyPath != null ) {
420+ imageClasspath .add (dependencyPath );
421+ if (dependency .getFile () != null ) {
422+ maybeAddDependencyMetadata (dependency , file -> {
423+ buildArgs .add ("--exclude-config" );
424+ buildArgs .add (Pattern .quote (dependency .getFile ().getAbsolutePath ()));
425+ buildArgs .add ("^/META-INF/native-image/" );
426+ });
427+ }
428+ }
388429 }
389430 }
390431 }
0 commit comments