< prev index next >

src/java.base/share/classes/java/lang/reflect/Module.java

Print this page
rev 16428 : 8171855: Move package name transformations during module bootstrap into native code
Reviewed-by: alanb, acorn, lfoltan, mchung, plevart, hseigel, sspitsyn


 111      * Creates a new named Module. The resulting Module will be defined to the
 112      * VM but will not read any other modules, will not have any exports setup
 113      * and will not be registered in the service catalog.
 114      */
 115     private Module(Layer layer,
 116                    ClassLoader loader,
 117                    ModuleDescriptor descriptor,
 118                    URI uri)
 119     {
 120         this.layer = layer;
 121         this.name = descriptor.name();
 122         this.loader = loader;
 123         this.descriptor = descriptor;
 124 
 125         // define module to VM
 126 
 127         boolean isOpen = descriptor.isOpen();
 128         Version version = descriptor.version().orElse(null);
 129         String vs = Objects.toString(version, null);
 130         String loc = Objects.toString(uri, null);
 131         Set<String> packages = descriptor.packages();
 132         int n = packages.size();
 133         String[] array = new String[n];
 134         int i = 0;
 135         for (String pn : packages) {
 136             array[i++] = pn.replace('.', '/');
 137         }
 138         defineModule0(this, isOpen, vs, loc, array);
 139     }
 140 
 141 
 142     /**
 143      * Create the unnamed Module for the given ClassLoader.
 144      *
 145      * @see ClassLoader#getUnnamedModule
 146      */
 147     private Module(ClassLoader loader) {
 148         this.layer = null;
 149         this.name = null;
 150         this.loader = loader;
 151         this.descriptor = null;
 152     }
 153 
 154 
 155     /**
 156      * Creates a named module but without defining the module to the VM.
 157      *
 158      * @apiNote This constructor is for VM white-box testing.


 772                                        boolean syncVM) {
 773         Objects.requireNonNull(other);
 774         Objects.requireNonNull(pn);
 775 
 776         // all packages are open in unnamed and open modules
 777         if (!isNamed() || descriptor.isOpen())
 778             return;
 779 
 780         // nothing to do if already exported/open to other
 781         if (implIsExportedOrOpen(pn, other, open))
 782             return;
 783 
 784         // can only export a package in the module
 785         if (!containsPackage(pn)) {
 786             throw new IllegalArgumentException("package " + pn
 787                                                + " not in contents");
 788         }
 789 
 790         // update VM first, just in case it fails
 791         if (syncVM) {
 792             String pkgInternalForm = pn.replace('.', '/');
 793             if (other == EVERYONE_MODULE) {
 794                 addExportsToAll0(this, pkgInternalForm);
 795             } else if (other == ALL_UNNAMED_MODULE) {
 796                 addExportsToAllUnnamed0(this, pkgInternalForm);
 797             } else {
 798                 addExports0(this, pkgInternalForm, other);
 799             }
 800         }
 801 
 802         // add package name to reflectivelyExports if absent
 803         Map<String, Boolean> map = reflectivelyExports
 804             .computeIfAbsent(this, other,
 805                              (m1, m2) -> new ConcurrentHashMap<>());
 806 
 807         if (open) {
 808             map.put(pn, Boolean.TRUE);  // may need to promote from FALSE to TRUE
 809         } else {
 810             map.putIfAbsent(pn, Boolean.FALSE);
 811         }
 812     }
 813 
 814 
 815     // -- services --
 816 
 817     // additional service type (2nd key) that some module (1st key) uses
 818     private static final WeakPairMap<Module, Class<?>, Boolean> reflectivelyUses


1004             return;
1005         }
1006         synchronized (this) {
1007             // recheck under lock
1008             extraPackages = this.extraPackages;
1009             if (extraPackages != null) {
1010                 if (extraPackages.contains(pn)) {
1011                     // already added
1012                     return;
1013                 }
1014 
1015                 // copy the set
1016                 extraPackages = new HashSet<>(extraPackages);
1017                 extraPackages.add(pn);
1018             } else {
1019                 extraPackages = Collections.singleton(pn);
1020             }
1021 
1022             // update VM first, just in case it fails
1023             if (syncVM)
1024                 addPackage0(this, pn.replace('.', '/'));
1025 
1026             // replace with new set
1027             this.extraPackages = extraPackages; // volatile write
1028         }
1029     }
1030 
1031 
1032     // -- creating Module objects --
1033 
1034     /**
1035      * Defines all module in a configuration to the runtime.
1036      *
1037      * @return a map of module name to runtime {@code Module}
1038      *
1039      * @throws IllegalArgumentException
1040      *         If defining any of the modules to the VM fails
1041      */
1042     static Map<String, Module> defineModules(Configuration cf,
1043                                              Function<String, ClassLoader> clf,
1044                                              Layer layer)


