Repository: GoogleContainerTools/jib
File: jib-cli/src/main/java/com/google/cloud/tools/jib/cli/jar/JarProcessors.java (Java)

Code before:
   * @param jarPath path to the jar
   * @return the jar type
   * @throws IOException if I/O error occurs when opening the file
   */
  private static String determineJarType(Path jarPath) throws IOException {
    try (JarFile jarFile = new JarFile(jarPath.toFile())) {
      if (jarFile.getEntry("BOOT-INF") != null) {
        return SPRING_BOOT;
      }
      return STANDARD;
    }
  }

  /**
   * Determines the java version of JAR. Derives the version from the first .class file it finds in
   * the JAR.
   *
   * @param jarPath path to the jar
   * @return java version
   * @throws IOException if I/O exception thrown when opening the jar file
   */
  @VisibleForTesting
  static Integer getJavaMajorVersion(Path jarPath) throws IOException {
    try (JarFile jarFile = new JarFile(jarPath.toFile())) {
      List<String> jarEntries =
          jarFile.stream().map(JarEntry::toString).collect(Collectors.toList());
      for (String jarEntry : jarEntries) {
        if (jarEntry.endsWith(".class") && !jarEntry.endsWith("module-info.class")) {
          URLClassLoader loader = new URLClassLoader(new URL[] {jarPath.toUri().toURL()});
          try (DataInputStream classFile =
              new DataInputStream(loader.getResourceAsStream(jarEntry))) {

            // Check magic number
            if (classFile.readInt() != 0xCAFEBABE) {
              throw new IOException("Invalid class file format.");
            }

            // Skip over minor version
            classFile.skipBytes(2);

            int majorVersion = classFile.readUnsignedShort();
            int javaVersion = (majorVersion - 45) + 1;
            return javaVersion;
          }
        }
      }
      return VERSION_NOT_FOUND;
    }
  }
}


Review comment (suggestion):
I realized that using .nextElement() results in a `NoSuchElementException` if there are no more elements - this would cause an issue if an empty jar was passed in.

Code after:
   * @throws IOException if I/O error occurs when opening the file
   */
  private static String determineJarType(Path jarPath) throws IOException {
    try (JarFile jarFile = new JarFile(jarPath.toFile())) {
      if (jarFile.getEntry("BOOT-INF") != null) {
        return SPRING_BOOT;
      }
      return STANDARD;
    }
  }

  /**
   * Determines the java version of JAR. Derives the version from the first .class file it finds in
   * the JAR.
   *
   * @param jarPath path to the jar
   * @return java version
   * @throws IOException if I/O exception thrown when opening the jar file
   */
  @VisibleForTesting
  static Integer getJavaMajorVersion(Path jarPath) throws IOException {
    try (JarFile jarFile = new JarFile(jarPath.toFile())) {
      Enumeration<JarEntry> jarEntries = jarFile.entries();
      while (jarEntries.hasMoreElements()) {
        String jarEntry = jarEntries.nextElement().toString();
        if (jarEntry.endsWith(".class") && !jarEntry.endsWith("module-info.class")) {
          URLClassLoader loader = new URLClassLoader(new URL[] {jarPath.toUri().toURL()});
          try (DataInputStream classFile =
              new DataInputStream(loader.getResourceAsStream(jarEntry))) {

            // Check magic number
            if (classFile.readInt() != 0xCAFEBABE) {
              throw new IOException("Invalid class file format.");
            }

            // Skip over minor version
            classFile.skipBytes(2);

            int majorVersion = classFile.readUnsignedShort();
            int javaVersion = (majorVersion - 45) + 1;
            return javaVersion;
          }
        }
      }
      return VERSION_NOT_FOUND;
    }
  }
}