@@ -513,6 +513,7 @@ export class ProjectProvider implements vscode.TreeDataProvider<LibertyProject>
513513 private async buildHierarchy ( projectsMap : Map < string , LibertyProject > ) : Promise < void > {
514514 const mavenProjectsByArtifactId = new Map < string , LibertyProject > ( ) ;
515515 const gradleProjectsByName = new Map < string , LibertyProject > ( ) ;
516+ const mavenMetadataMap = new Map < string , mavenUtil . MavenProjectMetadata > ( ) ;
516517
517518 // First pass: populate metadata for all projects
518519 for ( const [ buildFilePath , project ] of projectsMap . entries ( ) ) {
@@ -525,6 +526,7 @@ export class ProjectProvider implements vscode.TreeDataProvider<LibertyProject>
525526 project . isAggregator = metadata . isAggregator ;
526527 project . isLibertyEnabled = metadata . isLibertyEnabled ;
527528 mavenProjectsByArtifactId . set ( metadata . artifactId , project ) ;
529+ mavenMetadataMap . set ( buildFilePath , metadata ) ;
528530 } else if ( buildFilePath . endsWith ( "build.gradle" ) ) {
529531 const metadata = await gradleUtil . extractGradleMetadata ( buildFilePath ) ;
530532 project . artifactId = metadata . projectName ;
@@ -541,6 +543,7 @@ export class ProjectProvider implements vscode.TreeDataProvider<LibertyProject>
541543 }
542544
543545 // Second pass: build parent-child relationships
546+ // Strategy 1: Use parentArtifactId if available (standard Maven with <parent> element)
544547 for ( const project of projectsMap . values ( ) ) {
545548 if ( project . parentArtifactId ) {
546549 // Look up parent in the appropriate map based on build tool
@@ -557,6 +560,34 @@ export class ProjectProvider implements vscode.TreeDataProvider<LibertyProject>
557560 }
558561 }
559562
563+ // Strategy 2: For Maven projects without parent links, use filesystem paths + module declarations
564+ // This handles multimodule projects where child POMs don't have <parent> elements
565+ for ( const [ parentPath , parentMetadata ] of mavenMetadataMap . entries ( ) ) {
566+ if ( parentMetadata . isAggregator && parentMetadata . modules . length > 0 ) {
567+ const parentProject = projectsMap . get ( parentPath ) ;
568+ if ( ! parentProject ) continue ;
569+
570+ const parentDir = vscodePath . dirname ( parentPath ) ;
571+
572+ // For each module declared in parent's <modules> section
573+ for ( const moduleName of parentMetadata . modules ) {
574+ // Resolve the module path relative to parent
575+ const modulePomPath = vscodePath . resolve ( parentDir , moduleName , "pom.xml" ) ;
576+
577+ // Check if this module exists in our discovered projects
578+ const childProject = projectsMap . get ( modulePomPath ) ;
579+ if ( childProject && ! childProject . parent ) {
580+ // Link child to parent
581+ childProject . parent = parentProject ;
582+ if ( ! parentProject . children . includes ( childProject ) ) {
583+ parentProject . children . push ( childProject ) ;
584+ }
585+ console . debug ( `Linked module ${ moduleName } to parent ${ parentMetadata . artifactId } via filesystem path` ) ;
586+ }
587+ }
588+ }
589+ }
590+
560591 // Third pass: identify root projects (no parent or parent not in workspace)
561592 this . rootProjects = Array . from ( projectsMap . values ( ) )
562593 . filter ( p => ! p . parent )
0 commit comments