11package com .jaipilot .cli .files ;
22
33import com .jaipilot .cli .classpath .BuildToolClassResolutionService ;
4+ import com .jaipilot .cli .classpath .ClasspathResolutionException ;
45import com .jaipilot .cli .classpath .ClassResolutionResult ;
56import com .jaipilot .cli .classpath .LocationKind ;
67import com .jaipilot .cli .classpath .ResolutionOptions ;
8+ import com .jaipilot .cli .classpath .ResolutionFailure ;
79import com .jaipilot .cli .classpath .ResolvedSource ;
810import com .jaipilot .cli .process .BuildTool ;
911import com .jaipilot .cli .util .JavaSourceFormatter ;
@@ -311,20 +313,21 @@ private String readRequestedContextSource(Path projectRoot, Path preferredSource
311313 return dependencySource .get ().content ();
312314 }
313315
314- Optional <DependencySource > classpathResolvedSource = resolveDependencySourceViaClasspathIfPresent (
315- projectRoot ,
316- preferredSourcePath ,
317- requestedPath
318- );
316+ Optional <DependencySource > classpathResolvedSource ;
317+ try {
318+ classpathResolvedSource = resolveDependencySourceViaClasspathIfPresent (
319+ projectRoot ,
320+ preferredSourcePath ,
321+ requestedPath
322+ );
323+ } catch (ClasspathResolutionException exception ) {
324+ throw classpathResolutionFailure (requestedPath , exception );
325+ }
319326 if (classpathResolvedSource .isPresent ()) {
320327 return classpathResolvedSource .get ().content ();
321328 }
322329
323- throw new IllegalStateException (
324- "Unable to resolve requested context class path " + requestedPath
325- + ". Checked workspace sources and dependency sources. "
326- + "Ensure the class is on the module test classpath (profiles/build args) and dependency sources are available."
327- );
330+ throw new IllegalStateException (unresolvedContextMessage (requestedPath ));
328331 }
329332
330333 private Optional <DependencySource > resolveDependencySourceViaClasspathIfPresent (
@@ -339,35 +342,31 @@ private Optional<DependencySource> resolveDependencySourceViaClasspathIfPresent(
339342
340343 Path normalizedProjectRoot = projectRoot .toAbsolutePath ().normalize ();
341344 Path moduleRoot = resolveContextModuleRoot (normalizedProjectRoot , preferredSourcePath );
342- try {
343- Optional <ResolvedContextSource > resolved = contextSourceResolver .resolve (
344- normalizedProjectRoot ,
345- moduleRoot ,
346- requestedFqcn .get ()
347- );
348- if (resolved .isEmpty ()) {
349- return Optional .empty ();
350- }
351- String content = resolved .get ().content ();
352- String resolvedContextPath = normalizeContextPath (resolved .get ().contextPath ());
353- if (!resolvedContextPath .isBlank ()) {
354- dependencySourceContentCache .put (resolvedContextPath , content );
355- missingDependencySourcePaths .remove (resolvedContextPath );
356- }
357-
358- String requestedContextPath = normalizeContextPath (requestedPath );
359- if (!requestedContextPath .isBlank ()) {
360- dependencySourceContentCache .put (requestedContextPath , content );
361- missingDependencySourcePaths .remove (requestedContextPath );
362- }
363-
364- String contextPath = resolvedContextPath .isBlank ()
365- ? contextPathFromFqcn (requestedFqcn .get ())
366- : resolvedContextPath ;
367- return Optional .of (new DependencySource (contextPath , content ));
368- } catch (RuntimeException ignored ) {
345+ Optional <ResolvedContextSource > resolved = contextSourceResolver .resolve (
346+ normalizedProjectRoot ,
347+ moduleRoot ,
348+ requestedFqcn .get ()
349+ );
350+ if (resolved .isEmpty ()) {
369351 return Optional .empty ();
370352 }
353+ String content = resolved .get ().content ();
354+ String resolvedContextPath = normalizeContextPath (resolved .get ().contextPath ());
355+ if (!resolvedContextPath .isBlank ()) {
356+ dependencySourceContentCache .put (resolvedContextPath , content );
357+ missingDependencySourcePaths .remove (resolvedContextPath );
358+ }
359+
360+ String requestedContextPath = normalizeContextPath (requestedPath );
361+ if (!requestedContextPath .isBlank ()) {
362+ dependencySourceContentCache .put (requestedContextPath , content );
363+ missingDependencySourcePaths .remove (requestedContextPath );
364+ }
365+
366+ String contextPath = resolvedContextPath .isBlank ()
367+ ? contextPathFromFqcn (requestedFqcn .get ())
368+ : resolvedContextPath ;
369+ return Optional .of (new DependencySource (contextPath , content ));
371370 }
372371
373372 private Path resolveContextModuleRoot (Path projectRoot , Path preferredSourcePath ) {
@@ -1063,6 +1062,32 @@ private static String firstNonBlank(String... values) {
10631062 return null ;
10641063 }
10651064
1065+ private String unresolvedContextMessage (String requestedPath ) {
1066+ return "Unable to resolve requested context class path " + requestedPath
1067+ + ". Checked workspace sources and dependency sources. "
1068+ + "Ensure the class is on the module test classpath and dependency sources are available." ;
1069+ }
1070+
1071+ private IllegalStateException classpathResolutionFailure (
1072+ String requestedPath ,
1073+ ClasspathResolutionException exception
1074+ ) {
1075+ ResolutionFailure failure = exception .failure ();
1076+ if (failure == null ) {
1077+ return new IllegalStateException (unresolvedContextMessage (requestedPath ), exception );
1078+ }
1079+
1080+ String message = unresolvedContextMessage (requestedPath )
1081+ + " Classpath resolver failure: "
1082+ + failure .category ()
1083+ + " [tool=" + failure .buildTool ()
1084+ + ", moduleRoot=" + failure .moduleRoot ()
1085+ + ", action=" + failure .actionSummary ()
1086+ + ", output=" + failure .outputSnippet ()
1087+ + "]" ;
1088+ return new IllegalStateException (message , exception );
1089+ }
1090+
10661091 @ FunctionalInterface
10671092 interface ContextSourceResolver {
10681093 Optional <ResolvedContextSource > resolve (Path projectRoot , Path moduleRoot , String requestedFqcn );
0 commit comments