< prev index next >

src/java.base/share/classes/java/lang/module/ModuleInfo.java

Print this page




  30 import java.io.EOFException;
  31 import java.io.IOException;
  32 import java.io.InputStream;
  33 import java.io.UncheckedIOException;
  34 import java.lang.module.ModuleDescriptor.Builder;
  35 import java.lang.module.ModuleDescriptor.Requires;
  36 import java.lang.module.ModuleDescriptor.Exports;
  37 import java.lang.module.ModuleDescriptor.Opens;
  38 import java.nio.ByteBuffer;
  39 import java.nio.BufferUnderflowException;
  40 import java.util.ArrayList;
  41 import java.util.Collections;
  42 import java.util.HashMap;
  43 import java.util.HashSet;
  44 import java.util.List;
  45 import java.util.Map;
  46 import java.util.Set;
  47 import java.util.function.Supplier;
  48 
  49 import jdk.internal.module.ModuleHashes;

  50 
  51 import static jdk.internal.module.ClassFileConstants.*;
  52 
  53 
  54 /**
  55  * Read module information from a {@code module-info} class file.
  56  *
  57  * @implNote The rationale for the hand-coded reader is startup performance
  58  * and fine control over the throwing of InvalidModuleDescriptorException.
  59  */
  60 
  61 final class ModuleInfo {
  62 
  63     // supplies the set of packages when ModulePackages attribute not present
  64     private final Supplier<Set<String>> packageFinder;
  65 
  66     // indicates if the ModuleHashes attribute should be parsed
  67     private final boolean parseHashes;
  68 
  69     private ModuleInfo(Supplier<Set<String>> pf, boolean ph) {
  70         packageFinder = pf;
  71         parseHashes = ph;
  72     }


 176 
 177         int fields_count = in.readUnsignedShort();
 178         if (fields_count > 0)
 179             throw invalidModuleDescriptor("Bad #fields");
 180 
 181         int methods_count = in.readUnsignedShort();
 182         if (methods_count > 0)
 183             throw invalidModuleDescriptor("Bad #methods");
 184 
 185         int attributes_count = in.readUnsignedShort();
 186 
 187         // the names of the attributes found in the class file
 188         Set<String> attributes = new HashSet<>();
 189 
 190         Builder builder = null;
 191         Set<String> packages = null;
 192         String version = null;
 193         String mainClass = null;
 194         String[] osValues = null;
 195         ModuleHashes hashes = null;

 196 
 197         for (int i = 0; i < attributes_count ; i++) {
 198             int name_index = in.readUnsignedShort();
 199             String attribute_name = cpool.getUtf8(name_index);
 200             int length = in.readInt();
 201 
 202             boolean added = attributes.add(attribute_name);
 203             if (!added && isAttributeAtMostOnce(attribute_name)) {
 204                 throw invalidModuleDescriptor("More than one "
 205                                               + attribute_name + " attribute");
 206             }
 207 
 208             switch (attribute_name) {
 209 
 210                 case MODULE :
 211                     builder = readModuleAttribute(in, cpool);
 212                     break;
 213 
 214                 case MODULE_PACKAGES :
 215                     packages = readModulePackagesAttribute(in, cpool);


 218                 case MODULE_VERSION :
 219                     version = readModuleVersionAttribute(in, cpool);
 220                     break;
 221 
 222                 case MODULE_MAIN_CLASS :
 223                     mainClass = readModuleMainClassAttribute(in, cpool);
 224                     break;
 225 
 226                 case MODULE_TARGET :
 227                     osValues = readModuleTargetAttribute(in, cpool);
 228                     break;
 229 
 230                 case MODULE_HASHES :
 231                     if (parseHashes) {
 232                         hashes = readModuleHashesAttribute(in, cpool);
 233                     } else {
 234                         in.skipBytes(length);
 235                     }
 236                     break;
 237 




 238                 default:
 239                     if (isAttributeDisallowed(attribute_name)) {
 240                         throw invalidModuleDescriptor(attribute_name
 241                                                       + " attribute not allowed");
 242                     } else {
 243                         in.skipBytes(length);
 244                     }
 245 
 246             }
 247         }
 248 
 249         // the Module attribute is required
 250         if (builder == null) {
 251             throw invalidModuleDescriptor(MODULE + " attribute not found");
 252         }
 253 
 254         // If the ModulePackages attribute is not present then the packageFinder
 255         // is used to find the set of packages
 256         boolean usedPackageFinder = false;
 257         if (packages == null && packageFinder != null) {


 272                         tail = " missing from ModulePackages attribute";
 273                     }
 274                     throw invalidModuleDescriptor("Package " + pn + tail);
 275                 }
 276                 packages.remove(pn);
 277             }
 278             builder.contains(packages);
 279         }
 280 
 281         if (version != null)
 282             builder.version(version);
 283         if (mainClass != null)
 284             builder.mainClass(mainClass);
 285         if (osValues != null) {
 286             if (osValues[0] != null) builder.osName(osValues[0]);
 287             if (osValues[1] != null) builder.osArch(osValues[1]);
 288             if (osValues[2] != null) builder.osVersion(osValues[2]);
 289         }
 290         if (hashes != null)
 291             builder.hashes(hashes);




 292 
 293         return builder.build();
 294     }
 295 
 296     /**
 297      * Reads the Module attribute, returning the ModuleDescriptor.Builder to
 298      * build the corresponding ModuleDescriptor.
 299      */
 300     private Builder readModuleAttribute(DataInput in, ConstantPool cpool)
 301         throws IOException
 302     {
 303         // module_name
 304         int module_name_index = in.readUnsignedShort();
 305         String mn = cpool.getUtf8AsBinaryName(module_name_index);
 306 
 307         Builder builder = new ModuleDescriptor.Builder(mn, /*strict*/ false);
 308 
 309         int module_flags = in.readUnsignedShort();
 310         boolean open = ((module_flags & ACC_OPEN) != 0);
 311         if (open)


 512         int algorithm_index = in.readUnsignedShort();
 513         String algorithm = cpool.getUtf8(algorithm_index);
 514 
 515         int hash_count = in.readUnsignedShort();
 516         Map<String, byte[]> map = new HashMap<>(hash_count);
 517         for (int i=0; i<hash_count; i++) {
 518             int module_name_index = in.readUnsignedShort();
 519             String mn = cpool.getUtf8AsBinaryName(module_name_index);
 520             int hash_length = in.readUnsignedShort();
 521             if (hash_length == 0) {
 522                 throw invalidModuleDescriptor("hash_length == 0");
 523             }
 524             byte[] hash = new byte[hash_length];
 525             in.readFully(hash);
 526             map.put(mn, hash);
 527         }
 528 
 529         return new ModuleHashes(algorithm, map);
 530     }
 531 




























 532 
 533     /**
 534      * Returns true if the given attribute can be present at most once
 535      * in the class file. Returns false otherwise.
 536      */
 537     private static boolean isAttributeAtMostOnce(String name) {
 538 
 539         if (name.equals(MODULE) ||
 540                 name.equals(SOURCE_FILE) ||
 541                 name.equals(SDE) ||
 542                 name.equals(MODULE_PACKAGES) ||
 543                 name.equals(MODULE_VERSION) ||
 544                 name.equals(MODULE_MAIN_CLASS) ||
 545                 name.equals(MODULE_TARGET) ||
 546                 name.equals(MODULE_HASHES))

 547             return true;
 548 
 549         return false;
 550     }
 551 
 552     /**
 553      * Return true if the given attribute name is the name of a pre-defined
 554      * attribute that is not allowed in the class file.
 555      *
 556      * Except for Module, InnerClasses, SourceFile, SourceDebugExtension, and
 557      * Deprecated, none of the pre-defined attributes in JVMS 4.7 may appear.
 558      */
 559     private static boolean isAttributeDisallowed(String name) {
 560         Set<String> notAllowed = predefinedNotAllowed;
 561         if (notAllowed == null) {
 562             notAllowed = Set.of(
 563                     "ConstantValue",
 564                     "Code",
 565                     "StackMapTable",
 566                     "Exceptions",




  30 import java.io.EOFException;
  31 import java.io.IOException;
  32 import java.io.InputStream;
  33 import java.io.UncheckedIOException;
  34 import java.lang.module.ModuleDescriptor.Builder;
  35 import java.lang.module.ModuleDescriptor.Requires;
  36 import java.lang.module.ModuleDescriptor.Exports;
  37 import java.lang.module.ModuleDescriptor.Opens;
  38 import java.nio.ByteBuffer;
  39 import java.nio.BufferUnderflowException;
  40 import java.util.ArrayList;
  41 import java.util.Collections;
  42 import java.util.HashMap;
  43 import java.util.HashSet;
  44 import java.util.List;
  45 import java.util.Map;
  46 import java.util.Set;
  47 import java.util.function.Supplier;
  48 
  49 import jdk.internal.module.ModuleHashes;
  50 import jdk.internal.module.WarnIfResolvedReason;
  51 
  52 import static jdk.internal.module.ClassFileConstants.*;
  53 import static jdk.internal.module.WarnIfResolvedReason.fromClassFileFlags;
  54 
  55 /**
  56  * Read module information from a {@code module-info} class file.
  57  *
  58  * @implNote The rationale for the hand-coded reader is startup performance
  59  * and fine control over the throwing of InvalidModuleDescriptorException.
  60  */
  61 
  62 final class ModuleInfo {
  63 
  64     // supplies the set of packages when ModulePackages attribute not present
  65     private final Supplier<Set<String>> packageFinder;
  66 
  67     // indicates if the ModuleHashes attribute should be parsed
  68     private final boolean parseHashes;
  69 
  70     private ModuleInfo(Supplier<Set<String>> pf, boolean ph) {
  71         packageFinder = pf;
  72         parseHashes = ph;
  73     }


 177 
 178         int fields_count = in.readUnsignedShort();
 179         if (fields_count > 0)
 180             throw invalidModuleDescriptor("Bad #fields");
 181 
 182         int methods_count = in.readUnsignedShort();
 183         if (methods_count > 0)
 184             throw invalidModuleDescriptor("Bad #methods");
 185 
 186         int attributes_count = in.readUnsignedShort();
 187 
 188         // the names of the attributes found in the class file
 189         Set<String> attributes = new HashSet<>();
 190 
 191         Builder builder = null;
 192         Set<String> packages = null;
 193         String version = null;
 194         String mainClass = null;
 195         String[] osValues = null;
 196         ModuleHashes hashes = null;
 197         int moduleResolution = 0;
 198 
 199         for (int i = 0; i < attributes_count ; i++) {
 200             int name_index = in.readUnsignedShort();
 201             String attribute_name = cpool.getUtf8(name_index);
 202             int length = in.readInt();
 203 
 204             boolean added = attributes.add(attribute_name);
 205             if (!added && isAttributeAtMostOnce(attribute_name)) {
 206                 throw invalidModuleDescriptor("More than one "
 207                                               + attribute_name + " attribute");
 208             }
 209 
 210             switch (attribute_name) {
 211 
 212                 case MODULE :
 213                     builder = readModuleAttribute(in, cpool);
 214                     break;
 215 
 216                 case MODULE_PACKAGES :
 217                     packages = readModulePackagesAttribute(in, cpool);


 220                 case MODULE_VERSION :
 221                     version = readModuleVersionAttribute(in, cpool);
 222                     break;
 223 
 224                 case MODULE_MAIN_CLASS :
 225                     mainClass = readModuleMainClassAttribute(in, cpool);
 226                     break;
 227 
 228                 case MODULE_TARGET :
 229                     osValues = readModuleTargetAttribute(in, cpool);
 230                     break;
 231 
 232                 case MODULE_HASHES :
 233                     if (parseHashes) {
 234                         hashes = readModuleHashesAttribute(in, cpool);
 235                     } else {
 236                         in.skipBytes(length);
 237                     }
 238                     break;
 239 
 240                 case MODULE_RESOLUTION :
 241                     moduleResolution = readModuleResolution(in, cpool);
 242                     break;
 243 
 244                 default:
 245                     if (isAttributeDisallowed(attribute_name)) {
 246                         throw invalidModuleDescriptor(attribute_name
 247                                                       + " attribute not allowed");
 248                     } else {
 249                         in.skipBytes(length);
 250                     }
 251 
 252             }
 253         }
 254 
 255         // the Module attribute is required
 256         if (builder == null) {
 257             throw invalidModuleDescriptor(MODULE + " attribute not found");
 258         }
 259 
 260         // If the ModulePackages attribute is not present then the packageFinder
 261         // is used to find the set of packages
 262         boolean usedPackageFinder = false;
 263         if (packages == null && packageFinder != null) {


 278                         tail = " missing from ModulePackages attribute";
 279                     }
 280                     throw invalidModuleDescriptor("Package " + pn + tail);
 281                 }
 282                 packages.remove(pn);
 283             }
 284             builder.contains(packages);
 285         }
 286 
 287         if (version != null)
 288             builder.version(version);
 289         if (mainClass != null)
 290             builder.mainClass(mainClass);
 291         if (osValues != null) {
 292             if (osValues[0] != null) builder.osName(osValues[0]);
 293             if (osValues[1] != null) builder.osArch(osValues[1]);
 294             if (osValues[2] != null) builder.osVersion(osValues[2]);
 295         }
 296         if (hashes != null)
 297             builder.hashes(hashes);
 298         if (moduleResolution != 0) {
 299             builder.doNotResolveByDefault(doNotResolveFromFlags(moduleResolution));
 300             builder.warnIfResolved(fromClassFileFlags(moduleResolution));
 301         }
 302 
 303         return builder.build();
 304     }
 305 
 306     /**
 307      * Reads the Module attribute, returning the ModuleDescriptor.Builder to
 308      * build the corresponding ModuleDescriptor.
 309      */
 310     private Builder readModuleAttribute(DataInput in, ConstantPool cpool)
 311         throws IOException
 312     {
 313         // module_name
 314         int module_name_index = in.readUnsignedShort();
 315         String mn = cpool.getUtf8AsBinaryName(module_name_index);
 316 
 317         Builder builder = new ModuleDescriptor.Builder(mn, /*strict*/ false);
 318 
 319         int module_flags = in.readUnsignedShort();
 320         boolean open = ((module_flags & ACC_OPEN) != 0);
 321         if (open)


 522         int algorithm_index = in.readUnsignedShort();
 523         String algorithm = cpool.getUtf8(algorithm_index);
 524 
 525         int hash_count = in.readUnsignedShort();
 526         Map<String, byte[]> map = new HashMap<>(hash_count);
 527         for (int i=0; i<hash_count; i++) {
 528             int module_name_index = in.readUnsignedShort();
 529             String mn = cpool.getUtf8AsBinaryName(module_name_index);
 530             int hash_length = in.readUnsignedShort();
 531             if (hash_length == 0) {
 532                 throw invalidModuleDescriptor("hash_length == 0");
 533             }
 534             byte[] hash = new byte[hash_length];
 535             in.readFully(hash);
 536             map.put(mn, hash);
 537         }
 538 
 539         return new ModuleHashes(algorithm, map);
 540     }
 541 
 542     /**
 543      * Reads the ModuleResolution attribute.
 544      */
 545     private int readModuleResolution(DataInput in, ConstantPool cpool)
 546         throws IOException
 547     {
 548         int flags = in.readUnsignedShort();
 549 
 550         // just some basic validation
 551         int reason = 0;
 552         if ((flags & WARN_DEPRECATED) != 0)
 553             reason = WARN_DEPRECATED;
 554         if ((flags & WARN_DEPRECATED_FOR_REMOVAL) != 0) {
 555             if (reason != 0)
 556                 throw invalidModuleDescriptor("Bad module resolution flags:" + flags);
 557             reason = WARN_DEPRECATED_FOR_REMOVAL;
 558         }
 559         if ((flags & WARN_INCUBATING) != 0) {
 560             if (reason != 0)
 561                 throw invalidModuleDescriptor("Bad module resolution flags:" + flags);
 562         }
 563 
 564         return flags;
 565     }
 566 
 567     private boolean doNotResolveFromFlags(int flags) {
 568         return (flags & DO_NOT_RESOLVE_BY_DEFAULT) != 0;
 569     }
 570 
 571     /**
 572      * Returns true if the given attribute can be present at most once
 573      * in the class file. Returns false otherwise.
 574      */
 575     private static boolean isAttributeAtMostOnce(String name) {
 576 
 577         if (name.equals(MODULE) ||
 578                 name.equals(SOURCE_FILE) ||
 579                 name.equals(SDE) ||
 580                 name.equals(MODULE_PACKAGES) ||
 581                 name.equals(MODULE_VERSION) ||
 582                 name.equals(MODULE_MAIN_CLASS) ||
 583                 name.equals(MODULE_TARGET) ||
 584                 name.equals(MODULE_HASHES) ||
 585                 name.equals(MODULE_RESOLUTION))
 586             return true;
 587 
 588         return false;
 589     }
 590 
 591     /**
 592      * Return true if the given attribute name is the name of a pre-defined
 593      * attribute that is not allowed in the class file.
 594      *
 595      * Except for Module, InnerClasses, SourceFile, SourceDebugExtension, and
 596      * Deprecated, none of the pre-defined attributes in JVMS 4.7 may appear.
 597      */
 598     private static boolean isAttributeDisallowed(String name) {
 599         Set<String> notAllowed = predefinedNotAllowed;
 600         if (notAllowed == null) {
 601             notAllowed = Set.of(
 602                     "ConstantValue",
 603                     "Code",
 604                     "StackMapTable",
 605                     "Exceptions",


< prev index next >