1163                     Optional<Module> om = layer.findModule(dn);
1164                     assert om.isPresent() : dn + " not found in layer";
1165                     Module m = om.get();
1166                     assert m.getLayer() == layer : m + " not in expected layer";
1167                     return m;
1168                 })
1169                 .orElse(null);
1170     }
1171 
1172     /**
1173      * Initialize the maps of exported and open packages for module m.
1174      */
1175     private static void initExportsAndOpens(ModuleDescriptor descriptor,
1176                                             Map<String, Module> nameToModule,
1177                                             Module m)
1178     {
1179         // The VM doesn't know about open modules so need to export all packages
1180         if (descriptor.isOpen()) {
1181             assert descriptor.opens().isEmpty();
1182             for (String source : descriptor.packages()) {
1183                 String sourceInternalForm = source.replace('.', '/');
1184                 addExportsToAll0(m, sourceInternalForm);
1185             }
1186             return;
1187         }
1188 
1189         Map<String, Set<Module>> openPackages = new HashMap<>();
1190         Map<String, Set<Module>> exportedPackages = new HashMap<>();
1191 
1192         // process the open packages first
1193         for (Opens opens : descriptor.opens()) {
1194             String source = opens.source();
1195             String sourceInternalForm = source.replace('.', '/');
1196 
1197             if (opens.isQualified()) {
1198                 // qualified opens
1199                 Set<Module> targets = new HashSet<>();
1200                 for (String target : opens.targets()) {
1201                     // only open to modules that are in this configuration
1202                     Module m2 = nameToModule.get(target);
1203                     if (m2 != null) {
1204                         addExports0(m, sourceInternalForm, m2);
1205                         targets.add(m2);
1206                     }
1207                 }
1208                 if (!targets.isEmpty()) {
1209                     openPackages.put(source, targets);
1210                 }
1211             } else {
1212                 // unqualified opens
1213                 addExportsToAll0(m, sourceInternalForm);
1214                 openPackages.put(source, EVERYONE_SET);
1215             }
1216         }
1217 
1218         // next the exports, skipping exports when the package is open
1219         for (Exports exports : descriptor.exports()) {
1220             String source = exports.source();
1221             String sourceInternalForm = source.replace('.', '/');
1222 
1223             // skip export if package is already open to everyone
1224             Set<Module> openToTargets = openPackages.get(source);
1225             if (openToTargets != null && openToTargets.contains(EVERYONE_MODULE))
1226                 continue;
1227 
1228             if (exports.isQualified()) {
1229                 // qualified exports
1230                 Set<Module> targets = new HashSet<>();
1231                 for (String target : exports.targets()) {
1232                     // only export to modules that are in this configuration
1233                     Module m2 = nameToModule.get(target);
1234                     if (m2 != null) {
1235                         // skip qualified export if already open to m2
1236                         if (openToTargets == null || !openToTargets.contains(m2)) {
1237                             addExports0(m, sourceInternalForm, m2);
1238                             targets.add(m2);
1239                         }
1240                     }
1241                 }
1242                 if (!targets.isEmpty()) {
1243                     exportedPackages.put(source, targets);
1244                 }
1245 
1246             } else {
1247                 // unqualified exports
1248                 addExportsToAll0(m, sourceInternalForm);
1249                 exportedPackages.put(source, EVERYONE_SET);
1250             }
1251         }
1252 
1253         if (!openPackages.isEmpty())
1254             m.openPackages = openPackages;
1255         if (!exportedPackages.isEmpty())
1256             m.exportedPackages = exportedPackages;
1257     }
1258 
1259 
1260     // -- annotations --
1261 
1262     /**
1263      * {@inheritDoc}
1264      * This method returns {@code null} when invoked on an unnamed module.
1265      */
1266     @Override
1267     public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
1268         return moduleInfoClass().getDeclaredAnnotation(annotationClass);




 111      * Creates a new named Module. The resulting Module will be defined to the
 112      * VM but will not read any other modules, will not have any exports setup
 113      * and will not be registered in the service catalog.
 114      */
 115     private Module(Layer layer,
 116                    ClassLoader loader,
 117                    ModuleDescriptor descriptor,
 118                    URI uri)
 119     {
 120         this.layer = layer;
 121         this.name = descriptor.name();
 122         this.loader = loader;
 123         this.descriptor = descriptor;
 124 
 125         // define module to VM
 126 
 127         boolean isOpen = descriptor.isOpen();
 128         Version version = descriptor.version().orElse(null);
 129         String vs = Objects.toString(version, null);
 130         String loc = Objects.toString(uri, null);
 131         String[] packages = descriptor.packages().toArray(new String[0]);
 132         defineModule0(this, isOpen, vs, loc, packages);






 133     }
 134 
 135 
 136     /**
 137      * Create the unnamed Module for the given ClassLoader.
 138      *
 139      * @see ClassLoader#getUnnamedModule
 140      */
 141     private Module(ClassLoader loader) {
 142         this.layer = null;
 143         this.name = null;
 144         this.loader = loader;
 145         this.descriptor = null;
 146     }
 147 
 148 
 149     /**
 150      * Creates a named module but without defining the module to the VM.
 151      *
 152      * @apiNote This constructor is for VM white-box testing.


 766                                        boolean syncVM) {
 767         Objects.requireNonNull(other);
 768         Objects.requireNonNull(pn);
 769 
 770         // all packages are open in unnamed and open modules
 771         if (!isNamed() || descriptor.isOpen())
 772             return;
 773 
 774         // nothing to do if already exported/open to other
 775         if (implIsExportedOrOpen(pn, other, open))
 776             return;
 777 
 778         // can only export a package in the module
 779         if (!containsPackage(pn)) {
 780             throw new IllegalArgumentException("package " + pn
 781                                                + " not in contents");
 782         }
 783 
 784         // update VM first, just in case it fails
 785         if (syncVM) {

 786             if (other == EVERYONE_MODULE) {
 787                 addExportsToAll0(this, pn);
 788             } else if (other == ALL_UNNAMED_MODULE) {
 789                 addExportsToAllUnnamed0(this, pn);
 790             } else {
 791                 addExports0(this, pn, other);
 792             }
 793         }
 794 
 795         // add package name to reflectivelyExports if absent
 796         Map<String, Boolean> map = reflectivelyExports
 797             .computeIfAbsent(this, other,
 798                              (m1, m2) -> new ConcurrentHashMap<>());
 799 
 800         if (open) {
 801             map.put(pn, Boolean.TRUE);  // may need to promote from FALSE to TRUE
 802         } else {
 803             map.putIfAbsent(pn, Boolean.FALSE);
 804         }
 805     }
 806 
 807 
 808     // -- services --
 809 
 810     // additional service type (2nd key) that some module (1st key) uses
 811     private static final WeakPairMap<Module, Class<?>, Boolean> reflectivelyUses


 997             return;
 998         }
 999         synchronized (this) {
1000             // recheck under lock
1001             extraPackages = this.extraPackages;
1002             if (extraPackages != null) {
1003                 if (extraPackages.contains(pn)) {
1004                     // already added
1005                     return;
1006                 }
1007 
1008                 // copy the set
1009                 extraPackages = new HashSet<>(extraPackages);
1010                 extraPackages.add(pn);
1011             } else {
1012                 extraPackages = Collections.singleton(pn);
1013             }
1014 
1015             // update VM first, just in case it fails
1016             if (syncVM)
1017                 addPackage0(this, pn);
1018 
1019             // replace with new set
1020             this.extraPackages = extraPackages; // volatile write
1021         }
1022     }
1023 
1024 
1025     // -- creating Module objects --
1026 
1027     /**
1028      * Defines all module in a configuration to the runtime.
1029      *
1030      * @return a map of module name to runtime {@code Module}
1031      *
1032      * @throws IllegalArgumentException
1033      *         If defining any of the modules to the VM fails
1034      */
1035     static Map<String, Module> defineModules(Configuration cf,
1036                                              Function<String, ClassLoader> clf,
1037                                              Layer layer)


