2424 */
2525package com .oracle .svm .core .jdk ;
2626
27+ import com .oracle .svm .core .SubstrateUtil ;
2728import com .oracle .svm .core .annotate .Alias ;
2829import com .oracle .svm .core .annotate .RecomputeFieldValue ;
2930import com .oracle .svm .core .annotate .Substitute ;
3031import com .oracle .svm .core .annotate .TargetClass ;
3132import com .oracle .svm .core .jdk .resources .ResourceStorageEntry ;
3233
34+ import javax .lang .model .SourceVersion ;
3335import java .io .ByteArrayInputStream ;
3436import java .io .InputStream ;
37+ import java .util .Objects ;
3538
3639@ SuppressWarnings ("unused" )
3740@ TargetClass (className = "java.lang.Module" , onlyWith = JDK11OrLater .class )
@@ -46,22 +49,101 @@ public InputStream getResourceAsStream(String name) {
4649
4750 @ Substitute
4851 private static void defineModule0 (Module module , boolean isOpen , String version , String location , String [] pns ) {
52+ if (Objects .isNull (module )) {
53+ throw new NullPointerException ("Null module object" );
54+ }
55+
56+ if (Objects .isNull (module .getName ())) {
57+ throw new IllegalArgumentException ("Module name cannot be null" );
58+ }
59+
60+ if (module .getName ().equals ("java.base" )) {
61+ if (isOpen ) {
62+ throw new AssertionError ("java.base module cannot be open" );
63+ }
64+
65+ for (String pn : pns ) {
66+ if (!ModuleUtil .isValidPackageName (pn )) {
67+ throw new IllegalArgumentException ("Invalid package name: " + pn + " for module: java.base" );
68+ }
69+ }
70+
71+ if (module .getClassLoader () != null ) {
72+ throw new IllegalArgumentException ("Class loader must be the boot class loader" );
73+ }
74+ return ;
75+ }
76+
77+ ClassLoader loader = module .getClassLoader ();
78+ if (Objects .isNull (loader ) || loader .getClass ().getName ().equals ("jdk.internal.reflect.DelegatingClassLoader" )) {
79+ throw new IllegalArgumentException ("Class loader is an invalid delegating class loader" );
80+ }
81+
82+ for (String pn : pns ) {
83+ if (!ModuleUtil .isValidPackageName (pn )) {
84+ throw new IllegalArgumentException ("Invalid package name: " + pn + " for module: " + module .getName ());
85+ }
86+
87+ if (loader != ClassLoader .getPlatformClassLoader () && ModuleUtil .isPackageNameForbidden (pn )) {
88+ throw new IllegalArgumentException ("Class loader (instance of): " + loader .getClass ().getName () +
89+ " tried to define prohibited package name: " + pn );
90+ }
91+ }
92+
93+ // TODO is synchronization nececary?
94+ Package existingPackage = null ;
95+ boolean moduleAlreadyExists = false ;
96+ for (String pn : pns ) {
97+ existingPackage = loader .getDefinedPackage (pn );
98+ if (Objects .nonNull (existingPackage )) {
99+ moduleAlreadyExists = ModuleUtil .moduleAlreadyExists (module );
100+ break ;
101+ }
102+ }
103+ if (moduleAlreadyExists ) {
104+ throw new IllegalStateException ("Module " + module .getName () + " is already defined" );
105+ } else if (Objects .nonNull (existingPackage )) {
106+ Target_java_lang_NamedPackage namedPackage = SubstrateUtil .cast (existingPackage , Target_java_lang_NamedPackage .class );
107+ if (namedPackage .module .isNamed ()) {
108+ throw new IllegalStateException ("Package " + existingPackage .getName () + " is already in another module, "
109+ + namedPackage .module .getName () + ", defined to the class loader" );
110+ } else {
111+ throw new IllegalStateException ("Package " + existingPackage .getName ()
112+ + " is already in the unnamed module defined to the class loader" );
113+ }
114+ }
49115 }
50116
51117 @ Substitute
52118 private static void addReads0 (Module from , Module to ) {
119+ if (Objects .isNull (from )) {
120+ throw new NullPointerException ("from_module is null" );
121+ }
53122 }
54123
55124 @ Substitute
56125 private static void addExports0 (Module from , String pn , Module to ) {
126+ if (Objects .isNull (to )) {
127+ throw new NullPointerException ("to_module is null" );
128+ }
129+
130+ ModuleUtil .checkFromModuleAndPackageNullability (from , pn );
131+ ModuleUtil .checkIsPackageContainedInModule (pn , from );
57132 }
58133
59134 @ Substitute
60135 private static void addExportsToAll0 (Module from , String pn ) {
136+ ModuleUtil .checkFromModuleAndPackageNullability (from , pn );
137+ ModuleUtil .checkIsPackageContainedInModule (pn , from );
61138 }
62139
63140 @ Substitute
64141 private static void addExportsToAllUnnamed0 (Module from , String pn ) {
142+ ModuleUtil .checkFromModuleAndPackageNullability (from , pn );
143+
144+ if (from .isNamed ()) {
145+ ModuleUtil .checkIsPackageContainedInModule (pn , from );
146+ }
65147 }
66148
67149 @ TargetClass (className = "java.lang.Module" , innerClass = "ReflectionData" , onlyWith = JDK11OrLater .class ) //
@@ -70,3 +152,43 @@ private static final class Target_java_lang_Module_ReflectionData {
70152 static Target_java_lang_WeakPairMap <Module , Class <?>, Boolean > uses ;
71153 }
72154}
155+
156+ class ModuleUtil {
157+ static void checkFromModuleAndPackageNullability (Module from , String pn ) {
158+ if (Objects .isNull (from )) {
159+ throw new NullPointerException ("from_module is null" );
160+ }
161+
162+ if (Objects .isNull (pn )) {
163+ throw new NullPointerException ("package is null" );
164+ }
165+ }
166+
167+ static void checkIsPackageContainedInModule (String pn , Module module ) {
168+ if (module .getPackages ().stream ().noneMatch (p -> p .equals (pn ))) {
169+ throw new IllegalArgumentException ("Package " + pn + " not found in from_module " + module .getName ());
170+ }
171+
172+ // module.getClassLoader().getDefinedPackage(pn);
173+ // TODO print message if package is not in from_module but is in another module
174+ }
175+
176+ static boolean isPackageNameForbidden (String pn ) {
177+ if (!pn .startsWith ("java" )) {
178+ return false ;
179+ }
180+ char trailingChar = pn .length () < 5 ? '/' : pn .charAt ("java" .length ());
181+ return trailingChar == '/' ;
182+ }
183+
184+ static boolean isValidPackageName (String pn ) {
185+ // It is OK to use SourceVersion.isName here even though it calls String.split()
186+ // because pattern "\\." will take the fast path in the String.split() method
187+ return Objects .nonNull (pn ) && !pn .isEmpty () && SourceVersion .isName (pn );
188+ }
189+
190+ static boolean moduleAlreadyExists (Module module ) {
191+ // TODO
192+ return false ;
193+ }
194+ }
0 commit comments