1
1
/*
2
- * Copyright (c) 2013, 2023 , Oracle and/or its affiliates. All rights reserved.
2
+ * Copyright (c) 2013, 2025 , Oracle and/or its affiliates. All rights reserved.
3
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
4
*
5
5
* This code is free software; you can redistribute it and/or modify it
@@ -689,7 +689,6 @@ private ResolvedModule computeIfAbsent(Map<String, ResolvedModule> map,
689
689
* </ol>
690
690
*/
691
691
private void checkExportSuppliers (Map <ResolvedModule , Set <ResolvedModule >> graph ) {
692
-
693
692
for (Map .Entry <ResolvedModule , Set <ResolvedModule >> e : graph .entrySet ()) {
694
693
ModuleDescriptor descriptor1 = e .getKey ().descriptor ();
695
694
String name1 = descriptor1 .name ();
@@ -754,7 +753,6 @@ private void checkExportSuppliers(Map<ResolvedModule, Set<ResolvedModule>> graph
754
753
failTwoSuppliers (descriptor1 , source , descriptor2 , supplier );
755
754
}
756
755
}
757
-
758
756
}
759
757
}
760
758
@@ -764,18 +762,21 @@ private void checkExportSuppliers(Map<ResolvedModule, Set<ResolvedModule>> graph
764
762
// uses S
765
763
for (String service : descriptor1 .uses ()) {
766
764
String pn = packageName (service );
767
- if (!packageToExporter .containsKey (pn )) {
768
- resolveFail ("Module %s does not read a module that exports %s" ,
769
- descriptor1 .name (), pn );
765
+ if (!packageToExporter .containsKey (pn )
766
+ && !requiresStaticMissingModule (descriptor1 , reads )) {
767
+ resolveFail ("Module %s uses %s but does not read a module that exports %s to %s" ,
768
+ descriptor1 .name (), service , pn , descriptor1 .name ());
769
+
770
770
}
771
771
}
772
772
773
773
// provides S
774
774
for (ModuleDescriptor .Provides provides : descriptor1 .provides ()) {
775
775
String pn = packageName (provides .service ());
776
- if (!packageToExporter .containsKey (pn )) {
777
- resolveFail ("Module %s does not read a module that exports %s" ,
778
- descriptor1 .name (), pn );
776
+ if (!packageToExporter .containsKey (pn )
777
+ && !requiresStaticMissingModule (descriptor1 , reads )) {
778
+ resolveFail ("Module %s provides %s but does not read a module that exports %s to %s" ,
779
+ descriptor1 .name (), provides .service (), pn , descriptor1 .name ());
779
780
}
780
781
}
781
782
@@ -785,6 +786,34 @@ private void checkExportSuppliers(Map<ResolvedModule, Set<ResolvedModule>> graph
785
786
786
787
}
787
788
789
+ /**
790
+ * Returns true if a module 'requires static' a module that is not in the
791
+ * readability graph, or reads a module that 'requires static transitive'
792
+ * a module that is not in the readability graph.
793
+ */
794
+ private boolean requiresStaticMissingModule (ModuleDescriptor descriptor ,
795
+ Set <ResolvedModule > reads ) {
796
+ Set <String > moduleNames = reads .stream ()
797
+ .map (ResolvedModule ::name )
798
+ .collect (Collectors .toSet ());
799
+ for (ModuleDescriptor .Requires r : descriptor .requires ()) {
800
+ if (r .modifiers ().contains (Modifier .STATIC )
801
+ && !moduleNames .contains (r .name ())) {
802
+ return true ;
803
+ }
804
+ }
805
+ for (ResolvedModule rm : reads ) {
806
+ for (ModuleDescriptor .Requires r : rm .descriptor ().requires ()) {
807
+ if (r .modifiers ().contains (Modifier .STATIC )
808
+ && r .modifiers ().contains (Modifier .TRANSITIVE )
809
+ && !moduleNames .contains (r .name ())) {
810
+ return true ;
811
+ }
812
+ }
813
+ }
814
+ return false ;
815
+ }
816
+
788
817
/**
789
818
* Fail because a module in the configuration exports the same package to
790
819
* a module that reads both. This includes the case where a module M
0 commit comments