1 /*
   2  * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.lang.module;
  27 
  28 import java.io.InputStream;
  29 import java.io.IOException;
  30 import java.io.UncheckedIOException;
  31 import java.nio.ByteBuffer;
  32 import java.util.ArrayList;
  33 import java.util.Collections;
  34 import java.util.EnumSet;
  35 import java.util.HashMap;
  36 import java.util.HashSet;
  37 import java.util.List;
  38 import java.util.Map;
  39 import java.util.Objects;
  40 import java.util.Optional;
  41 import java.util.Set;
  42 import java.util.function.Supplier;
  43 
  44 import static jdk.internal.module.Checks.*;
  45 import static java.util.Objects.*;
  46 
  47 import jdk.internal.module.Checks;
  48 import jdk.internal.module.Hasher.DependencyHashes;
  49 
  50 
  51 /**
  52  * A module descriptor.
  53  *
  54  * <p> A {@code ModuleDescriptor} is typically created from the binary form
  55  * of a module declaration. The associated {@link ModuleDescriptor.Builder}
  56  * class can also be used to create a {@code ModuleDescriptor} from its
  57  * components. </p>
  58  *
  59  * <p> {@code ModuleDescriptor} objects are immutable and safe for use by
  60  * multiple concurrent threads.</p>
  61  *
  62  * @since 9
  63  * @see java.lang.reflect.Module
  64  */
  65 
  66 public class ModuleDescriptor
  67     implements Comparable<ModuleDescriptor>
  68 {
  69 
  70     /**
  71      * <p> A dependence upon a module </p>
  72      *
  73      * @see ModuleDescriptor#requires()
  74      * @since 9
  75      */
  76 
  77     public final static class Requires
  78         implements Comparable<Requires>
  79     {
  80 
  81         /**
  82          * A modifier on a module dependence.
  83          *
  84          * @since 9
  85          */
  86         public static enum Modifier {
  87 
  88             /**
  89              * The dependence causes any module which depends on the <i>current
  90              * module</i> to have an implicitly declared dependence on the module
  91              * named by the {@code Requires}.
  92              */
  93             PUBLIC,
  94 
  95             /**
  96              * The dependence was not explicitly or implicitly declared in the
  97              * source of the module declaration.
  98              */
  99             SYNTHETIC,
 100 
 101             /**
 102              * The dependence was implicitly declared in the source of the module
 103              * declaration.
 104              */
 105             MANDATED;
 106 
 107         }
 108 
 109         private final Set<Modifier> mods;
 110         private final String name;
 111 
 112         private Requires(Set<Modifier> ms, String mn) {
 113             this(ms, mn, true);
 114         }
 115         private Requires(Set<Modifier> ms, String mn, boolean check) {
 116             if (ms == null || ms.isEmpty()) {
 117                 mods = Collections.emptySet();
 118             } else {
 119                 mods = check ? Collections.unmodifiableSet(EnumSet.copyOf(ms))
 120                              : ms;
 121             }
 122             this.name = check ? requireModuleName(mn) : mn;
 123         }
 124 
 125         /**
 126          * Returns the set of modifiers.
 127          *
 128          * @return A possibly-empty unmodifiable set of modifiers
 129          */
 130         public Set<Modifier> modifiers() {
 131             return mods;
 132         }
 133 
 134         /**
 135          * Return the module name.
 136          *
 137          * @return The module name
 138          */
 139         public String name() {
 140             return name;
 141         }
 142 
 143         /**
 144          * Compares this module dependence to another.
 145          *
 146          * <p> Two {@code Requires} objects are compared by comparing their
 147          * module name lexicographically.  Where the module names are equal then
 148          * the sets of modifiers are compared.
 149          *
 150          * @return A negative integer, zero, or a positive integer if this module
 151          *         dependence is less than, equal to, or greater than the given
 152          *         module dependence
 153          */
 154         @Override
 155         public int compareTo(Requires that) {
 156             int c = this.name().compareTo(that.name());
 157             if (c != 0)
 158                 return c;
 159             // same name, compare by modifiers
 160             return Long.compare(this.modsValue(), that.modsValue());
 161         }
 162 
 163         /**
 164          * Return a value for the modifiers to allow sets of modifiers to be
 165          * compared.
 166          */
 167         private long modsValue() {
 168             long value = 0;
 169             for (Modifier m : mods) {
 170                 value += 1 << m.ordinal();
 171             }
 172             return value;
 173         }
 174 
 175 
 176         @Override
 177         public boolean equals(Object ob) {
 178             if (!(ob instanceof Requires))
 179                 return false;
 180             Requires that = (Requires)ob;
 181             return (name.equals(that.name) && mods.equals(that.mods));
 182         }
 183 
 184         @Override
 185         public int hashCode() {
 186             return name.hashCode() * 43 + mods.hashCode();
 187         }
 188 
 189         @Override
 190         public String toString() {
 191             return Dependence.toString(mods, name);
 192         }
 193 
 194     }
 195 
 196 
 197 
 198     /**
 199      * <p> A module export, may be qualified or unqualified. </p>
 200      *
 201      * @see ModuleDescriptor#exports()
 202      * @since 9
 203      */
 204 
 205     public final static class Exports {
 206 
 207         private final String source;
 208         private final Set<String> targets;  // empty if unqualified export
 209 
 210         /**
 211          * Constructs a qualified export.
 212          */
 213         private Exports(String source, Set<String> targets) {
 214             this(source, targets, true);
 215         }
 216 
 217         private Exports(String source, Set<String> targets, boolean check) {
 218             this.source = check ? requirePackageName(source) : source;
 219             targets = check ? Collections.unmodifiableSet(new HashSet<>(targets))
 220                             : Collections.unmodifiableSet(targets);
 221             if (targets.isEmpty())
 222                 throw new IllegalArgumentException("Empty target set");
 223             if (check)
 224                 targets.stream().forEach(Checks::requireModuleName);
 225             this.targets = targets;
 226         }
 227 
 228         /**
 229          * Constructs an unqualified export.
 230          */
 231         private Exports(String source) {
 232             this(source, true);
 233         }
 234         private Exports(String source, boolean check) {
 235             this.source = check ? requirePackageName(source) : source;
 236             this.targets = Collections.emptySet();
 237         }
 238 
 239         /**
 240          * Returns {@code true} if this is a qualified export.
 241          *
 242          * @return {@code true} if this is a qualified export
 243          */
 244         public boolean isQualified() {
 245             return !targets.isEmpty();
 246         }
 247 
 248         /**
 249          * Returns the package name.
 250          *
 251          * @return The package name
 252          */
 253         public String source() {
 254             return source;
 255         }
 256 
 257         /**
 258          * For a qualified export, returns the non-empty and immutable set
 259          * of the module names to which the package is exported. For an
 260          * unqualified export, returns an empty set.
 261          *
 262          * @return The set of target module names or for an unqualified
 263          *         export, an empty set
 264          */
 265         public Set<String> targets() {
 266             return targets;
 267         }
 268 
 269         public int hashCode() {
 270             return hash(source, targets);
 271         }
 272 
 273         public boolean equals(Object obj) {
 274             if (!(obj instanceof Exports))
 275                 return false;
 276             Exports other = (Exports)obj;
 277             return Objects.equals(this.source, other.source) &&
 278                 Objects.equals(this.targets, other.targets);
 279         }
 280 
 281         public String toString() {
 282             if (targets.isEmpty())
 283                 return source;
 284             else
 285                 return source + " to " + targets;
 286         }
 287 
 288     }
 289 
 290 
 291 
 292     /**
 293      * <p> A service that a module provides one or more implementations of. </p>
 294      *
 295      * @see ModuleDescriptor#provides()
 296      * @since 9
 297      */
 298 
 299     public final static class Provides {
 300 
 301         private final String service;
 302         private final Set<String> providers;
 303 
 304         private Provides(String service, Set<String> providers) {
 305             this(service, providers, true);
 306         }
 307 
 308         private Provides(String service, Set<String> providers, boolean check) {
 309             this.service = check ? requireServiceTypeName(service) : service;
 310             providers = check ? Collections.unmodifiableSet(new HashSet<>(providers))
 311                               : Collections.unmodifiableSet(providers);
 312             if (providers.isEmpty())
 313                 throw new IllegalArgumentException("Empty providers set");
 314             if (check)
 315                 providers.forEach(Checks::requireServiceProviderName);
 316             this.providers = providers;
 317         }
 318 
 319         /**
 320          * Returns the fully qualified class name of the service type.
 321          *
 322          * @return The fully qualified class name of the service type.
 323          */
 324         public String service() { return service; }
 325 
 326         /**
 327          * Returns the set of the fully qualified class names of the providers.
 328          *
 329          * @return A non-empty and unmodifiable set of the fully qualified class
 330          *         names of the providers.
 331          */
 332         public Set<String> providers() { return providers; }
 333 
 334         public int hashCode() {
 335             return hash(service, providers);
 336         }
 337 
 338         public boolean equals(Object obj) {
 339             if (!(obj instanceof Provides))
 340                 return false;
 341             Provides other = (Provides)obj;
 342             return Objects.equals(this.service, other.service) &&
 343                     Objects.equals(this.providers, other.providers);
 344         }
 345 
 346     }
 347 
 348 
 349 
 350     /**
 351      * Vaguely Debian-like version strings, for now.
 352      * This will, eventually, change.
 353      *
 354      * @see <a href="http://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Version">Debian
 355      * Policy Manual, Chapter 5: Control files and their fields</a>
 356      *
 357      * @see ModuleDescriptor#version()
 358      * @since 9
 359      */
 360 
 361     public final static class Version
 362         implements Comparable<Version>
 363     {
 364 
 365         private final String version;
 366 
 367         // If Java had disjunctive types then we'd write List<Integer|String> here
 368         //
 369         private final List<Object> sequence;
 370         private final List<Object> branch;
 371 
 372         // Take a numeric token starting at position i
 373         // Append it to the given list
 374         // Return the index of the first character not taken
 375         // Requires: s.charAt(i) is (decimal) numeric
 376         //
 377         private static int takeNumber(String s, int i, List<Object> acc) {
 378             char c = s.charAt(i);
 379             int d = (c - '0');
 380             int n = s.length();
 381             while (++i < n) {
 382                 c = s.charAt(i);
 383                 if (c >= '0' && c <= '9') {
 384                     d = d * 10 + (c - '0');
 385                     continue;
 386                 }
 387                 break;
 388             }
 389             acc.add(d);
 390             return i;
 391         }
 392 
 393         // Take a string token starting at position i
 394         // Append it to the given list
 395         // Return the index of the first character not taken
 396         // Requires: s.charAt(i) is not '.'
 397         //
 398         private static int takeString(String s, int i, List<Object> acc) {
 399             int b = i;
 400             int n = s.length();
 401             while (++i < n) {
 402                 char c = s.charAt(i);
 403                 if (c != '.' && c != '-' && !(c >= '0' && c <= '9'))
 404                     continue;
 405                 break;
 406             }
 407             acc.add(s.substring(b, i));
 408             return i;
 409         }
 410 
 411         // Version syntax, for now: tok+ ( '-' tok+)?
 412         // First token string is sequence, second is branch
 413         // Tokens are delimited by '.', or by changes between alpha & numeric
 414         // chars
 415         // Numeric tokens are compared as decimal numbers
 416         // Non-numeric tokens are compared lexicographically
 417         // Tokens in branch may contain '-'
 418         //
 419         private Version(String v) {
 420 
 421             if (v == null)
 422                 throw new IllegalArgumentException("Null version string");
 423             int n = v.length();
 424             if (n == 0)
 425                 throw new IllegalArgumentException("Empty version string");
 426 
 427             int i = 0;
 428             char c = v.charAt(i);
 429             if (!(c >= '0' && c <= '9'))
 430                 throw new
 431                         IllegalArgumentException(v
 432                         + ": Version does not start"
 433                         + " with a number");
 434 
 435             List<Object> sequence = new ArrayList<>(4);
 436             List<Object> branch = new ArrayList<>(2);
 437 
 438             i = takeNumber(v, i, sequence);
 439 
 440             while (i < n) {
 441                 c = v.charAt(i);
 442                 if (c == '.') {
 443                     i++;
 444                     continue;
 445                 }
 446                 if (c == '-') {
 447                     i++;
 448                     break;
 449                 }
 450                 if (c >= '0' && c <= '9')
 451                     i = takeNumber(v, i, sequence);
 452                 else
 453                     i = takeString(v, i, sequence);
 454             }
 455 
 456             if (c == '-' && i >= n)
 457                 throw new IllegalArgumentException(v + ": Empty branch");
 458 
 459             while (i < n) {
 460                 c = v.charAt(i);
 461                 if (c >= '0' && c <= '9')
 462                     i = takeNumber(v, i, branch);
 463                 else
 464                     i = takeString(v, i, branch);
 465                 if (i >= n)
 466                     break;
 467                 c = v.charAt(i);
 468                 if (c == '.') {
 469                     i++;
 470                     continue;
 471                 }
 472             }
 473 
 474             this.version = v;
 475             this.sequence = sequence;
 476             this.branch = branch;
 477         }
 478 
 479         /**
 480          * Parses the given string as a version string.
 481          *
 482          * @param  v
 483          *         The string to parse as a version string
 484          *
 485          * @return The resulting {@code Version}
 486          *
 487          * @throws IllegalArgumentException
 488          *         If {@code v} is {@code null}, an empty string, or cannot be
 489          *         parsed as a version string
 490          */
 491         public static Version parse(String v) {
 492             return new Version(v);
 493         }
 494 
 495         @SuppressWarnings("unchecked")
 496         private int cmp(Object o1, Object o2) {
 497             return ((Comparable)o1).compareTo(o2);
 498         }
 499 
 500         private int compareTokens(List<Object> ts1, List<Object> ts2) {
 501             int n = Math.min(ts1.size(), ts2.size());
 502             for (int i = 0; i < n; i++) {
 503                 Object o1 = ts1.get(i);
 504                 Object o2 = ts2.get(i);
 505                 if (   (o1 instanceof Integer && o2 instanceof Integer)
 506                         || (o1 instanceof String && o2 instanceof String)) {
 507                     int c = cmp(o1, o2);
 508                     if (c == 0)
 509                         continue;
 510                     return c;
 511                 }
 512                 // Types differ, so convert number to string form
 513                 int c = o1.toString().compareTo(o2.toString());
 514                 if (c == 0)
 515                     continue;
 516                 return c;
 517             }
 518             List<Object> rest = ts1.size() > ts2.size() ? ts1 : ts2;
 519             int e = rest.size();
 520             for (int i = n; i < e; i++) {
 521                 Object o = rest.get(i);
 522                 if (o instanceof Integer && ((Integer)o) == 0)
 523                     continue;
 524                 return ts1.size() - ts2.size();
 525             }
 526             return 0;
 527         }
 528 
 529         @Override
 530         public int compareTo(Version that) {
 531             int c = compareTokens(this.sequence, that.sequence);
 532             if (c != 0)
 533                 return c;
 534             return compareTokens(this.branch, that.branch);
 535         }
 536 
 537         @Override
 538         public boolean equals(Object ob) {
 539             if (!(ob instanceof Version))
 540                 return false;
 541             return compareTo((Version)ob) == 0;
 542         }
 543 
 544         @Override
 545         public int hashCode() {
 546             return version.hashCode();
 547         }
 548 
 549         @Override
 550         public String toString() {
 551             return version;
 552         }
 553 
 554     }
 555 
 556 
 557 
 558     // From module declarations
 559     private final String name;
 560     private final Set<Requires> requires;
 561     private final Set<Exports> exports;
 562     private final Set<String> uses;
 563     private final Map<String, Provides> provides;
 564 
 565     // Indicates if synthesised for a JAR file found on the module path
 566     private final boolean automatic;
 567 
 568     // Not generated from a module-info.java
 569     private final boolean synthetic;
 570 
 571     // "Extended" information, added post-compilation by tools
 572     private final Version version;
 573     private final String mainClass;
 574     private final String osName;
 575     private final String osArch;
 576     private final String osVersion;
 577     private final Set<String> conceals;
 578     private final Set<String> packages;
 579     private final DependencyHashes hashes;
 580 
 581     private ModuleDescriptor(String name,
 582                              boolean automatic,
 583                              boolean synthetic,
 584                              Map<String, Requires> requires,
 585                              Set<String> uses,
 586                              Map<String, Exports> exports,
 587                              Map<String, Provides> provides,
 588                              Version version,
 589                              String mainClass,
 590                              String osName,
 591                              String osArch,
 592                              String osVersion,
 593                              Set<String> conceals,
 594                              DependencyHashes hashes)
 595     {
 596 
 597         this.name = name;
 598         this.automatic = automatic;
 599         this.synthetic = synthetic;
 600 
 601         Set<Requires> rqs = new HashSet<>(requires.values());
 602         assert (rqs.stream().map(Requires::name).sorted().distinct().count()
 603                 == rqs.size())
 604             : "Module " + name + " has duplicate requires";
 605         this.requires = emptyOrUnmodifiableSet(rqs);
 606 
 607         Set<Exports> exs = new HashSet<>(exports.values());
 608         assert (exs.stream().map(Exports::source).sorted().distinct().count()
 609                 == exs.size())
 610             : "Module " + name + " has duplicate exports";
 611         this.exports = emptyOrUnmodifiableSet(exs);
 612 
 613         this.uses = emptyOrUnmodifiableSet(uses);
 614         this.provides = emptyOrUnmodifiableMap(provides);
 615 
 616         this.version = version;
 617         this.mainClass = mainClass;
 618         this.osName = osName;
 619         this.osArch = osArch;
 620         this.osVersion = osVersion;
 621         this.hashes = hashes;
 622 
 623         assert !exports.keySet().stream().anyMatch(conceals::contains)
 624             : "Module " + name + ": Package sets overlap";
 625         this.conceals = emptyOrUnmodifiableSet(conceals);
 626         this.packages = computePackages(this.exports, this.conceals);
 627     }
 628 
 629     /**
 630      * Clones the given module descriptor with an augmented set of packages
 631      */
 632     ModuleDescriptor(ModuleDescriptor md, Set<String> pkgs) {
 633         this.name = md.name;
 634         this.automatic = md.automatic;
 635         this.synthetic = md.synthetic;
 636 
 637         this.requires = md.requires;
 638         this.exports = md.exports;
 639         this.uses = md.uses;
 640         this.provides = md.provides;
 641 
 642         this.version = md.version;
 643         this.mainClass = md.mainClass;
 644         this.osName = md.osName;
 645         this.osArch = md.osArch;
 646         this.osVersion = md.osVersion;
 647         this.hashes = null; // need to ignore
 648 
 649         this.packages = emptyOrUnmodifiableSet(pkgs);
 650         this.conceals = computeConcealedPackages(this.exports, this.packages);
 651     }
 652 
 653     /**
 654      * Creates a module descriptor from its components. This method is intended
 655      * for use by the jlink plugin.
 656      */
 657     ModuleDescriptor(String name,
 658                      boolean automatic,
 659                      boolean synthetic,
 660                      Set<Requires> requires,
 661                      Set<String> uses,
 662                      Set<Exports> exports,
 663                      Map<String, Provides> provides,
 664                      Version version,
 665                      String mainClass,
 666                      String osName,
 667                      String osArch,
 668                      String osVersion,
 669                      Set<String> conceals,
 670                      Set<String> packages) {
 671         this.name = name;
 672         this.automatic = automatic;
 673         this.synthetic = synthetic;
 674         this.requires = Collections.unmodifiableSet(requires);
 675         this.exports = Collections.unmodifiableSet(exports);
 676         this.uses = Collections.unmodifiableSet(uses);
 677         this.provides = Collections.unmodifiableMap(provides);
 678         this.conceals = Collections.unmodifiableSet(conceals);
 679         this.packages = Collections.unmodifiableSet(packages);
 680 
 681         this.version = version;
 682         this.mainClass = mainClass;
 683         this.osName = osName;
 684         this.osArch = osArch;
 685         this.osVersion = osVersion;
 686         this.hashes = null;
 687     }
 688 
 689     /**
 690      * <p> The module name. </p>
 691      *
 692      * @return The module name
 693      */
 694     public String name() {
 695         return name;
 696     }
 697 
 698     /**
 699      * <p> Returns {@code true} if this is an automatic module. </p>
 700      *
 701      * <p> An automatic module is defined implicitly rather than explicitly
 702      * and therefore does not have a module declaration. JAR files located on
 703      * the application module path, or by the {@link ModuleFinder} returned by
 704      * {@link ModuleFinder#of(java.nio.file.Path[]) ModuleFinder.of}, are
 705      * treated as automatic modules if they do have not have a module
 706      * declaration. </p>
 707      *
 708      * @return  {@code true} if this is an automatic module
 709      */
 710     public boolean isAutomatic() {
 711         return automatic;
 712     }
 713 
 714     /**
 715      * <p> Returns {@code true} if this module descriptor was not generated
 716      * from an explicit module declaration ({@code module-info.java})
 717      * or an implicit module declaration (an {@link #isAutomatic() automatic}
 718      * module). </p>
 719      *
 720      * @return  {@code true} if this module descriptor was not generated by
 721      *          an explicit or implicit module declaration
 722      *
 723      * @jvms 4.7.8 The {@code Synthetic} Attribute
 724      */
 725     public boolean isSynthetic() {
 726         return synthetic;
 727     }
 728 
 729     /**
 730      * <p> The dependences of this module. </p>
 731      *
 732      * @return  A possibly-empty unmodifiable set of {@link Requires} objects
 733      */
 734     public Set<Requires> requires() {
 735         return requires;
 736     }
 737 
 738     /**
 739      * <p> The service dependences of this module. </p>
 740      *
 741      * @return  A possibly-empty unmodifiable set of the fully qualified class
 742      *          names of the service types used
 743      */
 744     public Set<String> uses() {
 745         return uses;
 746     }
 747 
 748     /**
 749      * <p> The services that this module provides. </p>
 750      *
 751      * @return The possibly-empty unmodifiable map of the services that this
 752      *         module provides. The map key is fully qualified class name of
 753      *         the service type.
 754      */
 755     public Map<String, Provides> provides() {
 756         return provides;
 757     }
 758 
 759     /**
 760      * <p> The module exports. </p>
 761      *
 762      * @return  A possibly-empty unmodifiable set of exported packages
 763      */
 764     public Set<Exports> exports() {
 765         return exports;
 766     }
 767 
 768     /**
 769      * Returns this module's version.
 770      *
 771      * @return This module's version
 772      */
 773     public Optional<Version> version() {
 774         return Optional.ofNullable(version);
 775     }
 776 
 777     /**
 778      * Returns a string containing this module's name and, if present, its
 779      * version.
 780      *
 781      * @return A string containing this module's name and, if present, its
 782      *         version.
 783      */
 784     public String toNameAndVersion() {
 785         if (version != null) {
 786             return name() + "@" + version;
 787         } else {
 788             return name();
 789         }
 790     }
 791 
 792     /**
 793      * Returns the module's main class.
 794      *
 795      * @return The fully qualified class name of this module's main class
 796      */
 797     public Optional<String> mainClass() {
 798         return Optional.ofNullable(mainClass);
 799     }
 800 
 801     /**
 802      * Returns the operating system name if this module is operating system
 803      * specific.
 804      *
 805      * @return The operating system name or an empty {@code Optional}
 806      *         if this module is not operating system specific
 807      */
 808     public Optional<String> osName() {
 809         return Optional.ofNullable(osName);
 810     }
 811 
 812     /**
 813      * Returns the operating system architecture if this module is operating
 814      * system architecture specific.
 815      *
 816      * @return The operating system architecture or an empty {@code Optional}
 817      *         if this module is not operating system architecture specific
 818      */
 819     public Optional<String> osArch() {
 820         return Optional.ofNullable(osArch);
 821     }
 822 
 823     /**
 824      * Returns the operating system version if this module is operating
 825      * system version specific.
 826      *
 827      * @return The operating system version or an empty {@code Optional}
 828      *         if this module is not operating system version specific
 829      */
 830     public Optional<String> osVersion() {
 831         return Optional.ofNullable(osVersion);
 832     }
 833 
 834     /**
 835      * Returns the names of the packages defined in, but not exported by, this
 836      * module.
 837      *
 838      * @return A possibly-empty unmodifiable set of the concealed packages
 839      */
 840     public Set<String> conceals() {
 841         return conceals;
 842     }
 843 
 844     /**
 845      * Returns the names of all the packages defined in this module, whether
 846      * exported or concealed.
 847      *
 848      * @return A possibly-empty unmodifiable set of the all packages
 849      */
 850     public Set<String> packages() {
 851         return packages;
 852     }
 853 
 854     /**
 855      * Returns the object with the hashes of the dependences.
 856      */
 857     Optional<DependencyHashes> hashes() {
 858         return Optional.ofNullable(hashes);
 859     }
 860 
 861 
 862     /**
 863      * A builder used for building {@link ModuleDescriptor} objects.
 864      *
 865      * <p> Example usage: </p>
 866      *
 867      * <pre>{@code
 868      *     ModuleDescriptor descriptor = new ModuleDescriptor.Builder("m1")
 869      *         .requires("m2")
 870      *         .exports("p")
 871      *         .build();
 872      * }</pre>
 873      * @since 9
 874      */
 875     public static final class Builder {
 876 
 877         final String name;
 878         final boolean automatic;
 879         boolean synthetic;
 880         final Map<String, Requires> requires = new HashMap<>();
 881         final Set<String> uses = new HashSet<>();
 882         final Map<String, Exports> exports = new HashMap<>();
 883         final Map<String, Provides> provides = new HashMap<>();
 884         Set<String> conceals = Collections.emptySet();
 885         Version version;
 886         String osName;
 887         String osArch;
 888         String osVersion;
 889         String mainClass;
 890         DependencyHashes hashes;
 891 
 892         /**
 893          * Initializes a new builder with the given module name.
 894          *
 895          * @param  name
 896          *         The module name
 897          *
 898          * @throws IllegalArgumentException
 899          *         If the module name is {@code null} or is not a legal Java
 900          *         identifier
 901          */
 902         public Builder(String name) {
 903             this(name, false);
 904         }
 905 
 906         /* package */ Builder(String name, boolean automatic) {
 907             this.name = requireModuleName(name);
 908             this.automatic = automatic;
 909         }
 910 
 911         /**
 912          * Adds a dependence on a module.
 913          *
 914          * @param  req
 915          *         The dependence
 916          *
 917          * @return This builder
 918          *
 919          * @throws IllegalArgumentException
 920          *         If the dependence is on the module that this builder was
 921          *         initialized to build
 922          * @throws IllegalStateException
 923          *         If the dependence on the module has already been declared
 924          */
 925         public Builder requires(Requires req) {
 926             String mn = req.name();
 927             if (name.equals(mn))
 928                 throw new IllegalArgumentException("Dependence on self");
 929             if (requires.containsKey(mn))
 930                 throw new IllegalStateException("Dependence upon " + mn
 931                                                 + " already declared");
 932             requires.put(mn, req);
 933             return this;
 934         }
 935 
 936         /**
 937          * Adds a dependence on a module with the given (and possibly empty)
 938          * set of modifiers.
 939          *
 940          * @param  mods
 941          *         The set of modifiers
 942          * @param  mn
 943          *         The module name
 944          *
 945          * @return This builder
 946          *
 947          * @throws IllegalArgumentException
 948          *         If the module name is {@code null}, is not a legal Java
 949          *         identifier, or is equal to the module name that this builder
 950          *         was initialized to build
 951          * @throws IllegalStateException
 952          *         If the dependence on the module has already been declared
 953          */
 954         public Builder requires(Set<Requires.Modifier> mods, String mn) {
 955             if (name.equals(mn))
 956                 throw new IllegalArgumentException("Dependence on self: " + mn);
 957             if (requires.containsKey(mn))
 958                 throw new IllegalStateException("Dependence upon " + mn
 959                                                 + " already declared");
 960             requires.put(mn, new Requires(mods, mn)); // checks mn
 961             return this;
 962         }
 963 
 964         /**
 965          * Adds a dependence on a module with an empty set of modifiers.
 966          *
 967          * @param  mn
 968          *         The module name
 969          *
 970          * @return This builder
 971          *
 972          * @throws IllegalArgumentException
 973          *         If the module name is {@code null}, is not a legal Java
 974          *         identifier, or is equal to the module name that this builder
 975          *         was initialized to build
 976          * @throws IllegalStateException
 977          *         If the dependence on the module has already been declared
 978          */
 979         public Builder requires(String mn) {
 980             return requires(EnumSet.noneOf(Requires.Modifier.class), mn);
 981         }
 982 
 983         /**
 984          * Adds a dependence on a module with the given modifier.
 985          *
 986          * @param  mod
 987          *         The modifier
 988          * @param  mn
 989          *         The module name
 990          *
 991          * @return This builder
 992          *
 993          * @throws IllegalArgumentException
 994          *         If the module name is {@code null}, is not a legal Java
 995          *         identifier, or is equal to the module name that this builder
 996          *         was initialized to build
 997          * @throws IllegalStateException
 998          *         If the dependence on the module has already been declared
 999          */
1000         public Builder requires(Requires.Modifier mod, String mn) {
1001             return requires(EnumSet.of(mod), mn);
1002         }
1003 
1004         /**
1005          * Adds a service dependence.
1006          *
1007          * @param  st
1008          *         The service type
1009          *
1010          * @return This builder
1011          *
1012          * @throws IllegalArgumentException
1013          *         If the service type is {@code null} or is not a legal Java
1014          *         identifier
1015          * @throws IllegalStateException
1016          *         If a dependency on the service type has already been declared
1017          */
1018         public Builder uses(String st) {
1019             if (uses.contains(requireServiceTypeName(st)))
1020                 throw new IllegalStateException("Dependence upon service "
1021                                                 + st + " already declared");
1022             uses.add(st);
1023             return this;
1024         }
1025 
1026         /**
1027          * Ensures that the given package name has not been declared as an
1028          * exported or concealed package.
1029          */
1030         private void ensureNotExportedOrConcealed(String pn) {
1031             if (exports.containsKey(pn))
1032                 throw new IllegalStateException("Export of package "
1033                                                 + pn + " already declared");
1034             if (conceals.contains(pn))
1035                 throw new IllegalStateException("Concealed package "
1036                                                 + pn + " already declared");
1037         }
1038 
1039         /**
1040          * Adds an export.
1041          *
1042          * @param  e
1043          *         The export
1044          *
1045          * @return This builder
1046          *
1047          * @throws IllegalStateException
1048          *         If the package is already declared as an exported or
1049          *         concealed package
1050          */
1051         public Builder exports(Exports e) {
1052             String pn = e.source();
1053             ensureNotExportedOrConcealed(pn);
1054             exports.put(pn, e);
1055             return this;
1056         }
1057 
1058         /**
1059          * Adds an export to a set of target modules.
1060          *
1061          * @param  pn
1062          *         The package name
1063          * @param  targets
1064          *         The set of target modules names
1065          *
1066          * @return This builder
1067          *
1068          * @throws IllegalArgumentException
1069          *         If the package name or any of the target modules is {@code
1070          *         null} or is not a legal Java identifier, or the set of
1071          *         targets is empty
1072          * @throws IllegalStateException
1073          *         If the package is already declared as an exported or
1074          *         concealed package
1075          */
1076         public Builder exports(String pn, Set<String> targets) {
1077             ensureNotExportedOrConcealed(pn);
1078             exports.put(pn, new Exports(pn, targets)); // checks pn and targets
1079             return this;
1080         }
1081 
1082         /**
1083          * Adds an export to a target module.
1084          *
1085          * @param  pn
1086          *         The package name
1087          * @param  target
1088          *         The target module name
1089          *
1090          * @return This builder
1091          *
1092          * @throws IllegalArgumentException
1093          *         If the package name or target module is {@code null} or is
1094          *         not a legal Java identifier
1095          * @throws IllegalStateException
1096          *         If the package is already declared as an exported or
1097          *         concealed package
1098          */
1099         public Builder exports(String pn, String target) {
1100             return exports(pn, Collections.singleton(target));
1101         }
1102 
1103         /**
1104          * Adds an export.
1105          *
1106          * @param  pn
1107          *         The package name
1108          *
1109          * @return This builder
1110          *
1111          * @throws IllegalArgumentException
1112          *         If the package name is {@code null} or is not a legal Java
1113          *         identifier
1114          * @throws IllegalStateException
1115          *         If the package is already declared as an exported or
1116          *         concealed package
1117          */
1118         public Builder exports(String pn) {
1119             ensureNotExportedOrConcealed(pn);
1120             exports.put(pn, new Exports(pn)); // checks pn
1121             return this;
1122         }
1123 
1124         // Used by ModuleInfo, after a packageFinder is invoked
1125         /* package */ Set<String> exportedPackages() {
1126             return exports.keySet();
1127         }
1128 
1129         /**
1130          * Provides a service with one or more implementations.
1131          *
1132          * @param  p
1133          *         The provides
1134          *
1135          * @return This builder
1136          *
1137          * @throws IllegalStateException
1138          *         If the providers for the service type have already been
1139          *         declared
1140          */
1141         public Builder provides(Provides p) {
1142             String st = p.service();
1143             if (provides.containsKey(st))
1144                 throw new IllegalStateException("Providers of service "
1145                                                 + st + " already declared");
1146             provides.put(st, p);
1147             return this;
1148         }
1149 
1150         /**
1151          * Provides service {@code st} with implementations {@code pcs}.
1152          *
1153          * @param  st
1154          *         The service type
1155          * @param  pcs
1156          *         The set of provider class names
1157          *
1158          * @return This builder
1159          *
1160          * @throws IllegalArgumentException
1161          *         If the service type or any of the provider class names is
1162          *         {@code null} or is not a legal Java identifier, or the set
1163          *         of provider class names is empty
1164          * @throws IllegalStateException
1165          *         If the providers for the service type have already been
1166          *         declared
1167          */
1168         public Builder provides(String st, Set<String> pcs) {
1169             if (provides.containsKey(st))
1170                 throw new IllegalStateException("Providers of service "
1171                                                 + st + " already declared");
1172             provides.put(st, new Provides(st, pcs)); // checks st and pcs
1173             return this;
1174         }
1175 
1176         /**
1177          * Provides service {@code st} with implementation {@code pc}.
1178          *
1179          * @param  st
1180          *         The service type
1181          * @param  pc
1182          *         The provider class name
1183          *
1184          * @return This builder
1185          *
1186          * @throws IllegalArgumentException
1187          *         If the service type or the provider class name is {@code
1188          *         null} or is not a legal Java identifier
1189          * @throws IllegalStateException
1190          *         If the providers for the service type have already been
1191          *         declared
1192          */
1193         public Builder provides(String st, String pc) {
1194             return provides(st, Collections.singleton(pc));
1195         }
1196 
1197         /**
1198          * Adds a set of (possible empty) concealed packages.
1199          *
1200          * @param  pns
1201          *         The set of package names of the concealed packages
1202          *
1203          * @return This builder
1204          *
1205          * @throws IllegalArgumentException
1206          *         If any of the package names is {@code null} or is not a
1207          *         legal Java identifier
1208          * @throws IllegalStateException
1209          *         If any of packages are already declared as a concealed or
1210          *         exported package
1211          */
1212         public Builder conceals(Set<String> pns) {
1213             pns.forEach(this::conceals);
1214             return this;
1215         }
1216 
1217         /**
1218          * Adds a concealed package.
1219          *
1220          * @param  pn
1221          *         The package name
1222          *
1223          * @return This builder
1224          *
1225          * @throws IllegalArgumentException
1226          *         If the package name is {@code null}, or is not a legal Java
1227          *         identifier
1228          * @throws IllegalStateException
1229          *         If the package is already declared as a concealed or exported
1230          *         package
1231          */
1232         public Builder conceals(String pn) {
1233             Checks.requirePackageName(pn);
1234             ensureNotExportedOrConcealed(pn);
1235             if (conceals.isEmpty())
1236                 conceals = new HashSet<>();
1237             conceals.add(pn);
1238             return this;
1239         }
1240 
1241         /**
1242          * Sets the module version.
1243          *
1244          * @param  v
1245          *         The version
1246          *
1247          * @return This builder
1248          *
1249          * @throws IllegalStateException
1250          *         If the module version is already set
1251          */
1252         public Builder version(Version v) {
1253             if (version != null)
1254                 throw new IllegalStateException("module version already set");
1255             version = requireNonNull(v);
1256             return this;
1257         }
1258 
1259         /**
1260          * Sets the module version.
1261          *
1262          * @param  v
1263          *         The version string to parse
1264          *
1265          * @return This builder
1266          *
1267          * @throws IllegalArgumentException
1268          *         If {@code v} is null or cannot be parsed as a version string
1269          * @throws IllegalStateException
1270          *         If the module version is already set
1271          *
1272          * @see Version#parse(String)
1273          */
1274         public Builder version(String v) {
1275             if (version != null)
1276                 throw new IllegalStateException(
1277                     "module version already set: " + version);
1278             version = Version.parse(v);
1279             return this;
1280         }
1281 
1282         /**
1283          * Sets the module main class.
1284          *
1285          * @param  mc
1286          *         The module main class
1287          *
1288          * @return This builder
1289          *
1290          * @throws IllegalArgumentException
1291          *         If {@code mainClass} is null or is not a legal Java identifier
1292          * @throws IllegalStateException
1293          *         If the module main class is already set
1294          */
1295         public Builder mainClass(String mc) {
1296             if (mainClass != null)
1297                 throw new IllegalStateException(
1298                     "main class already set: " + mainClass);
1299             mainClass = requireJavaIdentifier("main class name", mc);
1300             return this;
1301         }
1302 
1303         /**
1304          * Sets the operating system name.
1305          *
1306          * @param  name
1307          *         The operating system name
1308          *
1309          * @return This builder
1310          *
1311          * @throws IllegalArgumentException
1312          *         If {@code name} is null or the empty String
1313          * @throws IllegalStateException
1314          *         If the operating system name is already set
1315          */
1316         public Builder osName(String name) {
1317             if (osName != null)
1318                 throw new IllegalStateException(
1319                     "OS name already set: " + osName);
1320             if (name == null || name.isEmpty())
1321                 throw new IllegalArgumentException("OS name is null or empty");
1322             osName = name;
1323             return this;
1324         }
1325 
1326         /**
1327          * Sets the operating system architecture.
1328          *
1329          * @param  arch
1330          *         The operating system architecture
1331          *
1332          * @return This builder
1333          *
1334          * @throws IllegalArgumentException
1335          *         If {@code name} is null or the empty String
1336          * @throws IllegalStateException
1337          *         If the operating system architecture is already set
1338          */
1339         public Builder osArch(String arch) {
1340             if (osArch != null)
1341                 throw new IllegalStateException(
1342                     "OS arch already set: " + osArch);
1343             if (arch == null || arch.isEmpty())
1344                 throw new IllegalArgumentException("OS arch is null or empty");
1345             osArch = arch;
1346             return this;
1347         }
1348 
1349         /**
1350          * Sets the operating system version.
1351          *
1352          * @param  version
1353          *         The operating system version
1354          *
1355          * @return This builder
1356          *
1357          * @throws IllegalArgumentException
1358          *         If {@code name} is null or the empty String
1359          * @throws IllegalStateException
1360          *         If the operating system version is already set
1361          */
1362         public Builder osVersion(String version) {
1363             if (osVersion != null)
1364                 throw new IllegalStateException(
1365                     "OS version already set: " + osVersion);
1366             if (version == null || version.isEmpty())
1367                 throw new IllegalArgumentException("OS version is null or empty");
1368             osVersion = version;
1369             return this;
1370         }
1371 
1372         /* package */ Builder hashes(DependencyHashes hashes) {
1373             this.hashes = hashes;
1374             return this;
1375         }
1376 
1377 
1378         /* package */ Builder synthetic(boolean v) {
1379             this.synthetic = v;
1380             return this;
1381         }
1382 
1383         /**
1384          * Builds and returns a {@code ModuleDescriptor} from its components.
1385          *
1386          * @return The module descriptor
1387          */
1388         public ModuleDescriptor build() {
1389             assert name != null;
1390 
1391             return new ModuleDescriptor(name,
1392                                         automatic,
1393                                         synthetic,
1394                                         requires,
1395                                         uses,
1396                                         exports,
1397                                         provides,
1398                                         version,
1399                                         mainClass,
1400                                         osName,
1401                                         osArch,
1402                                         osVersion,
1403                                         conceals,
1404                                         hashes);
1405         }
1406 
1407     }
1408 
1409 
1410     /**
1411      * Compares this module descriptor to another.
1412      *
1413      * <p> Two {@code ModuleDescriptor} objects are compared by comparing their
1414      * module name lexicographically.  Where the module names are equal then
1415      * the versions, if present, are compared.
1416      *
1417      * @param  that
1418      *         The object to which this module descriptor is to be compared
1419      *
1420      * @return A negative integer, zero, or a positive integer if this module
1421      *         descriptor is less than, equal to, or greater than the given
1422      *         module descriptor
1423      */
1424     @Override
1425     public int compareTo(ModuleDescriptor that) {
1426         int c = this.name().compareTo(that.name());
1427         if (c != 0) return c;
1428         if (version == null) {
1429             if (that.version == null)
1430                 return 0;
1431             return -1;
1432         }
1433         if (that.version == null)
1434             return +1;
1435         return version.compareTo(that.version);
1436     }
1437 
1438     @Override
1439     public boolean equals(Object ob) {
1440         if (ob == this)
1441             return true;
1442         if (!(ob instanceof ModuleDescriptor))
1443             return false;
1444         ModuleDescriptor that = (ModuleDescriptor)ob;
1445         return (name.equals(that.name)
1446                 && automatic == that.automatic
1447                 && synthetic == that.synthetic
1448                 && requires.equals(that.requires)
1449                 && uses.equals(that.uses)
1450                 && exports.equals(that.exports)
1451                 && provides.equals(that.provides)
1452                 && Objects.equals(version, that.version)
1453                 && Objects.equals(mainClass, that.mainClass)
1454                 && Objects.equals(osName, that.osName)
1455                 && Objects.equals(osArch, that.osArch)
1456                 && Objects.equals(osVersion, that.osVersion)
1457                 && Objects.equals(conceals, that.conceals)
1458                 && Objects.equals(hashes, that.hashes));
1459     }
1460 
1461     private transient int hash;  // cached hash code
1462 
1463     @Override
1464     public int hashCode() {
1465         int hc = hash;
1466         if (hc == 0) {
1467             hc = name.hashCode();
1468             hc = hc * 43 + Boolean.hashCode(automatic);
1469             hc = hc * 43 + Boolean.hashCode(synthetic);
1470             hc = hc * 43 + requires.hashCode();
1471             hc = hc * 43 + uses.hashCode();
1472             hc = hc * 43 + exports.hashCode();
1473             hc = hc * 43 + provides.hashCode();
1474             hc = hc * 43 + Objects.hashCode(version);
1475             hc = hc * 43 + Objects.hashCode(mainClass);
1476             hc = hc * 43 + Objects.hashCode(osName);
1477             hc = hc * 43 + Objects.hashCode(osArch);
1478             hc = hc * 43 + Objects.hashCode(osVersion);
1479             hc = hc * 43 + Objects.hashCode(conceals);
1480             hc = hc * 43 + Objects.hashCode(hashes);
1481             if (hc != 0) hash = hc;
1482         }
1483         return hc;
1484     }
1485 
1486     @Override
1487     public String toString() {
1488         StringBuilder sb = new StringBuilder();
1489         sb.append("Module { name: ").append(toNameAndVersion());
1490         if (!requires.isEmpty())
1491             sb.append(", ").append(requires);
1492         if (!uses.isEmpty())
1493             sb.append(", ").append(uses);
1494         if (!exports.isEmpty())
1495             sb.append(", exports: ").append(exports);
1496         if (!provides.isEmpty()) {
1497             sb.append(", provides: [");
1498             for (Map.Entry<String, Provides> entry : provides.entrySet()) {
1499                 sb.append(entry.getKey())
1500                    .append(" with ")
1501                    .append(entry.getValue());
1502             }
1503             sb.append("]");
1504         }
1505         sb.append(" }");
1506         return sb.toString();
1507     }
1508 
1509     /**
1510      * Reads the binary form of a module declaration from an input stream
1511      * as a module descriptor.
1512      *
1513      * <p> If the descriptor encoded in the input stream does not indicate a
1514      * set of concealed packages then the {@code packageFinder} will be
1515      * invoked.  The packages it returns, except for those indicated as
1516      * exported in the encoded descriptor, will be considered to be concealed.
1517      * If the {@code packageFinder} throws an {@link UncheckedIOException} then
1518      * {@link IOException} cause will be re-thrown. </p>
1519      *
1520      * <p> If there are bytes following the module descriptor then it is
1521      * implementation specific as to whether those bytes are read, ignored,
1522      * or reported as an {@code InvalidModuleDescriptorException}. If this
1523      * method fails with an {@code InvalidModuleDescriptorException} or {@code
1524      * IOException} then it may do so after some, but not all, bytes have
1525      * been read from the input stream. It is strongly recommended that the
1526      * stream be promptly closed and discarded if an exception occurs. </p>
1527      *
1528      * @apiNote The {@code packageFinder} parameter is for use when reading
1529      * module descriptors from legacy module-artifact formats that do not
1530      * record the set of concealed packages in the descriptor itself.
1531      *
1532      * @param  in
1533      *         The input stream
1534      * @param  packageFinder
1535      *         A supplier that can produce a set of package names
1536      *
1537      * @return The module descriptor
1538      *
1539      * @throws InvalidModuleDescriptorException
1540      *         If an invalid module descriptor is detected
1541      * @throws IOException
1542      *         If an I/O error occurs reading from the input stream or {@code
1543      *         UncheckedIOException} is thrown by the package finder
1544      */
1545     public static ModuleDescriptor read(InputStream in,
1546                                         Supplier<Set<String>> packageFinder)
1547         throws IOException
1548     {
1549         return ModuleInfo.read(in, requireNonNull(packageFinder));
1550     }
1551 
1552     /**
1553      * Reads the binary form of a module declaration from an input stream
1554      * as a module descriptor.
1555      *
1556      * @param  in
1557      *         The input stream
1558      *
1559      * @return The module descriptor
1560      *
1561      * @throws InvalidModuleDescriptorException
1562      *         If an invalid module descriptor is detected
1563      * @throws IOException
1564      *         If an I/O error occurs reading from the input stream
1565      */
1566     public static ModuleDescriptor read(InputStream in) throws IOException {
1567         return ModuleInfo.read(in, null);
1568     }
1569 
1570     /**
1571      * Reads the binary form of a module declaration from a byte buffer
1572      * as a module descriptor.
1573      *
1574      * <p> If the descriptor encoded in the byte buffer does not indicate a
1575      * set of concealed packages then the {@code packageFinder} will be
1576      * invoked.  The packages it returns, except for those indicated as
1577      * exported in the encoded descriptor, will be considered to be
1578      * concealed. </p>
1579      *
1580      * <p> The module descriptor is read from the buffer stating at index
1581      * {@code p}, where {@code p} is the buffer's {@link ByteBuffer#position()
1582      * position} when this method is invoked. Upon return the buffer's position
1583      * will be equal to {@code p + n} where {@code n} is the number of bytes
1584      * read from the buffer. </p>
1585      *
1586      * <p> If there are bytes following the module descriptor then it is
1587      * implementation specific as to whether those bytes are read, ignored,
1588      * or reported as an {@code InvalidModuleDescriptorException}. If this
1589      * method fails with an {@code InvalidModuleDescriptorException} then it
1590      * may do so after some, but not all, bytes have been read. </p>
1591      *
1592      * @apiNote The {@code packageFinder} parameter is for use when reading
1593      * module descriptors from legacy module-artifact formats that do not
1594      * record the set of concealed packages in the descriptor itself.
1595      *
1596      * @param  bb
1597      *         The byte buffer
1598      * @param  packageFinder
1599      *         A supplier that can produce a set of package names
1600      *
1601      * @return The module descriptor
1602      *
1603      * @throws InvalidModuleDescriptorException
1604      *         If an invalid module descriptor is detected
1605      */
1606     public static ModuleDescriptor read(ByteBuffer bb,
1607                                         Supplier<Set<String>> packageFinder)
1608     {
1609         return ModuleInfo.read(bb, requireNonNull(packageFinder));
1610     }
1611 
1612     /**
1613      * Reads the binary form of a module declaration from a byte buffer
1614      * as a module descriptor.
1615      *
1616      * @param  bb
1617      *         The byte buffer
1618      *
1619      * @return The module descriptor
1620      *
1621      * @throws InvalidModuleDescriptorException
1622      *         If an invalid module descriptor is detected
1623      */
1624     public static ModuleDescriptor read(ByteBuffer bb) {
1625         return ModuleInfo.read(bb, null);
1626     }
1627 
1628 
1629     /**
1630      * Computes the set of packages from exports and concealed packages.
1631      * It returns the concealed packages set if there is no exported package.
1632      */
1633     private static Set<String> computePackages(Set<Exports> exports,
1634                                                Set<String> conceals)
1635     {
1636         if (exports.isEmpty())
1637             return conceals;
1638 
1639         Set<String> pkgs = new HashSet<>(conceals);
1640         exports.stream().map(Exports::source).forEach(pkgs::add);
1641         return emptyOrUnmodifiableSet(pkgs);
1642     }
1643 
1644     /**
1645      * Computes the set of concealed packages from exports and all packages.
1646      * It returns the packages set if there are no exported packages.
1647      */
1648     private static Set<String> computeConcealedPackages(Set<Exports> exports,
1649                                                         Set<String> pkgs)
1650     {
1651         if (exports.isEmpty())
1652             return pkgs;
1653 
1654         Set<String> conceals = new HashSet<>(pkgs);
1655         exports.stream().map(Exports::source).forEach(conceals::remove);
1656         return emptyOrUnmodifiableSet(conceals);
1657     }
1658 
1659     private static <K,V> Map<K,V> emptyOrUnmodifiableMap(Map<K,V> map) {
1660         if (map.isEmpty()) {
1661             return Collections.emptyMap();
1662         } else if (map.size() == 1) {
1663             Map.Entry<K, V> entry = map.entrySet().iterator().next();
1664             return Collections.singletonMap(entry.getKey(), entry.getValue());
1665         } else {
1666             return Collections.unmodifiableMap(map);
1667         }
1668     }
1669 
1670     private static <T> Set<T> emptyOrUnmodifiableSet(Set<T> set) {
1671         if (set.isEmpty()) {
1672             return Collections.emptySet();
1673         } else if (set.size() == 1) {
1674             return Collections.singleton(set.iterator().next());
1675         } else {
1676             return Collections.unmodifiableSet(set);
1677         }
1678     }
1679 
1680     static {
1681         /**
1682          * Setup the shared secret to allow code in other packages create
1683          * ModuleDescriptor and associated objects directly.
1684          */
1685         jdk.internal.misc.SharedSecrets
1686             .setJavaLangModuleAccess(new jdk.internal.misc.JavaLangModuleAccess() {
1687                 @Override
1688                 public Requires newRequires(Set<Requires.Modifier> ms, String mn) {
1689                     return new Requires(ms, mn, false);
1690                 }
1691 
1692                 @Override
1693                 public Exports newExports(String source, Set<String> targets) {
1694                     return new Exports(source, targets, false);
1695                 }
1696 
1697                 @Override
1698                 public Exports newExports(String source) {
1699                     return new Exports(source, false);
1700                 }
1701 
1702                 @Override
1703                 public Provides newProvides(String service, Set<String> providers) {
1704                     return new Provides(service, providers, false);
1705                 }
1706 
1707                 @Override
1708                 public Version newVersion(String v) {
1709                     return new Version(v);
1710                 }
1711 
1712                 @Override
1713                 public ModuleDescriptor newModuleDescriptor(ModuleDescriptor md,
1714                                                             Set<String> pkgs) {
1715                     return new ModuleDescriptor(md, pkgs);
1716                 }
1717 
1718                 @Override
1719                 public ModuleDescriptor newModuleDescriptor(String name,
1720                                                             boolean automatic,
1721                                                             boolean synthetic,
1722                                                             Set<Requires> requires,
1723                                                             Set<String> uses, Set<Exports> exports,
1724                                                             Map<String, Provides> provides,
1725                                                             Version version,
1726                                                             String mainClass,
1727                                                             String osName,
1728                                                             String osArch,
1729                                                             String osVersion,
1730                                                             Set<String> conceals,
1731                                                             Set<String> packages) {
1732                     return new ModuleDescriptor(name,
1733                                                 automatic,
1734                                                 synthetic,
1735                                                 requires,
1736                                                 uses,
1737                                                 exports,
1738                                                 provides,
1739                                                 version,
1740                                                 mainClass,
1741                                                 osName,
1742                                                 osArch,
1743                                                 osVersion,
1744                                                 conceals,
1745                                                 packages);
1746                 }
1747             });
1748     }
1749 
1750 }