class OpearFile implements Opear {

    static Result<File> cacheJar(final @NotNull JarFile jarFile, final @NotNull File cacheDir) {
        return jarFile.stream()
                .map(entry -> {
                    final File cacheFile = new File(cacheDir, entry.getName());
                    if (entry.isDirectory()) {
                        if (cacheFile.isDirectory() || cacheFile.mkdirs()) {
                            return Result.success(cacheFile);
                        }
                    } else {
                        if (cacheFile.getParentFile().isDirectory() || cacheFile.getParentFile().mkdirs()) {
                            try (InputStream input = jarFile.getInputStream(entry)) {
                                FileIOUtils.copyInputStreamToFile(input, cacheFile);
                                return Result.success(cacheFile);
                            } catch (IOException e) {
                                return Result.<File>failure("failed to cache entry " + entry.getName(), e);
                            }
                        }
                    }
                    return Result.<File>failure("failed to cache entry " + entry.getName());
                })
                .filter(Result::isFailure).findFirst()
                .map(failed -> failed.getError().map(Result::<File>failure)
                        .orElseGet(() -> Result.<File>failure("failed to cache jarFile" + jarFile.getName())))
                .orElse(Result.success(cacheDir));
    }

      OpearFile(final File cacheDir, final OpearMetadata metadata);

}