@@ -74,18 +74,73 @@ private void applyRecommendationsDirectly(final Project project, final Configura
7474 project .afterEvaluate (new Action <Project >() {
7575 @ Override
7676 public void execute (Project p ) {
77+ // Eagerly resolve and cache all BOMs after project evaluation
78+ eagerlyResolveBoms (p , recommendationProviderContainer );
79+
7780 p .getConfigurations ().all (new ExtendRecommenderConfigurationAction (bomConfiguration , p , recommendationProviderContainer ));
7881 p .subprojects (new Action <Project >() {
7982 @ Override
8083 public void execute (Project sub ) {
84+ // Also eagerly resolve BOMs for subprojects
85+ eagerlyResolveBoms (sub , recommendationProviderContainer );
8186 sub .getConfigurations ().all (new ExtendRecommenderConfigurationAction (bomConfiguration , sub , recommendationProviderContainer ));
8287 }
8388 });
8489 }
8590 });
8691 }
92+
93+ /**
94+ * Eagerly resolves BOM configurations during the configuration phase to prevent
95+ * configuration resolution lock conflicts in parallel builds.
96+ *
97+ * <p>This method is called during {@code afterEvaluate} when exclusive locks are
98+ * available. It instructs the {@link BomResolverService} to resolve all BOM
99+ * configurations and cache the results for later use during dependency resolution.</p>
100+ *
101+ * <p>The eager resolution prevents the need to resolve configurations during the
102+ * dependency resolution phase, which would cause {@code IllegalResolutionException}
103+ * in parallel builds with Gradle 9+.</p>
104+ *
105+ * @param project the Gradle project whose BOM configurations should be resolved
106+ * @param container the recommendation provider container to check for additional BOM providers
107+ */
108+ private void eagerlyResolveBoms (Project project , RecommendationProviderContainer container ) {
109+ try {
110+ // Get the build service
111+ org .gradle .api .provider .Provider <netflix .nebula .dependency .recommender .service .BomResolverService > bomResolverService =
112+ project .getGradle ().getSharedServices ().registerIfAbsent (
113+ "bomResolver" , netflix .nebula .dependency .recommender .service .BomResolverService .class , spec -> {}
114+ );
115+
116+ // Resolve BOMs from the nebulaRecommenderBom configuration
117+ bomResolverService .get ().eagerlyResolveAndCacheBoms (project , NEBULA_RECOMMENDER_BOM );
118+
119+ // Also trigger resolution for maven BOM provider if it exists
120+ // This handles mavenBom providers configured in the extension
121+ netflix .nebula .dependency .recommender .provider .MavenBomRecommendationProvider mavenBomProvider = container .getMavenBomProvider ();
122+ if (mavenBomProvider != null ) {
123+ try {
124+ mavenBomProvider .getVersion ("dummy" , "dummy" ); // Trigger lazy initialization
125+ } catch (Exception e ) {
126+ // Expected - just needed to trigger BOM resolution
127+ }
128+ }
129+ } catch (Exception e ) {
130+ logger .warn ("Failed to eagerly resolve BOMs for project " + project .getPath (), e );
131+ }
132+ }
87133
88134 private void applyRecommendations (final Project project ) {
135+ // Add eager BOM resolution for regular (non-core) BOM support
136+ project .afterEvaluate (new Action <Project >() {
137+ @ Override
138+ public void execute (Project p ) {
139+ // Eagerly resolve and cache all BOMs after project evaluation
140+ eagerlyResolveBoms (p , recommendationProviderContainer );
141+ }
142+ });
143+
89144 project .getConfigurations ().all (new Action <Configuration >() {
90145 @ Override
91146 public void execute (final Configuration conf ) {
0 commit comments