1156                     Optional<Module> om = layer.findModule(dn);
1157                     assert om.isPresent() : dn + " not found in layer";
1158                     Module m = om.get();
1159                     assert m.getLayer() == layer : m + " not in expected layer";
1160                     return m;
1161                 })
1162                 .orElse(null);
1163     }
1164 
1165     /**
1166      * Initialize the maps of exported and open packages for module m.
1167      */
1168     private static void initExportsAndOpens(ModuleDescriptor descriptor,
1169                                             Map<String, Module> nameToModule,
1170                                             Module m)
1171     {
1172         // The VM doesn't know about open modules so need to export all packages
1173         if (descriptor.isOpen()) {
1174             assert descriptor.opens().isEmpty();
1175             for (String source : descriptor.packages()) {
1176                 addExportsToAll0(m, source);

1177             }
1178             return;
1179         }
1180 
1181         Map<String, Set<Module>> openPackages = new HashMap<>();
1182         Map<String, Set<Module>> exportedPackages = new HashMap<>();
1183 
1184         // process the open packages first
1185         for (Opens opens : descriptor.opens()) {
1186             String source = opens.source();

1187 
1188             if (opens.isQualified()) {
1189                 // qualified opens
1190                 Set<Module> targets = new HashSet<>();
1191                 for (String target : opens.targets()) {
1192                     // only open to modules that are in this configuration
1193                     Module m2 = nameToModule.get(target);
1194                     if (m2 != null) {
1195                         addExports0(m, source, m2);
1196                         targets.add(m2);
1197                     }
1198                 }
1199                 if (!targets.isEmpty()) {
1200                     openPackages.put(source, targets);
1201                 }
1202             } else {
1203                 // unqualified opens
1204                 addExportsToAll0(m, source);
1205                 openPackages.put(source, EVERYONE_SET);
1206             }
1207         }
1208 
1209         // next the exports, skipping exports when the package is open
1210         for (Exports exports : descriptor.exports()) {
1211             String source = exports.source();

1212 
1213             // skip export if package is already open to everyone
1214             Set<Module> openToTargets = openPackages.get(source);
1215             if (openToTargets != null && openToTargets.contains(EVERYONE_MODULE))
1216                 continue;
1217 
1218             if (exports.isQualified()) {
1219                 // qualified exports
1220                 Set<Module> targets = new HashSet<>();
1221                 for (String target : exports.targets()) {
1222                     // only export to modules that are in this configuration
1223                     Module m2 = nameToModule.get(target);
1224                     if (m2 != null) {
1225                         // skip qualified export if already open to m2
1226                         if (openToTargets == null || !openToTargets.contains(m2)) {
1227                             addExports0(m, source, m2);
1228                             targets.add(m2);
1229                         }
1230                     }
1231                 }
1232                 if (!targets.isEmpty()) {
1233                     exportedPackages.put(source, targets);
1234                 }
1235 
1236             } else {
1237                 // unqualified exports
1238                 addExportsToAll0(m, source);
1239                 exportedPackages.put(source, EVERYONE_SET);
1240             }
1241         }
1242 
1243         if (!openPackages.isEmpty())
1244             m.openPackages = openPackages;
1245         if (!exportedPackages.isEmpty())
1246             m.exportedPackages = exportedPackages;
1247     }
1248 
1249 
1250     // -- annotations --
1251 
1252     /**
1253      * {@inheritDoc}
1254      * This method returns {@code null} when invoked on an unnamed module.
1255      */
1256     @Override
1257     public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
1258         return moduleInfoClass().getDeclaredAnnotation(annotationClass);


< prev index next >