Can I set java.library.path programmatically from java code itself?
The following doesn't work.
System.setProperty("java.library.path", "/blah");
Maybe this will help: Setting "java.library.path" programmatically
When messing around with JNI, one has to set the java.library.path accordingly.
Unfortunately the only way is to add a system property before the application is started:
java -Djava.library.path=/path/to/libs
Changing the system property later doesn’t have any effect, since the property is evaluated very early and cached. But the guys over at jdic discovered a way how to work around it. It is a little bit dirty – but hey, those hacks are the reason we all love Java…
System.setProperty( "java.library.path", "/path/to/libs" );
Field fieldSysPath = ClassLoader.class.getDeclaredField( "sys_paths" );
fieldSysPath.setAccessible( true );
fieldSysPath.set( null, null );
Explanation
At first the system property is updated with the new value. This might be a relative path – or maybe you want to create that path dynamically.
The Classloader has a static field (sys_paths) that contains the paths. If that field is set to null, it is initialized automatically. Therefore forcing that field to null will result into the reevaluation of the library path as soon as loadLibrary() is called…
No you can't. This property is a read only value. You can change it at JVM launchin time with:
-Djava.library.path=your_path
If you want to load a library from a specific location, you can use System.load(libraryPath) instead with the full path to the library.
I'm just quoting from the link provided by secmask (https://cedarsoft.com/blog.html), in case the link goes dead:
Changing the system property java.library.path later doesn’t have
any effect, since the property is evaluated very early and cached. But
the guys over at jdic discovered a way how to work around it. It is a
little bit dirty – but hey, those hacks are the reason we all love
Java.
System.setProperty("java.library.path", "/path/to/libs");
Field fieldSysPath = ClassLoader.class.getDeclaredField("sys_paths");
fieldSysPath.setAccessible(true);
fieldSysPath.set(null, null);
Explanation:
At first the system property is updated with the new value. This might be a relative path – or maybe you want to create that path dynamically. The Classloader has a static field (sys_paths) that contains the paths. If that field is set to null, it is initialized automatically.Therefore forcing that field to null will result into the reevaluation of the library path as soon as loadLibrary() is called.
Yes it will read the Environment Variables.
Following is the code for setting the Environment variable using the ini4j.
import java.io.IOException;
import org.ini4j.Reg;
public class SettingWinEnvironmentUsing_ini4j {
public static void main(String args[])
{
System.out.println("Setting System Environment Variables");
Reg reg = new Reg();
Reg.Key env = reg.add("HKEY_CURRENT_USER\\Environment");
env.put("RR_PROPERTY_PATH", "c:\\path");
try {
reg.write();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(env.get("RR_PROPERTY_PATH"));
}
}
You can find the ini4j jar at
http://cropforge.org/plugins/scmsvn/viewcvs.php/IAPlugin/lib/ini4j-0.5.2-SNAPSHOT.jar?rev=656&root=icisjavatools&view=log
import java.util.Map;
public class ReadingEnvironment {
public static void main(String[] args) {
System.out.println("Reading System Environment Variables:\n");
// System.out.println(System.getenv());
Map<String, String> env = System.getenv();
for (String envName : env.keySet()) {
System.out.format("%s=%s%n", envName, env.get(envName));
}
}
}
Related
Is there an existing Java solution to resolve file paths containing environment variables?
I need to convert this (simplified) method to handle the case where the provided path contains an environment variable (like %PROGRAMFILES(X86)%\SomeProgram\SomeFile.ini).
I know how to write code to extract the variable names, fetch their values and substitute them in the provided string but I can't help but feel I'm reinventing the wheel...
boolean isValidPath(String pathToValidate) {
File f = new File(pathToValidate);
if(f.exists()) {
return true;
}
return false;
}
Almost sure it does not exist in standard library simply because any environment variable is very specific in its usage. Some allow lists delimited by semicolons like PATH, some - only one single value. Also relying on values of env vars means that code becomes more platform-specific, and jre seems to avoid it at any reasonable cost.
There are already a couple of implementations of such substitutors on github, for example https://github.com/Haufe-Lexware/java-env-replacer.
You can actually get the environment variables details by calling System.getenv() and then you can write some logic (sample shown below) to achieve what you wanted:
public boolean isValidPath(String pathToValidate) {
String envValue = "";
for (String envName : env.keySet()) {
if(pathToValidate.contains(envName)) {
envValue= env.get(envName);
break;
}
}
//replace the envValue in pathToValidate
//Then check file exists or not & return true/false
}
steps I do:
I do in code
System.setProperty("myproperty", 1);
and then I set in a shell script the property "myProperty" to 3.
like this:
# setprop "myproperty" 3
and then in the code I try to read the property like this:
System.getProperty("myproperty");
I get the value of 1. which means that the set from the shell didn't actually work.
but when I print all props from shell with
# getprop
I see in the list that myproperty equals 3.
in shorter words: I want to change the value of a property from a script, and I see that this scripts actually changes the property but in the java code I get the old value.
any ideas?
Java code in Android provides System.getProperty and System.setProperty functions in java library but it's important to note that although these java APIs are semantically equal to native version, java version store data in a totally different place. Actually, a hashtable is employed by dalvik VM to store properties. So, java properties are separated, it can't get or set native properties, and neither vice versa.
You can use android.os.SystemProperties class can manipulate native properties, though it's intended for internal usage only. It calls through jni into native property library to get/set properties.
getprop/setprop work on android.os.SystemProperties, not on java.lang.System.
Unfortunately, this class is not available to third party application. Apparently you have rooted your device, so you may still access it.
You can use that snippet to run getProp as shell command and get the value of any property:
private String getSystemProperty(String propertyName) {
String propertyValue = "[UNKNOWN]";
try {
Process getPropProcess = Runtime.getRuntime().exec("getprop " + propertyName);
BufferedReader osRes =
new BufferedReader(new InputStreamReader(getPropProcess.getInputStream()));
propertyValue = osRes.readLine();
osRes.close();
} catch (Exception e) {
// Do nothing - can't get property value
}
return propertyValue;
}
I made a program in Java that uses two external databases. The paths to these databases are hard-coded inside my program code.
In order to make this program usable for other users on other computers (who should also install these two databases on their computers), I think that the path for these two databases should be added as environmental variables ? How could this be done ?
I am not a professional when it comes to environmental variables, so can you please advise what should be done in this case?
Thanks in advance
To get the value of an environment variable in Java, you write something like this:
String pathToDatabase = System.getenv().get("PATH_TO_DATABASE");
(where PATH_TO_DATABASE is the name of the environment variable). This uses System.getenv() to get a map of all environment variables.
To set the value of an environment variable in Linux, your users can write something like this:
export PATH_TO_DATABASE=/this/is/the/path/to/the/database
before running the program.
Environment vars are usually not be the best way to handle app config, but if you must, the specific OS docs are needed to learn how to set them and from Java use:
Map map = System.getenv();
Rather than environment variables, a properties file would be useful and more portable. For example, in your properties file you could have the following:
db.url = jdbc://foo/bar?whatever
db.user = username
db.password = password
Then your code could read that in using the follow:
Properties properties = new Properties();
try {
properties.load(new FileInputStream("path/filename"));
} catch (IOException e) {
System.err.println( "Eeeek!" );
}
System.out.println( properties.getProperty( "db.url" ) );
Handily, properties objects allow you to specify defaults, so you could still have the hardcoded values if you want and then override them with the external file.
Is it possible to initialize Java system properties using some sort of configuration file?
(ie: can you set java.library.path using a file inside your jar)
EDIT: Clarification: I am asking specifically about initializing the system properties to a value in a file, not setting them later from inside the virtual machine. Yes, you can change system properties to whatever you want very easily after the machine starts up, but the Java system classes will not use the new values.
Practically speaking, this means System.setProperty and System.setProperties are useless for loading native libraries, as JNI will always use the original value of java.library.path to load libraries with. I'm trying to figure out if there's a cleaner alternative to just putting -Djava.library.path=whatever in start up scripts everywhere.
There is a way to set java.library.path programatically, see this.
The code is a hack to set the sys_path field on the ClassLoader,
System.setProperty( "java.library.path", "/path/to/libs" );
Field fieldSysPath = ClassLoader.class.getDeclaredField( "sys_paths" );
fieldSysPath.setAccessible( true );
fieldSysPath.set( null, null );
It would be pretty simple to do yourself:
public static void main(String[] args) {
Properties p = new Properties();
p.load(...); // Load the properties from a file in your jar
for (String name : p.stringPropertyNames()) {
String value = p.getProperty(name);
System.setProperty(name, value);
}
}
Use JAVA_TOOL_OPTIONS environment variable. _JAVA_OPTIONS may also work, but it's not documented at all. The JAVA_TOOL_OPTIONS is weakly documented, but here are some links:
http://www.oracle.com/technetwork/java/javase/envvars-138887.html#gbmsy
https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/envvars002.html
https://bugs.openjdk.java.net/browse/JDK-4971166
An example of use:
set JAVA_TOOL_OPTIONS=-Dmy.property=sth
When launching JVM you should see a message:
Picked up JAVA_TOOL_OPTIONS: ...
You cannot initialize them as far as I know, but you can definitely override their values to anything you want, using any source you wish.
I think the reason why System.setProperty(key,value) is useless for java.library.path in your program is your application is started, you need set it before your program is running.
Check your native library, if the library have any dependency that not included in the java.library.path, System.load will fail, as if System.setProperty(key, value) does not work as expected.
You can parse properties file with additional code (another instance of JVM), redirect its output to var and use this variable as parameter to your java invocation. For example:
public class SystemPropertyLoader {
public static void main(String[] args) throws Exception {
String file = args[0];//TODO check args
Properties properties = new Properties();
InputStream is = new FileInputStream(file);
properties.load(is);
is.close();
StringBuilder builder = new StringBuilder();
for (Entry e : properties.entrySet()){
builder.append("-D");
builder.append(e.getKey());
builder.append('=');
builder.append(e.getValue());
builder.append(' ');
}
System.out.println(builder.toString());
}
}
and
#!/bin/ksh
properties_variable=$(java SystemPropertyLoader input.properties)
I am wrapping a shared library (written in C) with Java using JNA. The shared library is written internally, but that library uses functions from another external library, which again depends another external library. So the situation is something like this:
ext1 <- ext2 <- internal
I.e. the internal uses external library ext2 which again uses external library ext1. What I have tried is:
System.loadLibrary("ext1");
System.loadLibrary("ext2");
NativeLIbrary.loadLibrary("internal",xxx.class);
This approach fails with "UnresolvedException" when loading the library "ext2"; the linker complains about symbols which are indeed present in the library "ext1". So it semmes that the System.loadLibrary() function does not make the symbols from "ext1" globally available? When using the stdlib function dlopen() as:
handle = dlopen( lib_name , RTLD_GLOBAL );
All the symbols found in #lib_name will be available for symbol resolution in subsequent loads; I guess what I would like was something similar for the java variety System.loadLibrary()?
Regards - Joakim Hove
It's an old question, but I've found an acceptable solution, which should also be portable, and I thought I should post an answer. The solution is to use JNA's NativeLibrary#getInstance(), because on Linux this will pass RTLD_GLOBAL to dlopen() (and on Windows this is not needed).
Now, if you are using this library to implement a Java native method, you will also need to call System.load() (or Sysem.loadLibrary()) on the same library, after calling NativeLibrary#getInstance().
First, a link to a JNA bug: JNA-61
A comment in there says that basically one should load dependencies before the actual library to use from within JNA, not the standard Java way. I'll just copy-paste my code, it's a typical scenario:
String libPath =
"/path/to/my/lib:" + // My library file
"/usr/local/lib:" + // Libraries lept and tesseract
System.getProperty("java.library.path");
System.setProperty("jna.library.path", libPath);
NativeLibrary.getInstance("lept");
NativeLibrary.getInstance("tesseract");
OcrTesseractInterf ocrInstance = (OcrTesseractInterf)
Native.loadLibrary(OcrTesseractInterf.JNA_LIBRARY_NAME, OcrTesseractInterf.class);
I've written a small library to provide OCR capability to my Java app using Tesseract. Tesseract dependes on Leptonica, so to use my library, I need to load libraries lept and tesseract first. Loading the libraries with the standard means (System.load() and System.loadLibrary()) doesn't do the trick, neither does setting properties jna.library.path or java.library.path. Obviously, JNA likes to load libraries its own way.
This works for me in Linux, I guess if one sets the proper library path, this should work in other OSs as well.
There is yet another solution for that. You can dlopen directly inside JNI code, like this:
void loadLibrary() {
if(handle == NULL) {
handle = dlopen("libname.so", RTLD_LAZY | RTLD_GLOBAL);
if (!handle) {
fprintf(stderr, "%s\n", dlerror());
exit(EXIT_FAILURE);
}
}
}
...
...
loadLibrary();
This way, you will open library with RTLD_GLOBAL.
You can find detailed description here: http://www.owsiak.org/?p=3640
OK;
I have found an acceptable solution in the end, but not without significant amount of hoops. What I do is
Use the normal JNA mechanism to map the dlopen() function from the dynamic linking library (libdl.so).
Use the dlopen() function mapped in with JNA to load external libraries "ext1" and "ext2" with the option RTLD_GLOBAL set.
It actually seems to work :-)
As described at http://www.owsiak.org/?p=3640, an easy but crude solution on Linux is to use LD_PRELOAD.
If that's not acceptable, then I'd recommend the answer by Oo.oO: dlopen the library with RTLD_GLOBAL within JNI code.
Try this, add this function to your code. Call it before you load your dlls. For the parameter, use the location of your dlls.
public boolean addDllLocationToPath(String dllLocation)
{
try
{
System.setProperty("java.library.path", System.getProperty("java.library.path") + ";" + dllLocation);
Field fieldSysPath = ClassLoader.class.getDeclaredField("sys_paths");
fieldSysPath.setAccessible(true);
fieldSysPath.set(null, null);
}
catch (Exception e)
{
System.err.println("Could not modify path");
return false;
}
return true;
}
}
In order to fix your issue you can use this package: https://github.com/victor-paltz/global-load-library. It loads the libraries directly with the RTLD_GLOBAL flag.
Here is an example:
import com.globalload.LibraryLoaderJNI;
public class HelloWorldJNI {
static {
// Loaded with RTLD_GLOBAL flag
try {
LibraryLoaderJNI.loadLibrary("/path/to/my_native_lib_A");
} catch (UnsatisfiedLinkError e) {
System.Println("Couldn't load my_native_lib_A");
System.Println(e.getMessage());
e.printStackTrace();
}
// Not loaded with RTLD_GLOBAL flag
try {
System.load("/path/to/my_native_lib_B");
} catch (UnsatisfiedLinkError e) {
System.Println("Couldn't load my_native_lib_B");
System.Println(e.getMessage());
e.printStackTrace();
}
}
public static void main(String[] args) {
new HelloWorldJNI().sayHello();
}
private native void sayHello();
}
It is using the same dlopen() trick as the previous answers, but it is packaged in a standalone code.