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.PrintStream;
  31 import java.io.UncheckedIOException;
  32 import java.nio.ByteBuffer;
  33 import java.nio.file.Path;
  34 import java.util.ArrayList;
  35 import java.util.Collection;
  36 import java.util.Collections;
  37 import java.util.EnumSet;
  38 import java.util.HashMap;
  39 import java.util.HashSet;
  40 import java.util.List;
  41 import java.util.Map;
  42 import java.util.Objects;
  43 import java.util.Optional;
  44 import java.util.Set;
  45 import java.util.function.Supplier;
  46 import java.util.stream.Collectors;
  47 import java.util.stream.Stream;
  48 
  49 import static jdk.internal.module.Checks.*;
  50 import static java.util.Objects.*;
  51 
  52 import jdk.internal.module.Checks;
  53 import jdk.internal.module.ModuleInfo;
  54 
  55 
  56 /**
  57  * A module descriptor.
  58  *
  59  * <p> A {@code ModuleDescriptor} is typically created from the binary form
  60  * of a module declaration. Alternatively, the {@link ModuleDescriptor.Builder}
  61  * class can be used to create a {@code ModuleDescriptor} from its components.
  62  * The {@link #module module}, {@link #openModule openModule}, and {@link
  63  * #automaticModule automaticModule} methods create builders for building
  64  * different kinds of modules. </p>
  65  *
  66  * <p> {@code ModuleDescriptor} objects are immutable and safe for use by
  67  * multiple concurrent threads.</p>
  68  *
  69  * @since 9
  70  * @see java.lang.reflect.Module
  71  */
  72 
  73 public class ModuleDescriptor
  74     implements Comparable<ModuleDescriptor>
  75 {
  76 
  77     /**
  78      * <p> A dependence upon a module </p>
  79      *
  80      * @see ModuleDescriptor#requires()
  81      * @since 9
  82      */
  83 
  84     public final static class Requires
  85         implements Comparable<Requires>
  86     {
  87 
  88         /**
  89          * A modifier on a module dependence.
  90          *
  91          * @since 9
  92          */
  93         public static enum Modifier {
  94 
  95             /**
  96              * The dependence causes any module which depends on the <i>current
  97              * module</i> to have an implicitly declared dependence on the module
  98              * named by the {@code Requires}.
  99              */
 100             TRANSITIVE,
 101 
 102             /**
 103              * The dependence is mandatory in the static phase, during compilation,
 104              * but is optional in the dynamic phase, during execution.
 105              */
 106             STATIC,
 107 
 108             /**
 109              * The dependence was not explicitly or implicitly declared in the
 110              * source of the module declaration.
 111              */
 112             SYNTHETIC,
 113 
 114             /**
 115              * The dependence was implicitly declared in the source of the module
 116              * declaration.
 117              */
 118             MANDATED;
 119 
 120         }
 121 
 122         private final Set<Modifier> mods;
 123         private final String name;
 124         private final Version compiledVersion;
 125 
 126         private Requires(Set<Modifier> ms, String mn, Version v) {
 127             if (ms.isEmpty()) {
 128                 ms = Collections.emptySet();
 129             } else {
 130                 ms = Collections.unmodifiableSet(EnumSet.copyOf(ms));
 131             }
 132             this.mods = ms;
 133             this.name = mn;
 134             this.compiledVersion = v;
 135         }
 136 
 137         private Requires(Set<Modifier> ms, String mn, Version v, boolean unused) {
 138             this.mods = ms;
 139             this.name = mn;
 140             this.compiledVersion = v;
 141         }
 142 
 143         /**
 144          * Returns the set of modifiers.
 145          *
 146          * @return A possibly-empty unmodifiable set of modifiers
 147          */
 148         public Set<Modifier> modifiers() {
 149             return mods;
 150         }
 151 
 152         /**
 153          * Return the module name.
 154          *
 155          * @return The module name
 156          */
 157         public String name() {
 158             return name;
 159         }
 160 
 161         /**
 162          * Returns the version of the module if recorded at compile-time.
 163          *
 164          * @return The version of the module if recorded at compile-time
 165          */
 166         public Optional<Version> compiledVersion() {
 167             return Optional.ofNullable(compiledVersion);
 168         }
 169 
 170         /**
 171          * Compares this module dependence to another.
 172          *
 173          * <p> Two {@code Requires} objects are compared by comparing their
 174          * module name lexicographically.  Where the module names are equal then
 175          * the sets of modifiers are compared based on a value computed from the
 176          * ordinal of each modifier. Where the module names are equal and the
 177          * set of modifiers are equal then the version of the modules recorded
 178          * at compile-time are compared. When comparing the versions recorded
 179          * at compile-time then a dependence that has a recorded version is
 180          * considered to succeed a dependence that does not have a recorded
 181          * version. </p>
 182          *
 183          * @return A negative integer, zero, or a positive integer if this module
 184          *         dependence is less than, equal to, or greater than the given
 185          *         module dependence
 186          */
 187         @Override
 188         public int compareTo(Requires that) {
 189             int c = this.name().compareTo(that.name());
 190             if (c != 0)
 191                 return c;
 192 
 193             // modifiers
 194             c = Long.compare(this.modsValue(), that.modsValue());
 195             if (c != 0)
 196                 return c;
 197 
 198             // compiledVersion
 199             if (this.compiledVersion != null) {
 200                 if (that.compiledVersion != null)
 201                     c = this.compiledVersion.compareTo(that.compiledVersion);
 202                 else
 203                     c = 1;
 204             } else {
 205                 if (that.compiledVersion != null)
 206                     c = -1;
 207             }
 208 
 209             return c;
 210         }
 211 
 212         /**
 213          * Return a value for the modifiers to allow sets of modifiers to be
 214          * compared.
 215          */
 216         private long modsValue() {
 217             long value = 0;
 218             for (Modifier m : mods) {
 219                 value += 1 << m.ordinal();
 220             }
 221             return value;
 222         }
 223 
 224         /**
 225          * Tests this module dependence for equality with the given object.
 226          *
 227          * <p> If the given object is not a {@code Requires} then this method
 228          * returns {@code false}. Two module dependence objects are equal if
 229          * the module names are equal, set of modifiers are equal, and the
 230          * compiled version of both modules is equal or not recorded for
 231          * both modules. </p>
 232          *
 233          * <p> This method satisfies the general contract of the {@link
 234          * java.lang.Object#equals(Object) Object.equals} method. </p>
 235          *
 236          * @param   ob
 237          *          the object to which this object is to be compared
 238          *
 239          * @return  {@code true} if, and only if, the given object is a module
 240          *          dependence that is equal to this module dependence
 241          */
 242         @Override
 243         public boolean equals(Object ob) {
 244             if (!(ob instanceof Requires))
 245                 return false;
 246             Requires that = (Requires)ob;
 247             return name.equals(that.name) && mods.equals(that.mods)
 248                     && Objects.equals(compiledVersion, that.compiledVersion);
 249         }
 250 
 251         /**
 252          * Computes a hash code for this module dependence.
 253          *
 254          * <p> The hash code is based upon the module name, modifiers, and the
 255          * module version if recorded at compile time. It satisfies the general
 256          * contract of the {@link Object#hashCode Object.hashCode} method. </p>
 257          *
 258          * @return The hash-code value for this module dependence
 259          */
 260         @Override
 261         public int hashCode() {
 262             int hash = name.hashCode() * 43 + mods.hashCode();
 263             if (compiledVersion != null)
 264                 hash = hash * 43 + compiledVersion.hashCode();
 265             return hash;
 266         }
 267 
 268         /**
 269          * Returns a string describing module dependence.
 270          *
 271          * @return A string describing module dependence
 272          */
 273         @Override
 274         public String toString() {
 275             String what;
 276             if (compiledVersion != null) {
 277                 what = name() + " (@" + compiledVersion + ")";
 278             } else {
 279                 what = name();
 280             }
 281             return ModuleDescriptor.toString(mods, what);
 282         }
 283     }
 284 
 285 
 286 
 287     /**
 288      * <p> A module export, may be qualified or unqualified. </p>
 289      *
 290      * @see ModuleDescriptor#exports()
 291      * @since 9
 292      */
 293 
 294     public final static class Exports {
 295 
 296         /**
 297          * A modifier on a module export.
 298          *
 299          * @since 9
 300          */
 301         public static enum Modifier {
 302 
 303             /**
 304              * The export was not explicitly or implicitly declared in the
 305              * source of the module declaration.
 306              */
 307             SYNTHETIC,
 308 
 309             /**
 310              * The export was implicitly declared in the source of the module
 311              * declaration.
 312              */
 313             MANDATED;
 314 
 315         }
 316 
 317         private final Set<Modifier> mods;
 318         private final String source;
 319         private final Set<String> targets;  // empty if unqualified export
 320 
 321         /**
 322          * Constructs an export
 323          */
 324         private Exports(Set<Modifier> ms, String source, Set<String> targets) {
 325             if (ms.isEmpty()) {
 326                 ms = Collections.emptySet();
 327             } else {
 328                 ms = Collections.unmodifiableSet(EnumSet.copyOf(ms));
 329             }
 330             this.mods = ms;
 331             this.source = source;
 332             this.targets = emptyOrUnmodifiableSet(targets);
 333         }
 334 
 335         private Exports(Set<Modifier> ms,
 336                         String source,
 337                         Set<String> targets,
 338                         boolean unused) {
 339             this.mods = ms;
 340             this.source = source;
 341             this.targets = targets;
 342         }
 343 
 344         /**
 345          * Returns the set of modifiers.
 346          *
 347          * @return A possibly-empty unmodifiable set of modifiers
 348          */
 349         public Set<Modifier> modifiers() {
 350             return mods;
 351         }
 352 
 353         /**
 354          * Returns {@code true} if this is a qualified export.
 355          *
 356          * @return {@code true} if this is a qualified export
 357          */
 358         public boolean isQualified() {
 359             return !targets.isEmpty();
 360         }
 361 
 362         /**
 363          * Returns the package name.
 364          *
 365          * @return The package name
 366          */
 367         public String source() {
 368             return source;
 369         }
 370 
 371         /**
 372          * For a qualified export, returns the non-empty and immutable set
 373          * of the module names to which the package is exported. For an
 374          * unqualified export, returns an empty set.
 375          *
 376          * @return The set of target module names or for an unqualified
 377          *         export, an empty set
 378          */
 379         public Set<String> targets() {
 380             return targets;
 381         }
 382 
 383         /**
 384          * Computes a hash code for this module export.
 385          *
 386          * <p> The hash code is based upon the modifiers, the package name,
 387          * and for a qualified export, the set of modules names to which the
 388          * package is exported. It satisfies the general contract of the
 389          * {@link Object#hashCode Object.hashCode} method.
 390          *
 391          * @return The hash-code value for this module export
 392          */
 393         @Override
 394         public int hashCode() {
 395             int hash = mods.hashCode();
 396             hash = hash * 43 + source.hashCode();
 397             return hash * 43 + targets.hashCode();
 398         }
 399 
 400         /**
 401          * Tests this module export for equality with the given object.
 402          *
 403          * <p> If the given object is not an {@code Exports} then this method
 404          * returns {@code false}. Two module exports objects are equal if their
 405          * set of modifiers is equal, the package names are equal and the set
 406          * of target module names is equal. </p>
 407          *
 408          * <p> This method satisfies the general contract of the {@link
 409          * java.lang.Object#equals(Object) Object.equals} method. </p>
 410          *
 411          * @param   ob
 412          *          the object to which this object is to be compared
 413          *
 414          * @return  {@code true} if, and only if, the given object is a module
 415          *          dependence that is equal to this module dependence
 416          */
 417         @Override
 418         public boolean equals(Object ob) {
 419             if (!(ob instanceof Exports))
 420                 return false;
 421             Exports other = (Exports)ob;
 422             return Objects.equals(this.mods, other.mods)
 423                     && Objects.equals(this.source, other.source)
 424                     && Objects.equals(this.targets, other.targets);
 425         }
 426 
 427         /**
 428          * Returns a string describing module export.
 429          *
 430          * @return A string describing module export
 431          */
 432         @Override
 433         public String toString() {
 434             String s = ModuleDescriptor.toString(mods, source);
 435             if (targets.isEmpty())
 436                 return s;
 437             else
 438                 return s + " to " + targets;
 439         }
 440     }
 441 
 442 
 443     /**
 444      * <p> Represents a module <em>opens</em> directive, may be qualified or
 445      * unqualified. </p>
 446      *
 447      * <p> The <em>opens</em> directive in a module declaration declares a
 448      * package to be open to allow all types in the package, and all their
 449      * members, not just public types and their public members to be reflected
 450      * on by APIs that support private access or a way to bypass or suppress
 451      * default Java language access control checks. </p>
 452      *
 453      * @see ModuleDescriptor#opens()
 454      * @since 9
 455      */
 456 
 457     public final static class Opens {
 458 
 459         /**
 460          * A modifier on a module <em>opens</em> directive.
 461          *
 462          * @since 9
 463          */
 464         public static enum Modifier {
 465 
 466             /**
 467              * The opens was not explicitly or implicitly declared in the
 468              * source of the module declaration.
 469              */
 470             SYNTHETIC,
 471 
 472             /**
 473              * The opens was implicitly declared in the source of the module
 474              * declaration.
 475              */
 476             MANDATED;
 477 
 478         }
 479 
 480         private final Set<Modifier> mods;
 481         private final String source;
 482         private final Set<String> targets;  // empty if unqualified export
 483 
 484         /**
 485          * Constructs an Opens
 486          */
 487         private Opens(Set<Modifier> ms, String source, Set<String> targets) {
 488             if (ms.isEmpty()) {
 489                 ms = Collections.emptySet();
 490             } else {
 491                 ms = Collections.unmodifiableSet(EnumSet.copyOf(ms));
 492             }
 493             this.mods = ms;
 494             this.source = source;
 495             this.targets = emptyOrUnmodifiableSet(targets);
 496         }
 497 
 498         private Opens(Set<Modifier> ms,
 499                       String source,
 500                       Set<String> targets,
 501                       boolean unused) {
 502             this.mods = ms;
 503             this.source = source;
 504             this.targets = targets;
 505         }
 506 
 507         /**
 508          * Returns the set of modifiers.
 509          *
 510          * @return A possibly-empty unmodifiable set of modifiers
 511          */
 512         public Set<Modifier> modifiers() {
 513             return mods;
 514         }
 515 
 516         /**
 517          * Returns {@code true} if this is a qualified opens.
 518          *
 519          * @return {@code true} if this is a qualified opens
 520          */
 521         public boolean isQualified() {
 522             return !targets.isEmpty();
 523         }
 524 
 525         /**
 526          * Returns the package name.
 527          *
 528          * @return The package name
 529          */
 530         public String source() {
 531             return source;
 532         }
 533 
 534         /**
 535          * For a qualified opens, returns the non-empty and immutable set
 536          * of the module names to which the package is open. For an
 537          * unqualified opens, returns an empty set.
 538          *
 539          * @return The set of target module names or for an unqualified
 540          *         opens, an empty set
 541          */
 542         public Set<String> targets() {
 543             return targets;
 544         }
 545 
 546         /**
 547          * Computes a hash code for this module opens.
 548          *
 549          * <p> The hash code is based upon the modifiers, the package name,
 550          * and for a qualified opens, the set of modules names to which the
 551          * package is opened. It satisfies the general contract of the
 552          * {@link Object#hashCode Object.hashCode} method.
 553          *
 554          * @return The hash-code value for this module opens
 555          */
 556         @Override
 557         public int hashCode() {
 558             int hash = mods.hashCode();
 559             hash = hash * 43 + source.hashCode();
 560             return hash * 43 + targets.hashCode();
 561         }
 562 
 563         /**
 564          * Tests this module opens for equality with the given object.
 565          *
 566          * <p> If the given object is not an {@code Opens} then this method
 567          * returns {@code false}. Two {@code Opens} objects are equal if their
 568          * set of modifiers is equal, the package names are equal and the set
 569          * of target module names is equal. </p>
 570          *
 571          * <p> This method satisfies the general contract of the {@link
 572          * java.lang.Object#equals(Object) Object.equals} method. </p>
 573          *
 574          * @param   ob
 575          *          the object to which this object is to be compared
 576          *
 577          * @return  {@code true} if, and only if, the given object is a module
 578          *          dependence that is equal to this module dependence
 579          */
 580         @Override
 581         public boolean equals(Object ob) {
 582             if (!(ob instanceof Opens))
 583                 return false;
 584             Opens other = (Opens)ob;
 585             return Objects.equals(this.mods, other.mods)
 586                     && Objects.equals(this.source, other.source)
 587                     && Objects.equals(this.targets, other.targets);
 588         }
 589 
 590         /**
 591          * Returns a string describing module opens.
 592          *
 593          * @return A string describing module opens
 594          */
 595         @Override
 596         public String toString() {
 597             String s = ModuleDescriptor.toString(mods, source);
 598             if (targets.isEmpty())
 599                 return s;
 600             else
 601                 return s + " to " + targets;
 602         }
 603     }
 604 
 605 
 606     /**
 607      * <p> A service that a module provides one or more implementations of. </p>
 608      *
 609      * @see ModuleDescriptor#provides()
 610      * @since 9
 611      */
 612 
 613     public final static class Provides {
 614 
 615         private final String service;
 616         private final List<String> providers;
 617 
 618         private Provides(String service, List<String> providers) {
 619             this.service = service;
 620             this.providers = Collections.unmodifiableList(providers);
 621         }
 622 
 623         private Provides(String service, List<String> providers, boolean unused) {
 624             this.service = service;
 625             this.providers = providers;
 626         }
 627 
 628         /**
 629          * Returns the fully qualified class name of the service type.
 630          *
 631          * @return The fully qualified class name of the service type.
 632          */
 633         public String service() { return service; }
 634 
 635         /**
 636          * Returns the list of the fully qualified class names of the providers
 637          * or provider factories.
 638          *
 639          * @return A non-empty and unmodifiable list of the fully qualified class
 640          *         names of the providers or provider factories
 641          */
 642         public List<String> providers() { return providers; }
 643 
 644         /**
 645          * Computes a hash code for this provides.
 646          *
 647          * <p> The hash code is based upon the service type and the set of
 648          * providers. It satisfies the general contract of the {@link
 649          * Object#hashCode Object.hashCode} method. </p>
 650          *
 651          * @return The hash-code value for this module provides
 652          */
 653         @Override
 654         public int hashCode() {
 655             return service.hashCode() * 43 + providers.hashCode();
 656         }
 657 
 658         /**
 659          * Tests this provides for equality with the given object.
 660          *
 661          * <p> If the given object is not a {@code Provides} then this method
 662          * returns {@code false}. Two {@code Provides} objects are equal if the
 663          * service type is equal and the list of providers is equal. </p>
 664          *
 665          * <p> This method satisfies the general contract of the {@link
 666          * java.lang.Object#equals(Object) Object.equals} method. </p>
 667          *
 668          * @param   ob
 669          *          the object to which this object is to be compared
 670          *
 671          * @return  {@code true} if, and only if, the given object is a
 672          *          {@code Provides} that is equal to this {@code Provides}
 673          */
 674         @Override
 675         public boolean equals(Object ob) {
 676             if (!(ob instanceof Provides))
 677                 return false;
 678             Provides other = (Provides)ob;
 679             return Objects.equals(this.service, other.service) &&
 680                     Objects.equals(this.providers, other.providers);
 681         }
 682 
 683         /**
 684          * Returns a string describing this provides.
 685          *
 686          * @return A string describing this provides
 687          */
 688         @Override
 689         public String toString() {
 690             return service + " with " + providers;
 691         }
 692 
 693     }
 694 
 695 
 696 
 697     /**
 698      * A module's version string.
 699      *
 700      * <p> A version string has three components: The version number itself, an
 701      * optional pre-release version, and an optional build version.  Each
 702      * component is sequence of tokens; each token is either a non-negative
 703      * integer or a string.  Tokens are separated by the punctuation characters
 704      * {@code '.'}, {@code '-'}, or {@code '+'}, or by transitions from a
 705      * sequence of digits to a sequence of characters that are neither digits
 706      * nor punctuation characters, or vice versa.
 707      *
 708      * <ul>
 709      *
 710      *   <li> The <i>version number</i> is a sequence of tokens separated by
 711      *   {@code '.'} characters, terminated by the first {@code '-'} or {@code
 712      *   '+'} character. </li>
 713      *
 714      *   <li> The <i>pre-release version</i> is a sequence of tokens separated
 715      *   by {@code '.'} or {@code '-'} characters, terminated by the first
 716      *   {@code '+'} character. </li>
 717      *
 718      *   <li> The <i>build version</i> is a sequence of tokens separated by
 719      *   {@code '.'}, {@code '-'}, or {@code '+'} characters.
 720      *
 721      * </ul>
 722      *
 723      * <p> When comparing two version strings, the elements of their
 724      * corresponding components are compared in pointwise fashion.  If one
 725      * component is longer than the other, but otherwise equal to it, then the
 726      * first component is considered the greater of the two; otherwise, if two
 727      * corresponding elements are integers then they are compared as such;
 728      * otherwise, at least one of the elements is a string, so the other is
 729      * converted into a string if it is an integer and the two are compared
 730      * lexicographically.  Trailing integer elements with the value zero are
 731      * ignored.
 732      *
 733      * <p> Given two version strings, if their version numbers differ then the
 734      * result of comparing them is the result of comparing their version
 735      * numbers; otherwise, if one of them has a pre-release version but the
 736      * other does not then the first is considered to precede the second,
 737      * otherwise the result of comparing them is the result of comparing their
 738      * pre-release versions; otherwise, the result of comparing them is the
 739      * result of comparing their build versions.
 740      *
 741      * @see ModuleDescriptor#version()
 742      * @since 9
 743      */
 744 
 745     public final static class Version
 746         implements Comparable<Version>
 747     {
 748 
 749         private final String version;
 750 
 751         // If Java had disjunctive types then we'd write List<Integer|String> here
 752         //
 753         private final List<Object> sequence;
 754         private final List<Object> pre;
 755         private final List<Object> build;
 756 
 757         // Take a numeric token starting at position i
 758         // Append it to the given list
 759         // Return the index of the first character not taken
 760         // Requires: s.charAt(i) is (decimal) numeric
 761         //
 762         private static int takeNumber(String s, int i, List<Object> acc) {
 763             char c = s.charAt(i);
 764             int d = (c - '0');
 765             int n = s.length();
 766             while (++i < n) {
 767                 c = s.charAt(i);
 768                 if (c >= '0' && c <= '9') {
 769                     d = d * 10 + (c - '0');
 770                     continue;
 771                 }
 772                 break;
 773             }
 774             acc.add(d);
 775             return i;
 776         }
 777 
 778         // Take a string token starting at position i
 779         // Append it to the given list
 780         // Return the index of the first character not taken
 781         // Requires: s.charAt(i) is not '.'
 782         //
 783         private static int takeString(String s, int i, List<Object> acc) {
 784             int b = i;
 785             int n = s.length();
 786             while (++i < n) {
 787                 char c = s.charAt(i);
 788                 if (c != '.' && c != '-' && c != '+' && !(c >= '0' && c <= '9'))
 789                     continue;
 790                 break;
 791             }
 792             acc.add(s.substring(b, i));
 793             return i;
 794         }
 795 
 796         // Syntax: tok+ ( '-' tok+)? ( '+' tok+)?
 797         // First token string is sequence, second is pre, third is build
 798         // Tokens are separated by '.' or '-', or by changes between alpha & numeric
 799         // Numeric tokens are compared as decimal integers
 800         // Non-numeric tokens are compared lexicographically
 801         // A version with a non-empty pre is less than a version with same seq but no pre
 802         // Tokens in build may contain '-' and '+'
 803         //
 804         private Version(String v) {
 805 
 806             if (v == null)
 807                 throw new IllegalArgumentException("Null version string");
 808             int n = v.length();
 809             if (n == 0)
 810                 throw new IllegalArgumentException("Empty version string");
 811 
 812             int i = 0;
 813             char c = v.charAt(i);
 814             if (!(c >= '0' && c <= '9'))
 815                 throw new IllegalArgumentException(v
 816                                                    + ": Version string does not start"
 817                                                    + " with a number");
 818 
 819             List<Object> sequence = new ArrayList<>(4);
 820             List<Object> pre = new ArrayList<>(2);
 821             List<Object> build = new ArrayList<>(2);
 822 
 823             i = takeNumber(v, i, sequence);
 824 
 825             while (i < n) {
 826                 c = v.charAt(i);
 827                 if (c == '.') {
 828                     i++;
 829                     continue;
 830                 }
 831                 if (c == '-' || c == '+') {
 832                     i++;
 833                     break;
 834                 }
 835                 if (c >= '0' && c <= '9')
 836                     i = takeNumber(v, i, sequence);
 837                 else
 838                     i = takeString(v, i, sequence);
 839             }
 840 
 841             if (c == '-' && i >= n)
 842                 throw new IllegalArgumentException(v + ": Empty pre-release");
 843 
 844             while (i < n) {
 845                 c = v.charAt(i);
 846                 if (c >= '0' && c <= '9')
 847                     i = takeNumber(v, i, pre);
 848                 else
 849                     i = takeString(v, i, pre);
 850                 if (i >= n)
 851                     break;
 852                 c = v.charAt(i);
 853                 if (c == '.' || c == '-') {
 854                     i++;
 855                     continue;
 856                 }
 857                 if (c == '+') {
 858                     i++;
 859                     break;
 860                 }
 861             }
 862 
 863             if (c == '+' && i >= n)
 864                 throw new IllegalArgumentException(v + ": Empty pre-release");
 865 
 866             while (i < n) {
 867                 c = v.charAt(i);
 868                 if (c >= '0' && c <= '9')
 869                     i = takeNumber(v, i, build);
 870                 else
 871                     i = takeString(v, i, build);
 872                 if (i >= n)
 873                     break;
 874                 c = v.charAt(i);
 875                 if (c == '.' || c == '-' || c == '+') {
 876                     i++;
 877                     continue;
 878                 }
 879             }
 880 
 881             this.version = v;
 882             this.sequence = sequence;
 883             this.pre = pre;
 884             this.build = build;
 885         }
 886 
 887         /**
 888          * Parses the given string as a version string.
 889          *
 890          * @param  v
 891          *         The string to parse
 892          *
 893          * @return The resulting {@code Version}
 894          *
 895          * @throws IllegalArgumentException
 896          *         If {@code v} is {@code null}, an empty string, or cannot be
 897          *         parsed as a version string
 898          */
 899         public static Version parse(String v) {
 900             return new Version(v);
 901         }
 902 
 903         @SuppressWarnings("unchecked")
 904         private int cmp(Object o1, Object o2) {
 905             return ((Comparable)o1).compareTo(o2);
 906         }
 907 
 908         private int compareTokens(List<Object> ts1, List<Object> ts2) {
 909             int n = Math.min(ts1.size(), ts2.size());
 910             for (int i = 0; i < n; i++) {
 911                 Object o1 = ts1.get(i);
 912                 Object o2 = ts2.get(i);
 913                 if ((o1 instanceof Integer && o2 instanceof Integer)
 914                     || (o1 instanceof String && o2 instanceof String))
 915                 {
 916                     int c = cmp(o1, o2);
 917                     if (c == 0)
 918                         continue;
 919                     return c;
 920                 }
 921                 // Types differ, so convert number to string form
 922                 int c = o1.toString().compareTo(o2.toString());
 923                 if (c == 0)
 924                     continue;
 925                 return c;
 926             }
 927             List<Object> rest = ts1.size() > ts2.size() ? ts1 : ts2;
 928             int e = rest.size();
 929             for (int i = n; i < e; i++) {
 930                 Object o = rest.get(i);
 931                 if (o instanceof Integer && ((Integer)o) == 0)
 932                     continue;
 933                 return ts1.size() - ts2.size();
 934             }
 935             return 0;
 936         }
 937 
 938         /**
 939          * Compares this module version to another module version. Module
 940          * versions are compared as described in the class description.
 941          *
 942          * @param that
 943          *        The module version to compare
 944          *
 945          * @return A negative integer, zero, or a positive integer as this
 946          *         module version is less than, equal to, or greater than the
 947          *         given module version
 948          */
 949         @Override
 950         public int compareTo(Version that) {
 951             int c = compareTokens(this.sequence, that.sequence);
 952             if (c != 0) return c;
 953             if (this.pre.isEmpty()) {
 954                 if (!that.pre.isEmpty()) return +1;
 955             } else {
 956                 if (that.pre.isEmpty()) return -1;
 957             }
 958             c = compareTokens(this.pre, that.pre);
 959             if (c != 0) return c;
 960             return compareTokens(this.build, that.build);
 961         }
 962 
 963         /**
 964          * Tests this module version for equality with the given object.
 965          *
 966          * <p> If the given object is not a {@code Version} then this method
 967          * returns {@code false}. Two module version are equal if their
 968          * corresponding components are equal. </p>
 969          *
 970          * <p> This method satisfies the general contract of the {@link
 971          * java.lang.Object#equals(Object) Object.equals} method. </p>
 972          *
 973          * @param   ob
 974          *          the object to which this object is to be compared
 975          *
 976          * @return  {@code true} if, and only if, the given object is a module
 977          *          reference that is equal to this module reference
 978          */
 979         @Override
 980         public boolean equals(Object ob) {
 981             if (!(ob instanceof Version))
 982                 return false;
 983             return compareTo((Version)ob) == 0;
 984         }
 985 
 986         /**
 987          * Computes a hash code for this module version.
 988          *
 989          * <p> The hash code is based upon the components of the version and
 990          * satisfies the general contract of the {@link Object#hashCode
 991          * Object.hashCode} method. </p>
 992          *
 993          * @return The hash-code value for this module version
 994          */
 995         @Override
 996         public int hashCode() {
 997             return version.hashCode();
 998         }
 999 
1000         /**
1001          * Returns the string from which this version was parsed.
1002          *
1003          * @return The string from which this version was parsed.
1004          */
1005         @Override
1006         public String toString() {
1007             return version;
1008         }
1009 
1010     }
1011 
1012 
1013     private final String name;
1014     private final Version version;
1015     private final boolean open;
1016 
1017     // Indicates if synthesised for a JAR file found on the module path
1018     private final boolean automatic;
1019 
1020     // Not generated from a module-info.java
1021     private final boolean synthetic;
1022 
1023     private final Set<Requires> requires;
1024     private final Set<Exports> exports;
1025     private final Set<Opens> opens;
1026     private final Set<String> uses;
1027     private final Set<Provides> provides;
1028 
1029     // Added post-compilation by tools
1030     private final Set<String> packages;
1031     private final String mainClass;
1032     private final String osName;
1033     private final String osArch;
1034     private final String osVersion;
1035 
1036 
1037     private ModuleDescriptor(String name,
1038                              Version version,
1039                              boolean open,
1040                              boolean automatic,
1041                              boolean synthetic,
1042                              Set<Requires> requires,
1043                              Set<Exports> exports,
1044                              Set<Opens> opens,
1045                              Set<String> uses,
1046                              Set<Provides> provides,
1047                              Set<String> packages,
1048                              String mainClass,
1049                              String osName,
1050                              String osArch,
1051                              String osVersion)
1052     {
1053         this.name = name;
1054         this.version = version;
1055         this.open = open;
1056         this.automatic = automatic;
1057         this.synthetic = synthetic;
1058 
1059         assert (requires.stream().map(Requires::name).distinct().count()
1060                 == requires.size());
1061         this.requires = emptyOrUnmodifiableSet(requires);
1062         this.exports = emptyOrUnmodifiableSet(exports);
1063         this.opens = emptyOrUnmodifiableSet(opens);
1064         this.uses = emptyOrUnmodifiableSet(uses);
1065         this.provides = emptyOrUnmodifiableSet(provides);
1066 
1067         this.packages = emptyOrUnmodifiableSet(packages);
1068         this.mainClass = mainClass;
1069         this.osName = osName;
1070         this.osArch = osArch;
1071         this.osVersion = osVersion;
1072     }
1073 
1074     /**
1075      * Clones the given module descriptor with an augmented set of packages
1076      */
1077     ModuleDescriptor(ModuleDescriptor md, Set<String> pkgs) {
1078         this.name = md.name;
1079         this.version = md.version;
1080         this.open = md.open;
1081         this.automatic = md.automatic;
1082         this.synthetic = md.synthetic;
1083 
1084         this.requires = md.requires;
1085         this.exports = md.exports;
1086         this.opens = md.opens;
1087         this.uses = md.uses;
1088         this.provides = md.provides;
1089 
1090         Set<String> packages = new HashSet<>(md.packages);
1091         packages.addAll(pkgs);
1092         this.packages = emptyOrUnmodifiableSet(packages);
1093 
1094         this.mainClass = md.mainClass;
1095         this.osName = md.osName;
1096         this.osArch = md.osArch;
1097         this.osVersion = md.osVersion;
1098     }
1099 
1100     /**
1101      * Creates a module descriptor from its components.
1102      * The arguments are pre-validated and sets are unmodifiable sets.
1103      */
1104     ModuleDescriptor(String name,
1105                      Version version,
1106                      boolean open,
1107                      boolean automatic,
1108                      boolean synthetic,
1109                      Set<Requires> requires,
1110                      Set<Exports> exports,
1111                      Set<Opens> opens,
1112                      Set<String> uses,
1113                      Set<Provides> provides,
1114                      Set<String> packages,
1115                      String mainClass,
1116                      String osName,
1117                      String osArch,
1118                      String osVersion,
1119                      int hashCode,
1120                      boolean unused) {
1121         this.name = name;
1122         this.version = version;
1123         this.open = open;
1124         this.automatic = automatic;
1125         this.synthetic = synthetic;
1126         this.requires = requires;
1127         this.exports = exports;
1128         this.opens = opens;
1129         this.uses = uses;
1130         this.provides = provides;
1131         this.packages = packages;
1132         this.mainClass = mainClass;
1133         this.osName = osName;
1134         this.osArch = osArch;
1135         this.osVersion = osVersion;
1136         this.hash = hashCode;
1137     }
1138 
1139     /**
1140      * <p> The module name. </p>
1141      *
1142      * @return The module name
1143      */
1144     public String name() {
1145         return name;
1146     }
1147 
1148     /**
1149      * <p> Returns {@code true} if this is an open module. </p>
1150      *
1151      * <p> An open module does not declare any open packages (the {@link #opens()
1152      * opens} method returns an empty set) but the resulting module is treated
1153      * as if all packages are open. </p>
1154      *
1155      * @return  {@code true} if this is an open module
1156      */
1157     public boolean isOpen() {
1158         return open;
1159     }
1160 
1161     /**
1162      * <p> Returns {@code true} if this is an automatic module. </p>
1163      *
1164      * <p> An automatic module is defined implicitly rather than explicitly
1165      * and therefore does not have a module declaration. JAR files located on
1166      * the application module path, or by the {@link ModuleFinder} returned by
1167      * {@link ModuleFinder#of(java.nio.file.Path[]) ModuleFinder.of}, are
1168      * treated as automatic modules if they do have not have a module
1169      * declaration. </p>
1170      *
1171      * @return  {@code true} if this is an automatic module
1172      */
1173     public boolean isAutomatic() {
1174         return automatic;
1175     }
1176 
1177     /**
1178      * <p> Returns {@code true} if this module descriptor was not generated
1179      * from an explicit module declaration ({@code module-info.java})
1180      * or an implicit module declaration (an {@link #isAutomatic() automatic}
1181      * module). </p>
1182      *
1183      * @return  {@code true} if this module descriptor was not generated by
1184      *          an explicit or implicit module declaration
1185      */
1186     public boolean isSynthetic() {
1187         return synthetic;
1188     }
1189 
1190     /**
1191      * <p> The dependences of this module. </p>
1192      *
1193      * @return  A possibly-empty unmodifiable set of {@link Requires} objects
1194      */
1195     public Set<Requires> requires() {
1196         return requires;
1197     }
1198 
1199     /**
1200      * <p> The module exports. </p>
1201      *
1202      * @return  A possibly-empty unmodifiable set of exported packages
1203      */
1204     public Set<Exports> exports() {
1205         return exports;
1206     }
1207 
1208     /**
1209      * <p> The module <em>opens</em> directives. </p>
1210      *
1211      * <p> Each {@code Opens} object in the set represents a package (and
1212      * the set of target module names when qualified) where all types in the
1213      * package, and all their members, not just public types and their public
1214      * members, can be reflected on when using APIs that bypass or suppress
1215      * default Java language access control checks. </p>
1216      *
1217      * <p> This method returns an empty set when invoked on {@link #isOpen()
1218      * open} module. </p>
1219      *
1220      * @return  A possibly-empty unmodifiable set of open packages
1221      */
1222     public Set<Opens> opens() {
1223         return opens;
1224     }
1225 
1226     /**
1227      * <p> The service dependences of this module. </p>
1228      *
1229      * @return  A possibly-empty unmodifiable set of the fully qualified class
1230      *          names of the service types used
1231      */
1232     public Set<String> uses() {
1233         return uses;
1234     }
1235 
1236     /**
1237      * <p> The services that this module provides. </p>
1238      *
1239      * @return The possibly-empty unmodifiable set of the services that this
1240      *         module provides
1241      */
1242     public Set<Provides> provides() {
1243         return provides;
1244     }
1245 
1246     /**
1247      * Returns this module's version.
1248      *
1249      * @return This module's version
1250      */
1251     public Optional<Version> version() {
1252         return Optional.ofNullable(version);
1253     }
1254 
1255     /**
1256      * Returns a string containing this module's name and, if present, its
1257      * version.
1258      *
1259      * @return A string containing this module's name and, if present, its
1260      *         version.
1261      */
1262     public String toNameAndVersion() {
1263         if (version != null) {
1264             return name() + "@" + version;
1265         } else {
1266             return name();
1267         }
1268     }
1269 
1270     /**
1271      * Returns the module's main class.
1272      *
1273      * @return The fully qualified class name of this module's main class
1274      */
1275     public Optional<String> mainClass() {
1276         return Optional.ofNullable(mainClass);
1277     }
1278 
1279     /**
1280      * Returns the operating system name if this module is operating system
1281      * specific.
1282      *
1283      * @return The operating system name or an empty {@code Optional}
1284      *         if this module is not operating system specific
1285      */
1286     public Optional<String> osName() {
1287         return Optional.ofNullable(osName);
1288     }
1289 
1290     /**
1291      * Returns the operating system architecture if this module is operating
1292      * system architecture specific.
1293      *
1294      * @return The operating system architecture or an empty {@code Optional}
1295      *         if this module is not operating system architecture specific
1296      */
1297     public Optional<String> osArch() {
1298         return Optional.ofNullable(osArch);
1299     }
1300 
1301     /**
1302      * Returns the operating system version if this module is operating
1303      * system version specific.
1304      *
1305      * @return The operating system version or an empty {@code Optional}
1306      *         if this module is not operating system version specific
1307      */
1308     public Optional<String> osVersion() {
1309         return Optional.ofNullable(osVersion);
1310     }
1311 
1312     /**
1313      * Returns the names of all packages in this module.
1314      *
1315      * @return A possibly-empty unmodifiable set of all packages in the module
1316      */
1317     public Set<String> packages() {
1318         return packages;
1319     }
1320 
1321 
1322     /**
1323      * A builder used for building {@link ModuleDescriptor} objects.
1324      *
1325      * <p> {@code ModuleDescriptor} defines the {@link #module module}, {@link
1326      * #openModule openModule}, and {@link #automaticModule automaticModule}
1327      * methods to create builders for building different kinds of modules. </p>
1328      *
1329      * <p> Example usage: </p>
1330      * <pre>{@code    ModuleDescriptor descriptor = ModuleDescriptor.module("m1")
1331      *         .exports("p")
1332      *         .requires("m2")
1333      *         .build();
1334      * }</pre>
1335      *
1336      * @apiNote A {@code Builder} checks the components and invariants as
1337      * components are added to the builder. The rational for this is to detect
1338      * errors as early as possible and not defer all validation to the
1339      * {@link #build build} method. A {@code Builder} cannot be used to create
1340      * a {@link ModuleDescriptor#isSynthetic() synthetic} module.
1341      *
1342      * @since 9
1343      */
1344     public static final class Builder {
1345         final String name;
1346         final boolean strict; // true if module names are checked
1347         final boolean open;
1348         final boolean synthetic;
1349         boolean automatic;
1350         final Map<String, Requires> requires = new HashMap<>();
1351         final Map<String, Exports> exports = new HashMap<>();
1352         final Map<String, Opens> opens = new HashMap<>();
1353         final Set<String> concealedPackages = new HashSet<>();
1354         final Set<String> uses = new HashSet<>();
1355         final Map<String, Provides> provides = new HashMap<>();
1356         Version version;
1357         String osName;
1358         String osArch;
1359         String osVersion;
1360         String mainClass;
1361 
1362         /**
1363          * Initializes a new builder with the given module name.
1364          *
1365          * @param strict
1366          *        Indicates whether module names are checked or not
1367          */
1368         Builder(String name, boolean strict, boolean open, boolean synthetic) {
1369             this.name = (strict) ? requireModuleName(name) : name;
1370             this.strict = strict;
1371             this.open = open;
1372             this.synthetic = synthetic;
1373         }
1374 
1375         /* package */ Builder automatic(boolean automatic) {
1376             this.automatic = automatic;
1377             return this;
1378         }
1379 
1380         /**
1381          * Returns the set of packages that are exported (unconditionally or
1382          * unconditionally).
1383          */
1384         /* package */ Set<String> exportedPackages() {
1385             return exports.keySet();
1386         }
1387 
1388         /**
1389          * Returns the set of packages that are opened (unconditionally or
1390          * unconditionally).
1391          */
1392         /* package */Set<String> openPackages() {
1393             return opens.keySet();
1394         }
1395 
1396         /**
1397          * Adds a dependence on a module.
1398          *
1399          * @param  req
1400          *         The dependence
1401          *
1402          * @return This builder
1403          *
1404          * @throws IllegalArgumentException
1405          *         If the dependence is on the module that this builder was
1406          *         initialized to build
1407          * @throws IllegalStateException
1408          *         If the dependence on the module has already been declared
1409          */
1410         public Builder requires(Requires req) {
1411             String mn = req.name();
1412             if (name.equals(mn))
1413                 throw new IllegalArgumentException("Dependence on self");
1414             if (requires.containsKey(mn))
1415                 throw new IllegalStateException("Dependence upon " + mn
1416                                                 + " already declared");
1417             requires.put(mn, req);
1418             return this;
1419         }
1420 
1421         /**
1422          * Adds a dependence on a module with the given (and possibly empty)
1423          * set of modifiers. The dependence includes the version of the
1424          * module that that was recorded at compile-time.
1425          *
1426          * @param  ms
1427          *         The set of modifiers
1428          * @param  mn
1429          *         The module name
1430          * @param  compiledVersion
1431          *         The version of the module recorded at compile-time
1432          *
1433          * @return This builder
1434          *
1435          * @throws IllegalArgumentException
1436          *         If the module name is {@code null}, is not a legal Java
1437          *         identifier, or is equal to the module name that this builder
1438          *         was initialized to build
1439          * @throws IllegalStateException
1440          *         If the dependence on the module has already been declared
1441          */
1442         public Builder requires(Set<Requires.Modifier> ms,
1443                                 String mn,
1444                                 Version compiledVersion) {
1445             Objects.requireNonNull(compiledVersion);
1446             if (strict)
1447                 mn = requireModuleName(mn);
1448             return requires(new Requires(ms, mn, compiledVersion));
1449         }
1450 
1451         /**
1452          * Adds a dependence on a module with the given (and possibly empty)
1453          * set of modifiers.
1454          *
1455          * @param  ms
1456          *         The set of modifiers
1457          * @param  mn
1458          *         The module name
1459          *
1460          * @return This builder
1461          *
1462          * @throws IllegalArgumentException
1463          *         If the module name is {@code null}, is not a legal Java
1464          *         identifier, or is equal to the module name that this builder
1465          *         was initialized to build
1466          * @throws IllegalStateException
1467          *         If the dependence on the module has already been declared
1468          */
1469         public Builder requires(Set<Requires.Modifier> ms, String mn) {
1470             if (strict)
1471                 mn = requireModuleName(mn);
1472             return requires(new Requires(ms, mn, null));
1473         }
1474 
1475         /**
1476          * Adds a dependence on a module with an empty set of modifiers.
1477          *
1478          * @param  mn
1479          *         The module name
1480          *
1481          * @return This builder
1482          *
1483          * @throws IllegalArgumentException
1484          *         If the module name is {@code null}, is not a legal Java
1485          *         identifier, or is equal to the module name that this builder
1486          *         was initialized to build
1487          * @throws IllegalStateException
1488          *         If the dependence on the module has already been declared
1489          */
1490         public Builder requires(String mn) {
1491             return requires(EnumSet.noneOf(Requires.Modifier.class), mn);
1492         }
1493 
1494         /**
1495          * Adds an export.
1496          *
1497          * @param  e
1498          *         The export
1499          *
1500          * @return This builder
1501          *
1502          * @throws IllegalStateException
1503          *         If the package is already declared as a package with the
1504          *         {@link #contains contains} method or the package is already
1505          *         declared as exported
1506          */
1507         public Builder exports(Exports e) {
1508             // can't be exported and concealed
1509             String source = e.source();
1510             if (concealedPackages.contains(source)) {
1511                 throw new IllegalStateException("Package " + source
1512                                                  + " already declared");
1513             }
1514             if (exports.containsKey(source)) {
1515                 throw new IllegalStateException("Exported package " + source
1516                                                  + " already declared");
1517             }
1518 
1519             exports.put(source, e);
1520             return this;
1521         }
1522 
1523         /**
1524          * Adds an export, with the given (and possibly empty) set of modifiers,
1525          * to export a package to a set of target modules.
1526          *
1527          * @param  ms
1528          *         The set of modifiers
1529          * @param  pn
1530          *         The package name
1531          * @param  targets
1532          *         The set of target modules names
1533          *
1534          * @return This builder
1535          *
1536          * @throws IllegalArgumentException
1537          *         If the package name or any of the target modules is {@code
1538          *         null} or is not a legal Java identifier, or the set of
1539          *         targets is empty
1540          * @throws IllegalStateException
1541          *         If the package is already declared as a package with the
1542          *         {@link #contains contains} method or the package is already
1543          *         declared as exported
1544          */
1545         public Builder exports(Set<Exports.Modifier> ms,
1546                                String pn,
1547                                Set<String> targets)
1548         {
1549             Exports e = new Exports(ms, requirePackageName(pn), targets);
1550 
1551             // check targets
1552             targets = e.targets();
1553             if (targets.isEmpty())
1554                 throw new IllegalArgumentException("Empty target set");
1555             if (strict)
1556                 targets.stream().forEach(Checks::requireModuleName);
1557 
1558             return exports(e);
1559         }
1560 
1561         /**
1562          * Adds an unqualified export with the given (and possibly empty) set
1563          * of modifiers.
1564          *
1565          * @param  ms
1566          *         The set of modifiers
1567          * @param  pn
1568          *         The package name
1569          *
1570          * @return This builder
1571          *
1572          * @throws IllegalArgumentException
1573          *         If the package name is {@code null} or is not a legal Java
1574          *         identifier
1575          * @throws IllegalStateException
1576          *         If the package is already declared as a package with the
1577          *         {@link #contains contains} method or the package is already
1578          *         declared as exported
1579          */
1580         public Builder exports(Set<Exports.Modifier> ms, String pn) {
1581             Exports e = new Exports(ms, requirePackageName(pn), Collections.emptySet());
1582             return exports(e);
1583         }
1584 
1585         /**
1586          * Adds an export to export a package to a set of target modules.
1587          *
1588          * @param  pn
1589          *         The package name
1590          * @param  targets
1591          *         The set of target modules names
1592          *
1593          * @return This builder
1594          *
1595          * @throws IllegalArgumentException
1596          *         If the package name or any of the target modules is {@code
1597          *         null} or is not a legal Java identifier, or the set of
1598          *         targets is empty
1599          * @throws IllegalStateException
1600          *         If the package is already declared as a package with the
1601          *         {@link #contains contains} method or the package is already
1602          *         declared as exported
1603          */
1604         public Builder exports(String pn, Set<String> targets) {
1605             return exports(Collections.emptySet(), pn, targets);
1606         }
1607 
1608         /**
1609          * Adds an unqualified export.
1610          *
1611          * @param  pn
1612          *         The package name
1613          *
1614          * @return This builder
1615          *
1616          * @throws IllegalArgumentException
1617          *         If the package name is {@code null} or is not a legal Java
1618          *         identifier
1619          * @throws IllegalStateException
1620          *         If the package is already declared as a package with the
1621          *         {@link #contains contains} method or the package is already
1622          *         declared as exported
1623          */
1624         public Builder exports(String pn) {
1625             return exports(Collections.emptySet(), pn);
1626         }
1627 
1628         /**
1629          * Adds an <em>opens</em> directive.
1630          *
1631          * @param  obj
1632          *         The {@code Opens} object
1633          *
1634          * @return This builder
1635          *
1636          * @throws IllegalStateException
1637          *         If the package is already declared as a package with the
1638          *         {@link #contains contains} method, the package is already
1639          *         declared as open, or this is a builder for an open module
1640          */
1641         public Builder opens(Opens obj) {
1642             if (open) {
1643                 throw new IllegalStateException("open modules cannot declare"
1644                                                 + " open packages");
1645             }
1646 
1647             // can't be open and concealed
1648             String source = obj.source();
1649             if (concealedPackages.contains(source)) {
1650                 throw new IllegalStateException("Package " + source
1651                                                 + " already declared");
1652             }
1653             if (opens.containsKey(source)) {
1654                 throw new IllegalStateException("Open package " + source
1655                                                 + " already declared");
1656             }
1657 
1658             opens.put(source, obj);
1659             return this;
1660         }
1661 
1662 
1663         /**
1664          * Adds an <em>opens</em> directive, with the given (and possibly empty)
1665          * set of modifiers, to open a package to a set of target modules.
1666          *
1667          * @param  ms
1668          *         The set of modifiers
1669          * @param  pn
1670          *         The package name
1671          * @param  targets
1672          *         The set of target modules names
1673          *
1674          * @return This builder
1675          *
1676          * @throws IllegalArgumentException
1677          *         If the package name or any of the target modules is {@code
1678          *         null} or is not a legal Java identifier, or the set of
1679          *         targets is empty
1680          * @throws IllegalStateException
1681          *         If the package is already declared as a package with the
1682          *         {@link #contains contains} method, the package is already
1683          *         declared as open, or this is a builder for an open module
1684          */
1685         public Builder opens(Set<Opens.Modifier> ms,
1686                              String pn,
1687                              Set<String> targets)
1688         {
1689             Opens e = new Opens(ms, requirePackageName(pn), targets);
1690 
1691             // check targets
1692             targets = e.targets();
1693             if (targets.isEmpty())
1694                 throw new IllegalArgumentException("Empty target set");
1695             if (strict)
1696                 targets.stream().forEach(Checks::requireModuleName);
1697 
1698             return opens(e);
1699         }
1700 
1701         /**
1702          * Adds an <em>opens</em> directive to open a package with the given (and
1703          * possibly empty) set of modifiers.
1704          *
1705          * @param  ms
1706          *         The set of modifiers
1707          * @param  pn
1708          *         The package name
1709          *
1710          * @return This builder
1711          *
1712          * @throws IllegalArgumentException
1713          *         If the package name is {@code null} or is not a legal Java
1714          *         identifier
1715          * @throws IllegalStateException
1716          *         If the package is already declared as a package with the
1717          *         {@link #contains contains} method, the package is already
1718          *         declared as open, or this is a builder for an open module
1719          */
1720         public Builder opens(Set<Opens.Modifier> ms, String pn) {
1721             Opens e = new Opens(ms, requirePackageName(pn), Collections.emptySet());
1722             return opens(e);
1723         }
1724 
1725         /**
1726          * Adds an <em>opens</em> directive to open a package to a set of target
1727          * modules.
1728          *
1729          * @param  pn
1730          *         The package name
1731          * @param  targets
1732          *         The set of target modules names
1733          *
1734          * @return This builder
1735          *
1736          * @throws IllegalArgumentException
1737          *         If the package name or any of the target modules is {@code
1738          *         null} or is not a legal Java identifier, or the set of
1739          *         targets is empty
1740          * @throws IllegalStateException
1741          *         If the package is already declared as a package with the
1742          *         {@link #contains contains} method, the package is already
1743          *         declared as open, or this is a builder for an open module
1744          */
1745         public Builder opens(String pn, Set<String> targets) {
1746             return opens(Collections.emptySet(), pn, targets);
1747         }
1748 
1749         /**
1750          * Adds an <em>opens</em> directive to open a package.
1751          *
1752          * @param  pn
1753          *         The package name
1754          *
1755          * @return This builder
1756          *
1757          * @throws IllegalArgumentException
1758          *         If the package name is {@code null} or is not a legal Java
1759          *         identifier
1760          * @throws IllegalStateException
1761          *         If the package is already declared as a package with the
1762          *         {@link #contains contains} method, the package is already
1763          *         declared as open, or this is a builder for an open module
1764          */
1765         public Builder opens(String pn) {
1766             return opens(Collections.emptySet(), pn);
1767         }
1768 
1769         /**
1770          * Adds a service dependence.
1771          *
1772          * @param  service
1773          *         The service type
1774          *
1775          * @return This builder
1776          *
1777          * @throws IllegalArgumentException
1778          *         If the service type is {@code null} or is not a legal Java
1779          *         identifier
1780          * @throws IllegalStateException
1781          *         If a dependency on the service type has already been declared
1782          */
1783         public Builder uses(String service) {
1784             if (uses.contains(requireServiceTypeName(service)))
1785                 throw new IllegalStateException("Dependence upon service "
1786                                                 + service + " already declared");
1787             uses.add(service);
1788             return this;
1789         }
1790 
1791         /**
1792          * Provides a service with one or more implementations.
1793          *
1794          * @param  p
1795          *         The provides
1796          *
1797          * @return This builder
1798          *
1799          * @throws IllegalStateException
1800          *         If the providers for the service type have already been
1801          *         declared
1802          */
1803         public Builder provides(Provides p) {
1804             String st = p.service();
1805             if (provides.containsKey(st))
1806                 throw new IllegalStateException("Providers of service "
1807                                                 + st + " already declared");
1808             provides.put(st, p);
1809             return this;
1810         }
1811 
1812         /**
1813          * Provides implementations of a service.
1814          *
1815          * @param  service
1816          *         The service type
1817          * @param  providers
1818          *         The list of provider or provider factory class names
1819          *
1820          * @return This builder
1821          *
1822          * @throws IllegalArgumentException
1823          *         If the service type or any of the provider class names is
1824          *         {@code null} or is not a legal Java identifier, or the list
1825          *         of provider class names is empty
1826          * @throws IllegalStateException
1827          *         If the providers for the service type have already been
1828          *         declared
1829          */
1830         public Builder provides(String service, List<String> providers) {
1831             if (provides.containsKey(service))
1832                 throw new IllegalStateException("Providers of service "
1833                                                 + service + " already declared by " + name);
1834 
1835             Provides p = new Provides(requireServiceTypeName(service), providers);
1836 
1837             // check providers after the set has been copied.
1838             List<String> providerNames = p.providers();
1839             if (providerNames.isEmpty())
1840                 throw new IllegalArgumentException("Empty providers set");
1841             providerNames.forEach(Checks::requireServiceProviderName);
1842             provides.put(service, p);
1843             return this;
1844         }
1845 
1846         /**
1847          * Provides an implementation of a service.
1848          *
1849          * @param  service
1850          *         The service type
1851          * @param  provider
1852          *         The provider or provider factory class name
1853          *
1854          * @return This builder
1855          *
1856          * @throws IllegalArgumentException
1857          *         If the service type or the provider class name is {@code
1858          *         null} or is not a legal Java identifier
1859          * @throws IllegalStateException
1860          *         If the providers for the service type have already been
1861          *         declared
1862          */
1863         public Builder provides(String service, String provider) {
1864             if (provider == null)
1865                 throw new IllegalArgumentException("'provider' is null");
1866             return provides(service, List.of(provider));
1867         }
1868 
1869         /**
1870          * Adds a (possible empty) set of packages to the module
1871          *
1872          * @param  pns
1873          *         The set of package names
1874          *
1875          * @return This builder
1876          *
1877          * @throws IllegalArgumentException
1878          *         If any of the package names is {@code null} or is not a
1879          *         legal Java identifier
1880          * @throws IllegalStateException
1881          *         If any of packages are already declared as packages in
1882          *         the module. This includes packages that are already
1883          *         declared as exported or open packages.
1884          */
1885         public Builder contains(Set<String> pns) {
1886             pns.forEach(this::contains);
1887             return this;
1888         }
1889 
1890         /**
1891          * Adds a package to the module.
1892          *
1893          * @param  pn
1894          *         The package name
1895          *
1896          * @return This builder
1897          *
1898          * @throws IllegalArgumentException
1899          *         If the package name is {@code null}, or is not a legal Java
1900          *         identifier
1901          * @throws IllegalStateException
1902          *         If the package is already declared as a package in the
1903          *         module. This includes the package already declared as an
1904          *         exported or open package.
1905          */
1906         public Builder contains(String pn) {
1907             Checks.requirePackageName(pn);
1908             if (concealedPackages.contains(pn)) {
1909                 throw new IllegalStateException("Package " + pn
1910                                                 + " already declared");
1911             }
1912             if (exports.containsKey(pn)) {
1913                 throw new IllegalStateException("Exported package "
1914                                                 + pn + " already declared");
1915             }
1916             if (opens.containsKey(pn)) {
1917                 throw new IllegalStateException("Open package "
1918                                                  + pn + " already declared");
1919             }
1920             concealedPackages.add(pn);
1921             return this;
1922         }
1923 
1924         /**
1925          * Sets the module version.
1926          *
1927          * @param  v
1928          *         The version
1929          *
1930          * @return This builder
1931          */
1932         public Builder version(Version v) {
1933             version = requireNonNull(v);
1934             return this;
1935         }
1936 
1937         /**
1938          * Sets the module version.
1939          *
1940          * @param  v
1941          *         The version string to parse
1942          *
1943          * @return This builder
1944          *
1945          * @throws IllegalArgumentException
1946          *         If {@code v} is null or cannot be parsed as a version string
1947          *
1948          * @see Version#parse(String)
1949          */
1950         public Builder version(String v) {
1951             return version(Version.parse(v));
1952         }
1953 
1954         /**
1955          * Sets the module main class.
1956          *
1957          * @param  mc
1958          *         The module main class
1959          *
1960          * @return This builder
1961          *
1962          * @throws IllegalArgumentException
1963          *         If {@code mainClass} is null or is not a legal Java identifier
1964          */
1965         public Builder mainClass(String mc) {
1966             mainClass = requireBinaryName("main class name", mc);
1967             return this;
1968         }
1969 
1970         /**
1971          * Sets the operating system name.
1972          *
1973          * @param  name
1974          *         The operating system name
1975          *
1976          * @return This builder
1977          *
1978          * @throws IllegalArgumentException
1979          *         If {@code name} is null or the empty String
1980          */
1981         public Builder osName(String name) {
1982             if (name == null || name.isEmpty())
1983                 throw new IllegalArgumentException("OS name is null or empty");
1984             osName = name;
1985             return this;
1986         }
1987 
1988         /**
1989          * Sets the operating system architecture.
1990          *
1991          * @param  arch
1992          *         The operating system architecture
1993          *
1994          * @return This builder
1995          *
1996          * @throws IllegalArgumentException
1997          *         If {@code name} is null or the empty String
1998          */
1999         public Builder osArch(String arch) {
2000             if (arch == null || arch.isEmpty())
2001                 throw new IllegalArgumentException("OS arch is null or empty");
2002             osArch = arch;
2003             return this;
2004         }
2005 
2006         /**
2007          * Sets the operating system version.
2008          *
2009          * @param  version
2010          *         The operating system version
2011          *
2012          * @return This builder
2013          *
2014          * @throws IllegalArgumentException
2015          *         If {@code name} is null or the empty String
2016          */
2017         public Builder osVersion(String version) {
2018             if (version == null || version.isEmpty())
2019                 throw new IllegalArgumentException("OS version is null or empty");
2020             osVersion = version;
2021             return this;
2022         }
2023 
2024         /**
2025          * Builds and returns a {@code ModuleDescriptor} from its components.
2026          *
2027          * @return The module descriptor
2028          */
2029         public ModuleDescriptor build() {
2030             Set<Requires> requires = new HashSet<>(this.requires.values());
2031 
2032             Set<String> packages = new HashSet<>();
2033             packages.addAll(exports.keySet());
2034             packages.addAll(opens.keySet());
2035             packages.addAll(concealedPackages);
2036 
2037             Set<Exports> exports = new HashSet<>(this.exports.values());
2038             Set<Opens> opens = new HashSet<>(this.opens.values());
2039 
2040             Set<Provides> provides = new HashSet<>(this.provides.values());
2041 
2042             return new ModuleDescriptor(name,
2043                                         version,
2044                                         open,
2045                                         automatic,
2046                                         synthetic,
2047                                         requires,
2048                                         exports,
2049                                         opens,
2050                                         uses,
2051                                         provides,
2052                                         packages,
2053                                         mainClass,
2054                                         osName,
2055                                         osArch,
2056                                         osVersion);
2057         }
2058 
2059     }
2060 
2061     /**
2062      * Compares this module descriptor to another.
2063      *
2064      * <p> Two {@code ModuleDescriptor} objects are compared by comparing their
2065      * module name lexicographically.  Where the module names are equal then
2066      * the versions, if present, are compared. </p>
2067      *
2068      * @apiNote For now, the natural ordering is not consistent with equals.
2069      * If two module descriptors have equal module names, equal versions if
2070      * present, but their corresponding components are not equal, then they
2071      * will be considered equal by this method.
2072      *
2073      * @param  that
2074      *         The object to which this module descriptor is to be compared
2075      *
2076      * @return A negative integer, zero, or a positive integer if this module
2077      *         descriptor is less than, equal to, or greater than the given
2078      *         module descriptor
2079      */
2080     @Override
2081     public int compareTo(ModuleDescriptor that) {
2082         int c = this.name().compareTo(that.name());
2083         if (c != 0) return c;
2084         if (version == null) {
2085             if (that.version == null)
2086                 return 0;
2087             return -1;
2088         }
2089         if (that.version == null)
2090             return +1;
2091         return version.compareTo(that.version);
2092     }
2093 
2094     /**
2095      * Tests this module descriptor for equality with the given object.
2096      *
2097      * <p> If the given object is not a {@code ModuleDescriptor} then this
2098      * method returns {@code false}. Two module descriptors are equal if each
2099      * of their corresponding components is equal. </p>
2100      *
2101      * <p> This method satisfies the general contract of the {@link
2102      * java.lang.Object#equals(Object) Object.equals} method. </p>
2103      *
2104      * @param   ob
2105      *          the object to which this object is to be compared
2106      *
2107      * @return  {@code true} if, and only if, the given object is a module
2108      *          descriptor that is equal to this module descriptor
2109      */
2110     @Override
2111     public boolean equals(Object ob) {
2112         if (ob == this)
2113             return true;
2114         if (!(ob instanceof ModuleDescriptor))
2115             return false;
2116         ModuleDescriptor that = (ModuleDescriptor)ob;
2117         return (name.equals(that.name)
2118                 && open == that.open
2119                 && automatic == that.automatic
2120                 && synthetic == that.synthetic
2121                 && requires.equals(that.requires)
2122                 && exports.equals(that.exports)
2123                 && opens.equals(that.opens)
2124                 && uses.equals(that.uses)
2125                 && provides.equals(that.provides)
2126                 && Objects.equals(version, that.version)
2127                 && Objects.equals(mainClass, that.mainClass)
2128                 && Objects.equals(osName, that.osName)
2129                 && Objects.equals(osArch, that.osArch)
2130                 && Objects.equals(osVersion, that.osVersion)
2131                 && Objects.equals(packages, that.packages));
2132     }
2133 
2134     private transient int hash;  // cached hash code
2135 
2136     /**
2137      * Computes a hash code for this module descriptor.
2138      *
2139      * <p> The hash code is based upon the components of the module descriptor,
2140      * and satisfies the general contract of the {@link Object#hashCode
2141      * Object.hashCode} method. </p>
2142      *
2143      * @return The hash-code value for this module descriptor
2144      */
2145     @Override
2146     public int hashCode() {
2147         int hc = hash;
2148         if (hc == 0) {
2149             hc = name.hashCode();
2150             hc = hc * 43 + Boolean.hashCode(open);
2151             hc = hc * 43 + Boolean.hashCode(automatic);
2152             hc = hc * 43 + Boolean.hashCode(synthetic);
2153             hc = hc * 43 + requires.hashCode();
2154             hc = hc * 43 + exports.hashCode();
2155             hc = hc * 43 + opens.hashCode();
2156             hc = hc * 43 + uses.hashCode();
2157             hc = hc * 43 + provides.hashCode();
2158             hc = hc * 43 + Objects.hashCode(version);
2159             hc = hc * 43 + Objects.hashCode(mainClass);
2160             hc = hc * 43 + Objects.hashCode(osName);
2161             hc = hc * 43 + Objects.hashCode(osArch);
2162             hc = hc * 43 + Objects.hashCode(osVersion);
2163             hc = hc * 43 + Objects.hashCode(packages);
2164             if (hc == 0)
2165                 hc = -1;
2166             hash = hc;
2167         }
2168         return hc;
2169     }
2170 
2171     /**
2172      * Returns a string describing this descriptor.
2173      *
2174      * @return A string describing this descriptor
2175      */
2176     @Override
2177     public String toString() {
2178         StringBuilder sb = new StringBuilder();
2179 
2180         if (isOpen())
2181             sb.append("open ");
2182         sb.append("module { name: ").append(toNameAndVersion());
2183         if (!requires.isEmpty())
2184             sb.append(", ").append(requires);
2185         if (!uses.isEmpty())
2186             sb.append(", uses: ").append(uses);
2187         if (!exports.isEmpty())
2188             sb.append(", exports: ").append(exports);
2189         if (!opens.isEmpty())
2190             sb.append(", opens: ").append(opens);
2191         if (!provides.isEmpty()) {
2192             sb.append(", provides: ").append(provides);
2193         }
2194         sb.append(" }");
2195         return sb.toString();
2196     }
2197 
2198 
2199     /**
2200      * Instantiates a builder to build a module descriptor.
2201      *
2202      * @param  name
2203      *         The module name
2204      *
2205      * @return A new builder
2206      *
2207      * @throws IllegalArgumentException
2208      *         If the module name is {@code null} or is not a legal Java
2209      *         identifier
2210      */
2211     public static Builder module(String name) {
2212         return new Builder(name, true, false, false);
2213     }
2214 
2215     /**
2216      * Instantiates a builder to build a module descriptor for an open module.
2217      * An open module does not declare any open packages but the resulting
2218      * module is treated as if all packages are open.
2219      *
2220      * <p> As an example, the following creates a module descriptor for an open
2221      * name "{@code m}" containing two packages, one of which is exported. </p>
2222      * <pre>{@code
2223      *     ModuleDescriptor descriptor = ModuleDescriptor.openModule("m")
2224      *         .requires("java.base")
2225      *         .exports("p")
2226      *         .contains("q")
2227      *         .build();
2228      * }</pre>
2229      *
2230      * @param  name
2231      *         The module name
2232      *
2233      * @return A new builder that builds an open module
2234      *
2235      * @throws IllegalArgumentException
2236      *         If the module name is {@code null} or is not a legal Java
2237      *         identifier
2238      */
2239     public static Builder openModule(String name) {
2240         return new Builder(name, true, true, false);
2241     }
2242 
2243     /**
2244      * Instantiates a builder to build a module descriptor for an automatic
2245      * module. Automatic modules receive special treatment during resolution
2246      * (see {@link Configuration}) so that they read all other modules. When
2247      * Instantiated in the Java virtual machine as a {@link java.lang.reflect.Module}
2248      * then the Module reads every unnamed module in the Java virtual machine.
2249      *
2250      * @param  name
2251      *         The module name
2252      *
2253      * @return A new builder that builds an automatic module
2254      *
2255      * @throws IllegalArgumentException
2256      *         If the module name is {@code null} or is not a legal Java
2257      *         identifier
2258      *
2259      * @see ModuleFinder#of(Path[])
2260      */
2261     public static Builder automaticModule(String name) {
2262         return new Builder(name, true, false, false).automatic(true);
2263     }
2264 
2265 
2266     /**
2267      * Reads the binary form of a module declaration from an input stream
2268      * as a module descriptor.
2269      *
2270      * <p> If the descriptor encoded in the input stream does not indicate a
2271      * set of packages in the module then the {@code packageFinder} will be
2272      * invoked. If the {@code packageFinder} throws an {@link UncheckedIOException}
2273      * then {@link IOException} cause will be re-thrown. </p>
2274      *
2275      * <p> If there are bytes following the module descriptor then it is
2276      * implementation specific as to whether those bytes are read, ignored,
2277      * or reported as an {@code InvalidModuleDescriptorException}. If this
2278      * method fails with an {@code InvalidModuleDescriptorException} or {@code
2279      * IOException} then it may do so after some, but not all, bytes have
2280      * been read from the input stream. It is strongly recommended that the
2281      * stream be promptly closed and discarded if an exception occurs. </p>
2282      *
2283      * @apiNote The {@code packageFinder} parameter is for use when reading
2284      * module descriptors from legacy module-artifact formats that do not
2285      * record the set of packages in the descriptor itself.
2286      *
2287      * @param  in
2288      *         The input stream
2289      * @param  packageFinder
2290      *         A supplier that can produce the set of packages
2291      *
2292      * @return The module descriptor
2293      *
2294      * @throws InvalidModuleDescriptorException
2295      *         If an invalid module descriptor is detected
2296      * @throws IOException
2297      *         If an I/O error occurs reading from the input stream or {@code
2298      *         UncheckedIOException} is thrown by the package finder
2299      */
2300     public static ModuleDescriptor read(InputStream in,
2301                                         Supplier<Set<String>> packageFinder)
2302         throws IOException
2303     {
2304         return ModuleInfo.read(in, requireNonNull(packageFinder)).descriptor();
2305     }
2306 
2307     /**
2308      * Reads the binary form of a module declaration from an input stream
2309      * as a module descriptor.
2310      *
2311      * @param  in
2312      *         The input stream
2313      *
2314      * @return The module descriptor
2315      *
2316      * @throws InvalidModuleDescriptorException
2317      *         If an invalid module descriptor is detected
2318      * @throws IOException
2319      *         If an I/O error occurs reading from the input stream
2320      */
2321     public static ModuleDescriptor read(InputStream in) throws IOException {
2322         return ModuleInfo.read(in, null).descriptor();
2323     }
2324 
2325     /**
2326      * Reads the binary form of a module declaration from a byte buffer
2327      * as a module descriptor.
2328      *
2329      * <p> If the descriptor encoded in the byte buffer does not indicate a
2330      * set of packages then the {@code packageFinder} will be invoked. </p>
2331      *
2332      * <p> The module descriptor is read from the buffer stating at index
2333      * {@code p}, where {@code p} is the buffer's {@link ByteBuffer#position()
2334      * position} when this method is invoked. Upon return the buffer's position
2335      * will be equal to {@code p + n} where {@code n} is the number of bytes
2336      * read from the buffer. </p>
2337      *
2338      * <p> If there are bytes following the module descriptor then it is
2339      * implementation specific as to whether those bytes are read, ignored,
2340      * or reported as an {@code InvalidModuleDescriptorException}. If this
2341      * method fails with an {@code InvalidModuleDescriptorException} then it
2342      * may do so after some, but not all, bytes have been read. </p>
2343      *
2344      * @apiNote The {@code packageFinder} parameter is for use when reading
2345      * module descriptors from legacy module-artifact formats that do not
2346      * record the set of packages in the descriptor itself.
2347      *
2348      * @param  bb
2349      *         The byte buffer
2350      * @param  packageFinder
2351      *         A supplier that can produce the set of packages
2352      *
2353      * @return The module descriptor
2354      *
2355      * @throws InvalidModuleDescriptorException
2356      *         If an invalid module descriptor is detected
2357      */
2358     public static ModuleDescriptor read(ByteBuffer bb,
2359                                         Supplier<Set<String>> packageFinder)
2360     {
2361         return ModuleInfo.read(bb, requireNonNull(packageFinder)).descriptor();
2362     }
2363 
2364     /**
2365      * Reads the binary form of a module declaration from a byte buffer
2366      * as a module descriptor.
2367      *
2368      * @param  bb
2369      *         The byte buffer
2370      *
2371      * @return The module descriptor
2372      *
2373      * @throws InvalidModuleDescriptorException
2374      *         If an invalid module descriptor is detected
2375      */
2376     public static ModuleDescriptor read(ByteBuffer bb) {
2377         return ModuleInfo.read(bb, null).descriptor();
2378     }
2379 
2380     private static <K,V> Map<K,V> emptyOrUnmodifiableMap(Map<K,V> map) {
2381         if (map.isEmpty()) {
2382             return Collections.emptyMap();
2383         } else if (map.size() == 1) {
2384             Map.Entry<K, V> entry = map.entrySet().iterator().next();
2385             return Collections.singletonMap(entry.getKey(), entry.getValue());
2386         } else {
2387             return Collections.unmodifiableMap(map);
2388         }
2389     }
2390 
2391     private static <T> Set<T> emptyOrUnmodifiableSet(Set<T> set) {
2392         if (set.isEmpty()) {
2393             return Collections.emptySet();
2394         } else if (set.size() == 1) {
2395             return Collections.singleton(set.iterator().next());
2396         } else {
2397             return Collections.unmodifiableSet(set);
2398         }
2399     }
2400 
2401     /**
2402      * Returns a string containing the given set of modifiers and label.
2403      */
2404     private static <M> String toString(Set<M> mods, String what) {
2405         return (Stream.concat(mods.stream().map(e -> e.toString().toLowerCase()),
2406                               Stream.of(what)))
2407                 .collect(Collectors.joining(" "));
2408     }
2409 
2410     static {
2411         /**
2412          * Setup the shared secret to allow code in other packages access
2413          * private package methods in java.lang.module.
2414          */
2415         jdk.internal.misc.SharedSecrets
2416             .setJavaLangModuleAccess(new jdk.internal.misc.JavaLangModuleAccess() {
2417                 @Override
2418                 public Builder newModuleBuilder(String mn,
2419                                                 boolean strict,
2420                                                 boolean open,
2421                                                 boolean synthetic) {
2422                     return new Builder(mn, strict, open, synthetic);
2423                 }
2424 
2425                 @Override
2426                 public Set<String> exportedPackages(ModuleDescriptor.Builder builder) {
2427                     return builder.exportedPackages();
2428                 }
2429 
2430                 @Override
2431                 public Set<String> openPackages(ModuleDescriptor.Builder builder) {
2432                     return builder.openPackages();
2433                 }
2434 
2435                 @Override
2436                 public Requires newRequires(Set<Requires.Modifier> ms, String mn, Version v) {
2437                     return new Requires(ms, mn, v, true);
2438                 }
2439 
2440                 @Override
2441                 public Exports newExports(Set<Exports.Modifier> ms, String source) {
2442                     return new Exports(ms, source, Collections.emptySet(), true);
2443                 }
2444 
2445                 @Override
2446                 public Exports newExports(Set<Exports.Modifier> ms,
2447                                           String source,
2448                                           Set<String> targets) {
2449                     return new Exports(ms, source, targets, true);
2450                 }
2451 
2452                 @Override
2453                 public Opens newOpens(Set<Opens.Modifier> ms,
2454                                       String source,
2455                                       Set<String> targets) {
2456                     return new Opens(ms, source, targets, true);
2457                 }
2458 
2459                 @Override
2460                 public Opens newOpens(Set<Opens.Modifier> ms, String source) {
2461                     return new Opens(ms, source, Collections.emptySet(), true);
2462                 }
2463 
2464                 @Override
2465                 public Provides newProvides(String service, List<String> providers) {
2466                     return new Provides(service, providers, true);
2467                 }
2468 
2469                 @Override
2470                 public Version newVersion(String v) {
2471                     return new Version(v);
2472                 }
2473 
2474                 @Override
2475                 public ModuleDescriptor newModuleDescriptor(ModuleDescriptor md,
2476                                                             Set<String> pkgs) {
2477                     return new ModuleDescriptor(md, pkgs);
2478                 }
2479 
2480                 @Override
2481                 public ModuleDescriptor newModuleDescriptor(String name,
2482                                                             Version version,
2483                                                             boolean open,
2484                                                             boolean automatic,
2485                                                             boolean synthetic,
2486                                                             Set<Requires> requires,
2487                                                             Set<Exports> exports,
2488                                                             Set<Opens> opens,
2489                                                             Set<String> uses,
2490                                                             Set<Provides> provides,
2491                                                             Set<String> packages,
2492                                                             String mainClass,
2493                                                             String osName,
2494                                                             String osArch,
2495                                                             String osVersion,
2496                                                             int hashCode) {
2497                     return new ModuleDescriptor(name,
2498                                                 version,
2499                                                 open,
2500                                                 automatic,
2501                                                 synthetic,
2502                                                 requires,
2503                                                 exports,
2504                                                 opens,
2505                                                 uses,
2506                                                 provides,
2507                                                 packages,
2508                                                 mainClass,
2509                                                 osName,
2510                                                 osArch,
2511                                                 osVersion,
2512                                                 hashCode,
2513                                                 false);
2514                 }
2515 
2516                 @Override
2517                 public Configuration resolveRequiresAndUses(ModuleFinder finder,
2518                                                             Collection<String> roots,
2519                                                             boolean check,
2520                                                             PrintStream traceOutput)
2521                 {
2522                     return Configuration.resolveRequiresAndUses(finder, roots, check, traceOutput);
2523                 }
2524             });
2525     }
2526 
2527 }