diff --git a/src/main/java/com/uber/h3core/H3CoreLoader.java b/src/main/java/com/uber/h3core/H3CoreLoader.java index 9533e64..f8863c7 100644 --- a/src/main/java/com/uber/h3core/H3CoreLoader.java +++ b/src/main/java/com/uber/h3core/H3CoreLoader.java @@ -93,17 +93,36 @@ public static NativeMethods loadNatives() throws IOException { return loadNatives(os, arch); } - private static File createTempLibraryFile(OperatingSystem os) throws IOException { + static File createTempLibraryFile(OperatingSystem os) throws IOException { + // Check if the user specified a custom directory for native libraries + String customDir = System.getProperty("h3.native.dir"); + File dir = customDir != null ? new File(customDir) : null; + + // Ensure the custom directory exists + if (dir != null && !dir.exists()) { + dir.mkdirs(); + } + if (os.isPosix()) { // Note this is already done by the implementation of Files.createTempFile that I looked at, // but the javadoc does not seem to gaurantee the permissions will be restricted to owner // write. final FileAttribute> attr = PosixFilePermissions.asFileAttribute(PosixFilePermissions.fromString("rwx------")); - return Files.createTempFile("libh3-java", os.getSuffix(), attr).toFile(); + + if (dir != null) { + return Files.createTempFile(dir.toPath(), "libh3-java", os.getSuffix(), attr).toFile(); + } else { + return Files.createTempFile("libh3-java", os.getSuffix(), attr).toFile(); + } } else { // When not a POSIX OS, try to ensure the permissions are secure - final File f = Files.createTempFile("libh3-java", os.getSuffix()).toFile(); + final File f; + if (dir != null) { + f = Files.createTempFile(dir.toPath(), "libh3-java", os.getSuffix()).toFile(); + } else { + f = Files.createTempFile("libh3-java", os.getSuffix()).toFile(); + } f.setReadable(true, true); f.setWritable(true, true); f.setExecutable(true, true); diff --git a/src/test/java/com/uber/h3core/TestH3CoreLoader.java b/src/test/java/com/uber/h3core/TestH3CoreLoader.java index 34e4445..3864a57 100644 --- a/src/test/java/com/uber/h3core/TestH3CoreLoader.java +++ b/src/test/java/com/uber/h3core/TestH3CoreLoader.java @@ -68,4 +68,27 @@ void extractNonexistant() throws IOException { UnsatisfiedLinkError.class, () -> H3CoreLoader.copyResource("/nonexistant-resource", tempFile)); } + + @Test + void testCustomNativeDir() throws Exception { + String customDir = System.getProperty("java.io.tmpdir") + "/h3-custom-test-dir"; + System.setProperty("h3.native.dir", customDir); + + try { + H3CoreLoader.OperatingSystem currentOs = + H3CoreLoader.detectOs(System.getProperty("java.vendor"), System.getProperty("os.name")); + + // Call the package-private method directly! No reflection needed. + File tempFile = H3CoreLoader.createTempLibraryFile(currentOs); + + org.junit.jupiter.api.Assertions.assertTrue( + tempFile.getAbsolutePath().startsWith(new File(customDir).getAbsolutePath()), + "File should be created inside the custom directory"); + + tempFile.delete(); + new File(customDir).delete(); + } finally { + System.clearProperty("h3.native.dir"); + } + } }