Skip to content

Commit

Permalink
Fix loading issues with GraalVM Native Image
Browse files Browse the repository at this point in the history
  • Loading branch information
saudet committed Jun 20, 2020
1 parent 3a2adba commit e2b39ad
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 47 deletions.
11 changes: 7 additions & 4 deletions src/main/java/org/bytedeco/javacpp/ClassProperties.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import java.util.Map;
import java.util.Properties;
import org.bytedeco.javacpp.annotation.Platform;
import org.bytedeco.javacpp.tools.Logger;

/**
* Does the heavy lifting of collecting values off Properties annotations found
Expand All @@ -41,6 +42,8 @@
* @see Loader#loadProperties(Class, java.util.Properties, boolean)
*/
public class ClassProperties extends HashMap<String,List<String>> {
private static final Logger logger = Logger.create(ClassProperties.class);

public ClassProperties() { }
public ClassProperties(Properties properties) {
platform = properties.getProperty("platform");
Expand Down Expand Up @@ -313,12 +316,12 @@ public void load(Class cls, boolean inherit) {
setProperty("platform.executable", executable);
setProperty("platform.library", library);

try {
if (LoadEnabled.class.isAssignableFrom(c)) {
if (LoadEnabled.class.isAssignableFrom(c)) {
try {
((LoadEnabled)c.newInstance()).init(this);
} catch (ClassCastException | InstantiationException | IllegalAccessException e) {
logger.warn("Could not create an instance of " + c + ": " + e);
}
} catch (ClassCastException | InstantiationException | IllegalAccessException e) {
// fail silently as if the interface wasn't implemented
}

// need platform information from both classProperties and classPlatform to be considered "loaded"
Expand Down
35 changes: 27 additions & 8 deletions src/main/java/org/bytedeco/javacpp/Loader.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.HttpURLConnection;
Expand Down Expand Up @@ -462,14 +463,17 @@ public static File cacheResource(URL resourceURL) throws IOException {
public static File cacheResource(URL resourceURL, String target) throws IOException {
// Find appropriate subdirectory in cache for the resource ...
File urlFile;
String[] splitURL = resourceURL.toString().split("#");
try {
urlFile = new File(new URI(resourceURL.toString().split("#")[0]));
// ... remove fragment since some subclasses of URLConnection don't like it ...
resourceURL = new URL(splitURL[0]);
urlFile = new File(new URI(splitURL[0]));
} catch (IllegalArgumentException | URISyntaxException e) {
urlFile = new File(resourceURL.getPath());
}
String name = urlFile.getName();
boolean reference = false;
long size, timestamp;
long size = 0, timestamp = 0;
File cacheDir = getCacheDir();
File cacheSubdir = cacheDir.getCanonicalFile();
String s = System.getProperty("org.bytedeco.javacpp.cachedir.nosubdir", "false").toLowerCase();
Expand Down Expand Up @@ -518,15 +522,20 @@ public static File cacheResource(URL resourceURL, String target) throws IOExcept
cacheSubdir = new File(cacheSubdir, urlFile.getParentFile().getName());
}
} else {
size = urlFile.length();
timestamp = urlFile.lastModified();
if (urlFile.exists()) {
size = urlFile.length();
timestamp = urlFile.lastModified();
} else if (urlConnection != null) {
size = urlConnection.getContentLengthLong();
timestamp = urlConnection.getLastModified();
}
if (!noSubdir) {
cacheSubdir = new File(cacheSubdir, urlFile.getParentFile().getName());
}
}
if (resourceURL.getRef() != null) {
if (splitURL.length > 1 && splitURL[1] != null && splitURL[1].length() > 0) {
// ... get the URL fragment to let users rename library files ...
String newName = resourceURL.getRef();
String newName = splitURL[1];
// ... but create a symbolic link only if the name does not change ...
reference = newName.equals(name);
name = newName;
Expand Down Expand Up @@ -1420,12 +1429,17 @@ public static URL[] findLibrary(Class cls, ClassProperties properties, String li
if (u != null) {
if (reference) {
u = new URL(u + "#" + styles2[i]);
if (!u.toString().contains("#")) {
Field f = URL.class.getDeclaredField("ref");
f.setAccessible(true);
f.set(u, styles2[i]);
}
}
if (!urls.contains(u)) {
urls.add(u);
}
}
} catch (IOException e) {
} catch (IOException | NoSuchFieldException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
Expand All @@ -1441,11 +1455,16 @@ public static URL[] findLibrary(Class cls, ClassProperties properties, String li
URL u = file.toURI().toURL();
if (reference) {
u = new URL(u + "#" + styles2[i]);
if (!u.toString().contains("#")) {
Field f = URL.class.getDeclaredField("ref");
f.setAccessible(true);
f.set(u, styles2[i]);
}
}
if (!urls.contains(u)) {
urls.add(k++, u);
}
} catch (IOException ex) {
} catch (IOException | NoSuchFieldException | IllegalAccessException ex) {
throw new RuntimeException(ex);
}
}
Expand Down
8 changes: 4 additions & 4 deletions src/main/java/org/bytedeco/javacpp/tools/Builder.java
Original file line number Diff line number Diff line change
Expand Up @@ -1085,12 +1085,12 @@ public File[] build() throws IOException, InterruptedException, ParserException
// Do not inherit properties when parsing because it generates annotations itself
ClassProperties p = Loader.loadProperties(c, properties, false);
if (p.isLoaded()) {
try {
if (Arrays.asList(c.getInterfaces()).contains(BuildEnabled.class)) {
if (Arrays.asList(c.getInterfaces()).contains(BuildEnabled.class)) {
try {
((BuildEnabled)c.newInstance()).init(logger, properties, encoding);
} catch (ClassCastException | InstantiationException | IllegalAccessException e) {
logger.warn("Could not create an instance of " + c + ": " + e);
}
} catch (ClassCastException | InstantiationException | IllegalAccessException e) {
// fail silently as if the interface wasn't implemented
}
String target = p.getProperty("global");
if (target != null && !c.getName().equals(target)) {
Expand Down
72 changes: 41 additions & 31 deletions src/main/java/org/bytedeco/javacpp/tools/Generator.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
import org.bytedeco.javacpp.FloatPointer;
import org.bytedeco.javacpp.FunctionPointer;
import org.bytedeco.javacpp.IntPointer;
import org.bytedeco.javacpp.LoadEnabled;
import org.bytedeco.javacpp.Loader;
import org.bytedeco.javacpp.LongPointer;
import org.bytedeco.javacpp.Pointer;
Expand Down Expand Up @@ -1733,42 +1734,51 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver
out2.println("#endif");
}

for (PrintWriter o : new PrintWriter[] {jniConfigOut, reflectConfigOut}) {
allClasses.addAll(jclasses.keySet());
allClasses.addAll(jclasses.keySet());

LinkedHashSet<Class> reflectClasses = new LinkedHashSet<Class>();
reflectClasses.addAll(baseClasses);
reflectClasses.add(Object.class);
reflectClasses.add(Buffer.class);
reflectClasses.add(String.class);
LinkedHashSet<Class> reflectClasses = new LinkedHashSet<Class>();
reflectClasses.addAll(baseClasses);
reflectClasses.add(Object.class);
reflectClasses.add(Buffer.class);
reflectClasses.add(String.class);

if (o != null) {
o.println("[");
String separator = "";
for (Class cls : allClasses) {
do {
o.println(separator + " {");
o.print(" \"name\" : \"" + cls.getName() + "\"");
if (reflectClasses.contains(cls) || reflectClasses.contains(cls.getEnclosingClass())) {
o.println(",");
o.println(" \"allDeclaredConstructors\" : true,");
o.println(" \"allPublicConstructors\" : true,");
o.println(" \"allDeclaredMethods\" : true,");
o.println(" \"allPublicMethods\" : true,");
o.println(" \"allDeclaredFields\" : true,");
o.println(" \"allPublicFields\" : true,");
o.println(" \"allDeclaredClasses\" : true,");
o.print(" \"allPublicClasses\" : true");
}
o.println();
o.print(" }");
separator = "," + System.lineSeparator();
cls = cls.getEnclosingClass();
} while (cls != null);
for (Class cls : new LinkedHashSet<Class>(allClasses)) {
while ((cls = cls.getEnclosingClass()) != null) {
allClasses.add(cls);
}
}

for (PrintWriter o : new PrintWriter[] {jniConfigOut, reflectConfigOut}) {
if (o == null) {
continue;
}
o.println("[");
String separator = "";
for (Class cls : allClasses) {
o.println(separator + " {");
o.print(" \"name\" : \"" + cls.getName() + "\"");
if (reflectClasses.contains(cls) || reflectClasses.contains(cls.getEnclosingClass())) {
o.println(",");
o.println(" \"allDeclaredConstructors\" : true,");
o.println(" \"allPublicConstructors\" : true,");
o.println(" \"allDeclaredMethods\" : true,");
o.println(" \"allPublicMethods\" : true,");
o.println(" \"allDeclaredFields\" : true,");
o.println(" \"allPublicFields\" : true,");
o.println(" \"allDeclaredClasses\" : true,");
o.print(" \"allPublicClasses\" : true");
} else if (LoadEnabled.class.isAssignableFrom(cls)) {
o.println(",");
o.println(" \"allDeclaredConstructors\" : true,");
o.print(" \"allPublicConstructors\" : true");
}
o.println();
o.println("]");
o.print(" }");
separator = "," + System.lineSeparator();
cls = cls.getEnclosingClass();
}
o.println();
o.println("]");
}

return supportedPlatform;
Expand Down

0 comments on commit e2b39ad

Please sign in to comment.