diff --git a/deps.edn b/deps.edn index fa24a181..df8b3807 100644 --- a/deps.edn +++ b/deps.edn @@ -20,7 +20,7 @@ "impl-java/src"], :deps {org.clojure/clojure {:mvn/version "1.11.1"}, org.babashka/sci {:local/root "sci"} - org.babashka/babashka.impl.java {:mvn/version "0.1.6"} + org.babashka/babashka.impl.java {:mvn/version "0.1.8"} org.babashka/sci.impl.types {:mvn/version "0.0.2"} babashka/babashka.curl {:local/root "babashka.curl"} babashka/fs {:local/root "fs"} diff --git a/impl-java/build.clj b/impl-java/build.clj index 3d256312..b2688a9c 100644 --- a/impl-java/build.clj +++ b/impl-java/build.clj @@ -3,7 +3,7 @@ [clojure.tools.build.api :as b])) (def lib 'org.babashka/babashka.impl.java) -(def version "0.1.6") +(def version "0.1.8") (def class-dir "target/classes") (def basis (b/create-basis {:project "deps.edn"})) (def jar-file (format "target/%s-%s.jar" (name lib) version)) diff --git a/impl-java/src-java/babashka/impl/URLClassLoader.java b/impl-java/src-java/babashka/impl/URLClassLoader.java index d2cf476e..9416f2b9 100644 --- a/impl-java/src-java/babashka/impl/URLClassLoader.java +++ b/impl-java/src-java/babashka/impl/URLClassLoader.java @@ -1,6 +1,17 @@ +// This file is mostly a workaround for https://github.com/oracle/graal/issues/1956 + package babashka.impl; -public class URLClassLoader extends java.net.URLClassLoader { +import java.util.WeakHashMap; +import java.io.*; +import java.util.Objects; +import java.net.*; +import java.util.jar.*; + +public class URLClassLoader extends java.net.URLClassLoader implements Closeable { + + private WeakHashMap + closeables = new WeakHashMap<>(); public URLClassLoader(java.net.URL[] urls) { super(urls); @@ -13,4 +24,71 @@ public class URLClassLoader extends java.net.URLClassLoader { public void _addURL(java.net.URL url) { super.addURL(url); } + + // calling super.getResource() returned nil in native-image + public java.net.URL getResource(String name) { + return findResource(name); + } + + // calling super.getResourceAsStream() returned nil in native-image + public InputStream getResourceAsStream(String name) { + Objects.requireNonNull(name); + URL url = getResource(name); + try { + if (url == null) { + return null; + } + URLConnection urlc = url.openConnection(); + InputStream is = urlc.getInputStream(); + if (urlc instanceof JarURLConnection) { + JarFile jar = ((JarURLConnection)urlc).getJarFile(); + synchronized (closeables) { + if (!closeables.containsKey(jar)) { + closeables.put(jar, null); + } + } + } else { + synchronized (closeables) { + closeables.put(is, null); + } + } + return is; + } catch (IOException e) { + return null; + } + } + + public java.util.Enumeration getResources(String name) throws java.io.IOException { + return findResources(name); + } + + public void close() throws IOException { + super.close(); + + java.util.List errors = new java.util.ArrayList(); + + synchronized (closeables) { + java.util.Set keys = closeables.keySet(); + for (Closeable c : keys) { + try { + c.close(); + } catch (IOException ex) { + errors.add(ex); + } + } + closeables.clear(); + } + + if (errors.isEmpty()) { + return; + } + + IOException firstEx = errors.remove(0); + + for (IOException error: errors) { + firstEx.addSuppressed(error); + } + throw firstEx; + } + } diff --git a/project.clj b/project.clj index c4aa233f..e3c3672e 100644 --- a/project.clj +++ b/project.clj @@ -27,7 +27,7 @@ [nrepl/bencode "1.1.0"] [borkdude/sci.impl.reflector "0.0.1"] [org.babashka/sci.impl.types "0.0.2"] - [org.babashka/babashka.impl.java "0.1.6"] + [org.babashka/babashka.impl.java "0.1.8"] [org.clojure/core.async "1.6.673"] [org.clojure/test.check "1.1.1"] [com.github.clj-easy/graal-build-time "0.1.0"] diff --git a/resources/META-INF/babashka/deps.edn b/resources/META-INF/babashka/deps.edn index fa24a181..df8b3807 100644 --- a/resources/META-INF/babashka/deps.edn +++ b/resources/META-INF/babashka/deps.edn @@ -20,7 +20,7 @@ "impl-java/src"], :deps {org.clojure/clojure {:mvn/version "1.11.1"}, org.babashka/sci {:local/root "sci"} - org.babashka/babashka.impl.java {:mvn/version "0.1.6"} + org.babashka/babashka.impl.java {:mvn/version "0.1.8"} org.babashka/sci.impl.types {:mvn/version "0.0.2"} babashka/babashka.curl {:local/root "babashka.curl"} babashka/fs {:local/root "fs"} diff --git a/resources/UrlClassLoaderSubstitutions.java b/resources/UrlClassLoaderSubstitutions.java new file mode 100644 index 00000000..53bb1a32 --- /dev/null +++ b/resources/UrlClassLoaderSubstitutions.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.Closeable; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.net.URLClassLoader; +import java.security.AccessControlContext; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.WeakHashMap; + +import com.oracle.svm.core.annotate.Alias; +import com.oracle.svm.core.annotate.RecomputeFieldValue; +import com.oracle.svm.core.annotate.Substitute; +import com.oracle.svm.core.annotate.TargetClass; + +@TargetClass(URLClassLoader.class) +@SuppressWarnings({"unused", "static-method"}) +final class Target_java_net_URLClassLoader { + @Alias// + @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.NewInstance, declClass = WeakHashMap.class)// + private WeakHashMap closeables; + + @Substitute + public InputStream getResourceAsStream(String name) throws IOException { + System.out.println("getResource"); + return null; + // return Resources.createInputStream(name); + } +} diff --git a/script/compile b/script/compile index 17b7dc76..b92abeb3 100755 --- a/script/compile +++ b/script/compile @@ -26,17 +26,6 @@ fi export JAVA_HOME=$GRAALVM_HOME export PATH=$GRAALVM_HOME/bin:$PATH -rm -rf resources/*.class -# SVM_JAR=$(find -L "$GRAALVM_HOME" | grep svm.jar) -# "$GRAALVM_HOME/bin/javac" -cp "$SVM_JAR" resources/CutOffCoreServicesDependencies.java -# "$GRAALVM_HOME/bin/javac" -cp "$SVM_JAR" resources/CutOffSunAwtWwwContentAudioAiff.java -# "$GRAALVM_HOME/bin/javac" -cp "$SVM_JAR" resources/CutOffMisc.java -if [ -z "$BABASHKA_JAR" ]; then - lein with-profiles +reflection,+native-image "do" run - lein "do" clean, uberjar, metabom - BABASHKA_JAR=${BABASHKA_JAR:-"target/babashka-$BABASHKA_VERSION-standalone.jar"} -fi - # because script/test cleans target during ci before the jar can we saved cp target/metabom.jar . diff --git a/script/uberjar b/script/uberjar index f56cbc29..525a2d71 100755 --- a/script/uberjar +++ b/script/uberjar @@ -178,6 +178,12 @@ fi mkdir -p resources/META-INF/babashka cp deps.edn resources/META-INF/babashka/deps.edn +rm -rf resources/*.class +# SVM_JAR=$(find -L "$GRAALVM_HOME" | grep svm.jar) +# "$GRAALVM_HOME/bin/javac" -cp "$SVM_JAR" resources/UrlClassLoaderSubstitutions.java +# "$GRAALVM_HOME/bin/javac" -cp "$SVM_JAR" resources/CutOffSunAwtWwwContentAudioAiff.java +# "$GRAALVM_HOME/bin/javac" -cp "$SVM_JAR" resources/CutOffMisc.java + if [ -z "$BABASHKA_JAR" ]; then lein with-profiles "$BABASHKA_LEIN_PROFILES,+reflection,-uberjar" do run lein with-profiles "$BABASHKA_LEIN_PROFILES" do clean, uberjar, metabom diff --git a/test/babashka/classpath_test.clj b/test/babashka/classpath_test.clj index 3b4beeff..5c5daa0d 100644 --- a/test/babashka/classpath_test.clj +++ b/test/babashka/classpath_test.clj @@ -76,4 +76,9 @@ (tu/bb nil "--classpath" "test-resources/babashka/src_for_classpath_test/foo.jar" "(first (map str (.getURLs (clojure.lang.RT/baseLoader))))")] (is (str/includes? url "file:")) - (is (str/includes? url "foo.jar")))) + (is (str/includes? url "foo.jar"))) + (let [results (tu/bb nil "--classpath" "test-resources/babashka/src_for_classpath_test/foo.jar" + "(map some? [(.getResource (clojure.lang.RT/baseLoader) \"foo.clj\") + (.getResourceAsStream (clojure.lang.RT/baseLoader) \"foo.clj\") + (.getResources (clojure.lang.RT/baseLoader) \"foo.clj\")])")] + (is (= [true true true] (edn/read-string results)))))