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

Code before:
          CliLogger.newLogger(
              commonCliOptions.getVerbosity(),
              commonCliOptions.getConsoleOutput(),
              spec.commandLine().getOut(),
              spec.commandLine().getErr(),
              executor);

      if (!Files.exists(jarFile)) {
        logger.log(LogEvent.Level.ERROR, "The file path provided does not exist: " + jarFile);
        return 1;
      }
      if (Files.isDirectory(jarFile)) {
        logger.log(
            LogEvent.Level.ERROR,
            "The file path provided is for a directory. Please provide a path to a JAR: "
                + jarFile);
        return 1;
      }
      if (!entrypoint.isEmpty() && !jvmFlags.isEmpty()) {
        logger.log(LogEvent.Level.WARN, "--jvm-flags is ignored when --entrypoint is specified");
      }

      CacheDirectories cacheDirectories =
          CacheDirectories.from(commonCliOptions, jarFile.toAbsolutePath().getParent());
      JarProcessor processor = JarProcessors.from(jarFile, cacheDirectories, mode);
      Integer jarJavaVersion = JarProcessors.getJavaMajorVersion(jarFile);
      JibContainerBuilder containerBuilder =
          JarFiles.toJibContainerBuilder(processor, this, commonCliOptions, logger, jarJavaVersion);
      Containerizer containerizer = Containerizers.from(commonCliOptions, logger, cacheDirectories);
      containerBuilder.containerize(containerizer);
    } catch (Exception ex) {
      if (commonCliOptions.isStacktrace()) {
        ex.printStackTrace();
      }
      System.err.println(ex.getClass().getName() + ": " + ex.getMessage());
      return 1;
    } finally {
      executor.shutDownAndAwaitTermination(Duration.ofSeconds(3));
    }
    return 0;
  }

  /**
   * Returns the user-specified base image.
   *
   * @return an optional base image
   */
  public Optional<String> getFrom() {
    return Optional.ofNullable(from);
  }


Review comment (performance):
Instead of making `getJavaMajorVersion()` public and calling it twice (although I have no idea if there will be noticeable performance impact when "opening a jar" twice with `new JarFile()` in this case), how about adding a field `JarProcessor.javaVersion` and a getter for it? (Maybe the current `getJavaMajorVersion()` should be renamed to, say, `{read|determine}JavaMajorVersion` if we do so.) That way, we can avoid running the code twice. I see `JarProcessor` is already passed into `toJibContainerBuilder()`, so it just needs to call the getter.

Code after:
          CliLogger.newLogger(
              commonCliOptions.getVerbosity(),
              commonCliOptions.getConsoleOutput(),
              spec.commandLine().getOut(),
              spec.commandLine().getErr(),
              executor);

      if (!Files.exists(jarFile)) {
        logger.log(LogEvent.Level.ERROR, "The file path provided does not exist: " + jarFile);
        return 1;
      }
      if (Files.isDirectory(jarFile)) {
        logger.log(
            LogEvent.Level.ERROR,
            "The file path provided is for a directory. Please provide a path to a JAR: "
                + jarFile);
        return 1;
      }
      if (!entrypoint.isEmpty() && !jvmFlags.isEmpty()) {
        logger.log(LogEvent.Level.WARN, "--jvm-flags is ignored when --entrypoint is specified");
      }

      CacheDirectories cacheDirectories =
          CacheDirectories.from(commonCliOptions, jarFile.toAbsolutePath().getParent());
      JarProcessor processor = JarProcessors.from(jarFile, cacheDirectories, mode);
      JibContainerBuilder containerBuilder =
          JarFiles.toJibContainerBuilder(processor, this, commonCliOptions, logger);
      Containerizer containerizer = Containerizers.from(commonCliOptions, logger, cacheDirectories);
      containerBuilder.containerize(containerizer);
    } catch (Exception ex) {
      if (commonCliOptions.isStacktrace()) {
        ex.printStackTrace();
      }
      System.err.println(ex.getClass().getName() + ": " + ex.getMessage());
      return 1;
    } finally {
      executor.shutDownAndAwaitTermination(Duration.ofSeconds(3));
    }
    return 0;
  }

  /**
   * Returns the user-specified base image.
   *
   * @return an optional base image
   */
  public Optional<String> getFrom() {
    return Optional.ofNullable(from);
  }

  public List<String> getJvmFlags() {