< prev index next >

src/java.base/share/classes/java/util/jar/JarFile.java

Print this page
rev 48062 : 8192833: JEP 322: Time-Based Release Versioning


 100  * <p>If the verify flag is on when opening a signed jar file, the content of
 101  * the file is verified against its signature embedded inside the file. Please
 102  * note that the verification process does not include validating the signer's
 103  * certificate. A caller should inspect the return value of
 104  * {@link JarEntry#getCodeSigners()} to further determine if the signature
 105  * can be trusted.
 106  *
 107  * <p> Unless otherwise noted, passing a {@code null} argument to a constructor
 108  * or method in this class will cause a {@link NullPointerException} to be
 109  * thrown.
 110  *
 111  * @implNote
 112  * <div class="block">
 113  * If the API can not be used to configure a {@code JarFile} (e.g. to override
 114  * the configuration of a compiled application or library), two {@code System}
 115  * properties are available.
 116  * <ul>
 117  * <li>
 118  * {@code jdk.util.jar.version} can be assigned a value that is the
 119  * {@code String} representation of a non-negative integer
 120  * {@code <= Runtime.version().major()}.  The value is used to set the effective
 121  * runtime version to something other than the default value obtained by
 122  * evaluating {@code Runtime.version().major()}. The effective runtime version
 123  * is the version that the {@link JarFile#JarFile(File, boolean, int, Runtime.Version)}
 124  * constructor uses when the value of the last argument is
 125  * {@code JarFile.runtimeVersion()}.
 126  * </li>
 127  * <li>
 128  * {@code jdk.util.jar.enableMultiRelease} can be assigned one of the three
 129  * {@code String} values <em>true</em>, <em>false</em>, or <em>force</em>.  The
 130  * value <em>true</em>, the default value, enables multi-release jar file
 131  * processing.  The value <em>false</em> disables multi-release jar processing,
 132  * ignoring the "Multi-Release" manifest attribute, and the versioned
 133  * directories in a multi-release jar file if they exist.  Furthermore,
 134  * the method {@link JarFile#isMultiRelease()} returns <em>false</em>. The value
 135  * <em>force</em> causes the {@code JarFile} to be initialized to runtime
 136  * versioning after construction.  It effectively does the same as this code:
 137  * {@code (new JarFile(File, boolean, int, JarFile.runtimeVersion())}.
 138  * </li>
 139  * </ul>
 140  * </div>
 141  *
 142  * @author  David Connelly
 143  * @see     Manifest
 144  * @see     java.util.zip.ZipFile
 145  * @see     java.util.jar.JarEntry
 146  * @since   1.2
 147  */
 148 public
 149 class JarFile extends ZipFile {
 150     private final static Runtime.Version BASE_VERSION;
 151     private final static int BASE_VERSION_MAJOR;
 152     private final static Runtime.Version RUNTIME_VERSION;
 153     private final static boolean MULTI_RELEASE_ENABLED;
 154     private final static boolean MULTI_RELEASE_FORCED;
 155     private SoftReference<Manifest> manRef;
 156     private JarEntry manEntry;
 157     private JarVerifier jv;
 158     private boolean jvInitialized;
 159     private boolean verify;
 160     private final Runtime.Version version;  // current version
 161     private final int versionMajor;         // version.major()
 162     private boolean isMultiRelease;         // is jar multi-release?
 163 
 164     // indicates if Class-Path attribute present
 165     private boolean hasClassPathAttribute;
 166     // true if manifest checked for special attributes
 167     private volatile boolean hasCheckedSpecialAttributes;
 168 
 169     private static final JavaUtilZipFileAccess JUZFA;
 170 
 171     static {
 172         // Set up JavaUtilJarAccess in SharedSecrets
 173         SharedSecrets.setJavaUtilJarAccess(new JavaUtilJarAccessImpl());
 174         // Get JavaUtilZipFileAccess from SharedSecrets
 175         JUZFA = jdk.internal.misc.SharedSecrets.getJavaUtilZipFileAccess();
 176         // multi-release jar file versions >= 9
 177         BASE_VERSION = Runtime.Version.parse(Integer.toString(8));
 178         BASE_VERSION_MAJOR = BASE_VERSION.major();
 179         String jarVersion = GetPropertyAction.privilegedGetProperty("jdk.util.jar.version");
 180         int runtimeVersion = Runtime.version().major();
 181         if (jarVersion != null) {
 182             int jarVer = Integer.parseInt(jarVersion);
 183             runtimeVersion = (jarVer > runtimeVersion)
 184                     ? runtimeVersion
 185                     : Math.max(jarVer, BASE_VERSION_MAJOR);
 186         }
 187         RUNTIME_VERSION = Runtime.Version.parse(Integer.toString(runtimeVersion));
 188         String enableMultiRelease = GetPropertyAction
 189                 .privilegedGetProperty("jdk.util.jar.enableMultiRelease", "true");
 190         switch (enableMultiRelease) {
 191             case "true":
 192             default:
 193                 MULTI_RELEASE_ENABLED = true;
 194                 MULTI_RELEASE_FORCED = false;
 195                 break;
 196             case "false":
 197                 MULTI_RELEASE_ENABLED = false;
 198                 MULTI_RELEASE_FORCED = false;
 199                 break;
 200             case "force":
 201                 MULTI_RELEASE_ENABLED = true;
 202                 MULTI_RELEASE_FORCED = true;
 203                 break;
 204         }
 205     }


 212      * The JAR manifest file name.
 213      */
 214     public static final String MANIFEST_NAME = META_INF + "MANIFEST.MF";
 215 
 216     /**
 217      * Returns the version that represents the unversioned configuration of a
 218      * multi-release jar file.
 219      *
 220      * @return the version that represents the unversioned configuration
 221      *
 222      * @since 9
 223      */
 224     public static Runtime.Version baseVersion() {
 225         return BASE_VERSION;
 226     }
 227 
 228     /**
 229      * Returns the version that represents the effective runtime versioned
 230      * configuration of a multi-release jar file.
 231      * <p>
 232      * By default the major version number of the returned {@code Version} will
 233      * be equal to the major version number of {@code Runtime.version()}.
 234      * However, if the {@code jdk.util.jar.version} property is set, the
 235      * returned {@code Version} is derived from that property and major version
 236      * numbers may not be equal.
 237      *
 238      * @return the version that represents the runtime versioned configuration
 239      *
 240      * @since 9
 241      */
 242     public static Runtime.Version runtimeVersion() {
 243         return RUNTIME_VERSION;
 244     }
 245 
 246     /**
 247      * Creates a new {@code JarFile} to read from the specified
 248      * file {@code name}. The {@code JarFile} will be verified if
 249      * it is signed.
 250      * @param name the name of the jar file to be opened for reading
 251      * @throws IOException if an I/O error has occurred
 252      * @throws SecurityException if access to the file is denied
 253      *         by the SecurityManager
 254      */
 255     public JarFile(String name) throws IOException {


 310      * @throws IllegalArgumentException
 311      *         if the {@code mode} argument is invalid
 312      * @throws SecurityException if access to the file is denied
 313      *         by the SecurityManager
 314      * @since 1.3
 315      */
 316     public JarFile(File file, boolean verify, int mode) throws IOException {
 317         this(file, verify, mode, BASE_VERSION);
 318     }
 319 
 320     /**
 321      * Creates a new {@code JarFile} to read from the specified
 322      * {@code File} object in the specified mode.  The mode argument
 323      * must be either {@code OPEN_READ} or {@code OPEN_READ | OPEN_DELETE}.
 324      * The version argument, after being converted to a canonical form, is
 325      * used to configure the {@code JarFile} for processing
 326      * multi-release jar files.
 327      * <p>
 328      * The canonical form derived from the version parameter is
 329      * {@code Runtime.Version.parse(Integer.toString(n))} where {@code n} is
 330      * {@code Math.max(version.major(), JarFile.baseVersion().major())}.
 331      *
 332      * @param file the jar file to be opened for reading
 333      * @param verify whether or not to verify the jar file if
 334      * it is signed.
 335      * @param mode the mode in which the file is to be opened
 336      * @param version specifies the release version for a multi-release jar file
 337      * @throws IOException if an I/O error has occurred
 338      * @throws IllegalArgumentException
 339      *         if the {@code mode} argument is invalid
 340      * @throws SecurityException if access to the file is denied
 341      *         by the SecurityManager
 342      * @throws NullPointerException if {@code version} is {@code null}
 343      * @since 9
 344      */
 345     public JarFile(File file, boolean verify, int mode, Runtime.Version version) throws IOException {
 346         super(file, mode);
 347         this.verify = verify;
 348         Objects.requireNonNull(version);
 349         if (MULTI_RELEASE_FORCED || version.major() == RUNTIME_VERSION.major()) {
 350             // This deals with the common case where the value from JarFile.runtimeVersion() is passed
 351             this.version = RUNTIME_VERSION;
 352         } else if (version.major() <= BASE_VERSION_MAJOR) {
 353             // This also deals with the common case where the value from JarFile.baseVersion() is passed
 354             this.version = BASE_VERSION;
 355         } else {
 356             // Canonicalize
 357             this.version = Runtime.Version.parse(Integer.toString(version.major()));
 358         }
 359         this.versionMajor = this.version.major();
 360     }
 361 
 362     /**
 363      * Returns the maximum version used when searching for versioned entries.
 364      * <p>
 365      * If this {@code JarFile} is not a multi-release jar file or is not
 366      * configured to be processed as such, then the version returned will be the
 367      * same as that returned from {@link #baseVersion()}.
 368      *
 369      * @return the maximum version
 370      * @since 9
 371      */
 372     public final Runtime.Version getVersion() {
 373         return isMultiRelease() ? this.version : BASE_VERSION;
 374     }
 375 
 376     /**
 377      * Indicates whether or not this jar file is a multi-release jar file.
 378      *
 379      * @return true if this JarFile is a multi-release jar file


 560         }
 561         return stream();
 562     }
 563 
 564     /*
 565      * Invokes {@ZipFile}'s getEntry to Return a {@code JarFileEntry} for the
 566      * given entry name or {@code null} if not found.
 567      */
 568     private JarFileEntry getEntry0(String name) {
 569         return (JarFileEntry)JUZFA.getEntry(this, name, JarFileEntry::new);
 570     }
 571 
 572     private String getBasename(String name) {
 573         if (name.startsWith(META_INF_VERSIONS)) {
 574             int off = META_INF_VERSIONS.length();
 575             int index = name.indexOf('/', off);
 576             try {
 577                 // filter out dir META-INF/versions/ and META-INF/versions/*/
 578                 // and any entry with version > 'version'
 579                 if (index == -1 || index == (name.length() - 1) ||
 580                     Integer.parseInt(name, off, index, 10) > versionMajor) {
 581                     return null;
 582                 }
 583             } catch (NumberFormatException x) {
 584                 return null; // remove malformed entries silently
 585             }
 586             // map to its base name
 587             return name.substring(index + 1);
 588         }
 589         return name;
 590     }
 591 
 592     private JarEntry getVersionedEntry(String name, JarEntry je) {
 593         if (BASE_VERSION_MAJOR < versionMajor) {
 594             if (!name.startsWith(META_INF)) {
 595                 // search for versioned entry
 596                 int v = versionMajor;
 597                 while (v > BASE_VERSION_MAJOR) {
 598                     JarFileEntry vje = getEntry0(META_INF_VERSIONS + v + "/" + name);
 599                     if (vje != null) {
 600                         return vje.withBasename(name);
 601                     }
 602                     v--;
 603                 }
 604             }
 605         }
 606         return je;
 607     }
 608 
 609     // placeholder for now
 610     String getRealName(JarEntry entry) {
 611         return entry.getRealName();
 612     }
 613 
 614     private class JarFileEntry extends JarEntry {
 615         private String basename;
 616 
 617         JarFileEntry(String name) {


 654             } catch (IOException e) {
 655                 throw new RuntimeException(e);
 656             }
 657             if (signers == null && jv != null) {
 658                 signers = jv.getCodeSigners(JarFile.this, realEntry());
 659             }
 660             return signers == null ? null : signers.clone();
 661         }
 662 
 663         @Override
 664         public String getRealName() {
 665             return super.getName();
 666         }
 667 
 668         @Override
 669         public String getName() {
 670             return basename;
 671         }
 672 
 673         JarFileEntry realEntry() {
 674             if (isMultiRelease() && versionMajor != BASE_VERSION_MAJOR) {
 675                 String entryName = super.getName();
 676                 return entryName == basename || entryName.equals(basename) ?
 677                         this : new JarFileEntry(entryName, this);
 678             }
 679             return this;
 680         }
 681 
 682         // changes the basename, returns "this"
 683         JarFileEntry withBasename(String name) {
 684             basename = name;
 685             return this;
 686         }
 687     }
 688 
 689     /*
 690      * Ensures that the JarVerifier has been created if one is
 691      * necessary (i.e., the jar appears to be signed.) This is done as
 692      * a quick check to avoid processing of the manifest for unsigned
 693      * jars.
 694      */




 100  * <p>If the verify flag is on when opening a signed jar file, the content of
 101  * the file is verified against its signature embedded inside the file. Please
 102  * note that the verification process does not include validating the signer's
 103  * certificate. A caller should inspect the return value of
 104  * {@link JarEntry#getCodeSigners()} to further determine if the signature
 105  * can be trusted.
 106  *
 107  * <p> Unless otherwise noted, passing a {@code null} argument to a constructor
 108  * or method in this class will cause a {@link NullPointerException} to be
 109  * thrown.
 110  *
 111  * @implNote
 112  * <div class="block">
 113  * If the API can not be used to configure a {@code JarFile} (e.g. to override
 114  * the configuration of a compiled application or library), two {@code System}
 115  * properties are available.
 116  * <ul>
 117  * <li>
 118  * {@code jdk.util.jar.version} can be assigned a value that is the
 119  * {@code String} representation of a non-negative integer
 120  * {@code <= Runtime.version().feature()}.  The value is used to set the effective
 121  * runtime version to something other than the default value obtained by
 122  * evaluating {@code Runtime.version().feature()}. The effective runtime version
 123  * is the version that the {@link JarFile#JarFile(File, boolean, int, Runtime.Version)}
 124  * constructor uses when the value of the last argument is
 125  * {@code JarFile.runtimeVersion()}.
 126  * </li>
 127  * <li>
 128  * {@code jdk.util.jar.enableMultiRelease} can be assigned one of the three
 129  * {@code String} values <em>true</em>, <em>false</em>, or <em>force</em>.  The
 130  * value <em>true</em>, the default value, enables multi-release jar file
 131  * processing.  The value <em>false</em> disables multi-release jar processing,
 132  * ignoring the "Multi-Release" manifest attribute, and the versioned
 133  * directories in a multi-release jar file if they exist.  Furthermore,
 134  * the method {@link JarFile#isMultiRelease()} returns <em>false</em>. The value
 135  * <em>force</em> causes the {@code JarFile} to be initialized to runtime
 136  * versioning after construction.  It effectively does the same as this code:
 137  * {@code (new JarFile(File, boolean, int, JarFile.runtimeVersion())}.
 138  * </li>
 139  * </ul>
 140  * </div>
 141  *
 142  * @author  David Connelly
 143  * @see     Manifest
 144  * @see     java.util.zip.ZipFile
 145  * @see     java.util.jar.JarEntry
 146  * @since   1.2
 147  */
 148 public
 149 class JarFile extends ZipFile {
 150     private final static Runtime.Version BASE_VERSION;
 151     private final static int BASE_VERSION_FEATURE;
 152     private final static Runtime.Version RUNTIME_VERSION;
 153     private final static boolean MULTI_RELEASE_ENABLED;
 154     private final static boolean MULTI_RELEASE_FORCED;
 155     private SoftReference<Manifest> manRef;
 156     private JarEntry manEntry;
 157     private JarVerifier jv;
 158     private boolean jvInitialized;
 159     private boolean verify;
 160     private final Runtime.Version version;  // current version
 161     private final int versionFeature;         // version.feature()
 162     private boolean isMultiRelease;         // is jar multi-release?
 163 
 164     // indicates if Class-Path attribute present
 165     private boolean hasClassPathAttribute;
 166     // true if manifest checked for special attributes
 167     private volatile boolean hasCheckedSpecialAttributes;
 168 
 169     private static final JavaUtilZipFileAccess JUZFA;
 170 
 171     static {
 172         // Set up JavaUtilJarAccess in SharedSecrets
 173         SharedSecrets.setJavaUtilJarAccess(new JavaUtilJarAccessImpl());
 174         // Get JavaUtilZipFileAccess from SharedSecrets
 175         JUZFA = jdk.internal.misc.SharedSecrets.getJavaUtilZipFileAccess();
 176         // multi-release jar file versions >= 9
 177         BASE_VERSION = Runtime.Version.parse(Integer.toString(8));
 178         BASE_VERSION_FEATURE = BASE_VERSION.feature();
 179         String jarVersion = GetPropertyAction.privilegedGetProperty("jdk.util.jar.version");
 180         int runtimeVersion = Runtime.version().feature();
 181         if (jarVersion != null) {
 182             int jarVer = Integer.parseInt(jarVersion);
 183             runtimeVersion = (jarVer > runtimeVersion)
 184                     ? runtimeVersion
 185                     : Math.max(jarVer, BASE_VERSION_FEATURE);
 186         }
 187         RUNTIME_VERSION = Runtime.Version.parse(Integer.toString(runtimeVersion));
 188         String enableMultiRelease = GetPropertyAction
 189                 .privilegedGetProperty("jdk.util.jar.enableMultiRelease", "true");
 190         switch (enableMultiRelease) {
 191             case "true":
 192             default:
 193                 MULTI_RELEASE_ENABLED = true;
 194                 MULTI_RELEASE_FORCED = false;
 195                 break;
 196             case "false":
 197                 MULTI_RELEASE_ENABLED = false;
 198                 MULTI_RELEASE_FORCED = false;
 199                 break;
 200             case "force":
 201                 MULTI_RELEASE_ENABLED = true;
 202                 MULTI_RELEASE_FORCED = true;
 203                 break;
 204         }
 205     }


 212      * The JAR manifest file name.
 213      */
 214     public static final String MANIFEST_NAME = META_INF + "MANIFEST.MF";
 215 
 216     /**
 217      * Returns the version that represents the unversioned configuration of a
 218      * multi-release jar file.
 219      *
 220      * @return the version that represents the unversioned configuration
 221      *
 222      * @since 9
 223      */
 224     public static Runtime.Version baseVersion() {
 225         return BASE_VERSION;
 226     }
 227 
 228     /**
 229      * Returns the version that represents the effective runtime versioned
 230      * configuration of a multi-release jar file.
 231      * <p>
 232      * By default the feature version number of the returned {@code Version} will
 233      * be equal to the feature version number of {@code Runtime.version()}.
 234      * However, if the {@code jdk.util.jar.version} property is set, the
 235      * returned {@code Version} is derived from that property and feature version
 236      * numbers may not be equal.
 237      *
 238      * @return the version that represents the runtime versioned configuration
 239      *
 240      * @since 9
 241      */
 242     public static Runtime.Version runtimeVersion() {
 243         return RUNTIME_VERSION;
 244     }
 245 
 246     /**
 247      * Creates a new {@code JarFile} to read from the specified
 248      * file {@code name}. The {@code JarFile} will be verified if
 249      * it is signed.
 250      * @param name the name of the jar file to be opened for reading
 251      * @throws IOException if an I/O error has occurred
 252      * @throws SecurityException if access to the file is denied
 253      *         by the SecurityManager
 254      */
 255     public JarFile(String name) throws IOException {


 310      * @throws IllegalArgumentException
 311      *         if the {@code mode} argument is invalid
 312      * @throws SecurityException if access to the file is denied
 313      *         by the SecurityManager
 314      * @since 1.3
 315      */
 316     public JarFile(File file, boolean verify, int mode) throws IOException {
 317         this(file, verify, mode, BASE_VERSION);
 318     }
 319 
 320     /**
 321      * Creates a new {@code JarFile} to read from the specified
 322      * {@code File} object in the specified mode.  The mode argument
 323      * must be either {@code OPEN_READ} or {@code OPEN_READ | OPEN_DELETE}.
 324      * The version argument, after being converted to a canonical form, is
 325      * used to configure the {@code JarFile} for processing
 326      * multi-release jar files.
 327      * <p>
 328      * The canonical form derived from the version parameter is
 329      * {@code Runtime.Version.parse(Integer.toString(n))} where {@code n} is
 330      * {@code Math.max(version.feature(), JarFile.baseVersion().feature())}.
 331      *
 332      * @param file the jar file to be opened for reading
 333      * @param verify whether or not to verify the jar file if
 334      * it is signed.
 335      * @param mode the mode in which the file is to be opened
 336      * @param version specifies the release version for a multi-release jar file
 337      * @throws IOException if an I/O error has occurred
 338      * @throws IllegalArgumentException
 339      *         if the {@code mode} argument is invalid
 340      * @throws SecurityException if access to the file is denied
 341      *         by the SecurityManager
 342      * @throws NullPointerException if {@code version} is {@code null}
 343      * @since 9
 344      */
 345     public JarFile(File file, boolean verify, int mode, Runtime.Version version) throws IOException {
 346         super(file, mode);
 347         this.verify = verify;
 348         Objects.requireNonNull(version);
 349         if (MULTI_RELEASE_FORCED || version.feature() == RUNTIME_VERSION.feature()) {
 350             // This deals with the common case where the value from JarFile.runtimeVersion() is passed
 351             this.version = RUNTIME_VERSION;
 352         } else if (version.feature() <= BASE_VERSION_FEATURE) {
 353             // This also deals with the common case where the value from JarFile.baseVersion() is passed
 354             this.version = BASE_VERSION;
 355         } else {
 356             // Canonicalize
 357             this.version = Runtime.Version.parse(Integer.toString(version.feature()));
 358         }
 359         this.versionFeature = this.version.feature();
 360     }
 361 
 362     /**
 363      * Returns the maximum version used when searching for versioned entries.
 364      * <p>
 365      * If this {@code JarFile} is not a multi-release jar file or is not
 366      * configured to be processed as such, then the version returned will be the
 367      * same as that returned from {@link #baseVersion()}.
 368      *
 369      * @return the maximum version
 370      * @since 9
 371      */
 372     public final Runtime.Version getVersion() {
 373         return isMultiRelease() ? this.version : BASE_VERSION;
 374     }
 375 
 376     /**
 377      * Indicates whether or not this jar file is a multi-release jar file.
 378      *
 379      * @return true if this JarFile is a multi-release jar file


 560         }
 561         return stream();
 562     }
 563 
 564     /*
 565      * Invokes {@ZipFile}'s getEntry to Return a {@code JarFileEntry} for the
 566      * given entry name or {@code null} if not found.
 567      */
 568     private JarFileEntry getEntry0(String name) {
 569         return (JarFileEntry)JUZFA.getEntry(this, name, JarFileEntry::new);
 570     }
 571 
 572     private String getBasename(String name) {
 573         if (name.startsWith(META_INF_VERSIONS)) {
 574             int off = META_INF_VERSIONS.length();
 575             int index = name.indexOf('/', off);
 576             try {
 577                 // filter out dir META-INF/versions/ and META-INF/versions/*/
 578                 // and any entry with version > 'version'
 579                 if (index == -1 || index == (name.length() - 1) ||
 580                     Integer.parseInt(name, off, index, 10) > versionFeature) {
 581                     return null;
 582                 }
 583             } catch (NumberFormatException x) {
 584                 return null; // remove malformed entries silently
 585             }
 586             // map to its base name
 587             return name.substring(index + 1);
 588         }
 589         return name;
 590     }
 591 
 592     private JarEntry getVersionedEntry(String name, JarEntry je) {
 593         if (BASE_VERSION_FEATURE < versionFeature) {
 594             if (!name.startsWith(META_INF)) {
 595                 // search for versioned entry
 596                 int v = versionFeature;
 597                 while (v > BASE_VERSION_FEATURE) {
 598                     JarFileEntry vje = getEntry0(META_INF_VERSIONS + v + "/" + name);
 599                     if (vje != null) {
 600                         return vje.withBasename(name);
 601                     }
 602                     v--;
 603                 }
 604             }
 605         }
 606         return je;
 607     }
 608 
 609     // placeholder for now
 610     String getRealName(JarEntry entry) {
 611         return entry.getRealName();
 612     }
 613 
 614     private class JarFileEntry extends JarEntry {
 615         private String basename;
 616 
 617         JarFileEntry(String name) {


 654             } catch (IOException e) {
 655                 throw new RuntimeException(e);
 656             }
 657             if (signers == null && jv != null) {
 658                 signers = jv.getCodeSigners(JarFile.this, realEntry());
 659             }
 660             return signers == null ? null : signers.clone();
 661         }
 662 
 663         @Override
 664         public String getRealName() {
 665             return super.getName();
 666         }
 667 
 668         @Override
 669         public String getName() {
 670             return basename;
 671         }
 672 
 673         JarFileEntry realEntry() {
 674             if (isMultiRelease() && versionFeature != BASE_VERSION_FEATURE) {
 675                 String entryName = super.getName();
 676                 return entryName == basename || entryName.equals(basename) ?
 677                         this : new JarFileEntry(entryName, this);
 678             }
 679             return this;
 680         }
 681 
 682         // changes the basename, returns "this"
 683         JarFileEntry withBasename(String name) {
 684             basename = name;
 685             return this;
 686         }
 687     }
 688 
 689     /*
 690      * Ensures that the JarVerifier has been created if one is
 691      * necessary (i.e., the jar appears to be signed.) This is done as
 692      * a quick check to avoid processing of the manifest for unsigned
 693      * jars.
 694      */


< prev index next >