The "Path of the running EXE" is well defined for Windows Applications written in C#, C++, VB, etc.
-
Java Applications on Windows are not "EXE-Applications" but a class-file or a jar-file is started rather than an EXE-file.
So for java Applications the term "ExePath" should be translated to "MainClassPath" or to "JarPath" resp.
-
In some cases a programmer needs to know the physical Path of the Application's jar or MainClass.
(e.g. when you develop a large project both in java and in c# with identical classes and identical methods)
-
thanks to other stackoverflow users this statement does the job:
String exePath = URLDecoder.decode(this.getClass().getProtectionDomain().getCodeSource().getLocation().getPath(), "UTF-8")
and now comes my question:
If I put the same code into any helper/utils jar-library then it will return the path of the helperlib.jar, it will NOT return the path of my MainClass/AppJar !
-
So the final getExePath() helper method should look something like:
return(URLDecoder.decode(Thread.currentThread().getStartingThread().getMainClass().getProtectionDomain().getCodeSource().getLocation().getPath(), "UTF-8"));
(if there only were methods like getStartingThread() and getMainClass() in java ...)
-
please, point me to the final solution, how can I implement these steps:
get the starting Thread
get the Main Class of the starting Thread
get the Path of the Main Class
if I get you right, just put the method with a parameter of the desired class into your helperlib-class ...
e.g.:
public static String getExePath(Object main) {
String path = "";
try {
path = URLDecoder.decode(main.getClass().getProtectionDomain().getCodeSource().getLocation().getPath(), "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return path;
}
then you can call it e.g. from inside your main-jar with the parameter 'this' ...
System.out.println("AppPath:\n" + helperlib.getExePath(this));
... and you got the path of the class specified in you parameter
hope it helps and sorry for my bad english ... ;)
Related
I'm having a problem with loading printer dll. I have a dll file from the printer manufacturer (JniPrinterStatusLib.dll). I wrote code like printer manufacturer suggested. The code is:
package com.printer.test
public class JniPrinterStatus {
static{
System.loadLibrary("JniPrinterStatusLib");
}
public native int GetStatus(String printer);
}
package com.printer.test
public class TestSample {
public static void main(String[] args) {
int status;
String printer = "MY PRINTER";
JniPrinterStatus jps = new JniPrinterStatus();
System.out.println("PRINTER NAME = " + printer);
status = jps.GetStatus(printer);
if (status == -1) {
System.out.println("status = -1");
}
else if (status == 0) {
System.out.println("status = NORMAL");
}
else if ((status & 0x00000080) != 0) {
System.out.println("status = PRINTER_STATUS_OFFLINE");
}
else if ((status & 0x00400000) != 0) {
System.out.println("status = PRINTER_STATUS_DOOR_OPEN");
}
else if ((status & 0x00000010) != 0) {
System.out.println("status = PRINTER_STATUS_PAPER_OUT");
}
else if ((status & 0x00000800) != 0) {
System.out.println("status = PRINTER_STATUS_OUTPUT_BIN_FULL");
}
else if ((status & 0x00000040) != 0) {
System.out.println("status = PRINTER_STATUS_PAPER_PROBLEM");
}
}
}
I used Eclipse to run the code, i put the dll library in the folder project and the error is
PRINTER NAME = MY PRINTER
Exception in thread "main" java.lang.UnsatisfiedLinkError: com.printer.test.JniPrinterStatus.GetStatus(Ljava/lang/String;)I
at com.printer.test.JniPrinterStatus.GetStatus(Native Method)
at com.printer.test.TestSample.main(TestSample.java:10)
If i move the source from the package "com.printer.test" to default package the code works and show:
PRINTER NAME = MY PRINTER
status = -1
I don't know how it's possible. If i compile and run the code from command prompt without package it works.
Where is the problem?
Thank you
From the javadoc for class UnsatisfiedLinkError...
Thrown if the Java Virtual Machine cannot find an appropriate
native-language definition of a method declared native.
That means that function Java_com_printer_test_JniPrinterStatus_GetStatus is not found.
Method loadLibrary in class java.lang.System usually searches the directories listed in the [System] property "java.library.path". For Windows machines, the value of this property is generally the value of the PATH environment variable.
So I suggest printing out the value of that property in your code to see whether it includes the directory containing your DLL. If it doesn't then you need to fix that, either by relocating the DLL or changing the PATH environment variable or launching your java program with the -Djava.library.path=... option. After that you need to check the signature of the native method. Dependency Walker is a tool I use at my work to accomplish this.
EDIT
Having re-read your question, I feel I did not accurately address your question, so let me add...
The default behaviour of Eclipse is to copy resource files, like DLLs, to the output folder. So if you put your DLL in folder src\com\printer\test, it will get copie to folder bin\com\printer\test. My guess is that the current, working directory, i.e. . is in your "java.library.path" which is why it works when your java code is in the default package.
Sorry, actually I wanted to write a comment, but as I'm still low on reputation, I have to try and guess an answer.
There should be no need to recompile the dll - it's just some native code to be invoked.
The java package of the class loading the dll should not make a difference, either.
You have to take care about your system architecture: A 64-bit dll file will fail in a 32-bit JRE and vice versa. Make sure, your JRE architecture matches the dll architecture.
Another thing to take into account is your working directory. Eclipse may use a working directory different from what you used when you ran you program from console.
Last but not least, please have a look at your java.library.path variable.
This page might also help: https://www.chilkatsoft.com/java-loadLibrary-Windows.asp
I covers all the details.
The expected package of the Java classes is hard-coded in the JNI library. In your case, it's the default package.
Let me expand on that. When one implements a native method in a JNI library, one has to create a public C function with a name in the following format:
Java_com_mypackage_MyClass_MyMethod
In other words, the JNI library can't provide methods for the classes in arbitrary packages - only for classes in packages that the JNI library authors had in mind.
In your case, it's the default one. The C function goes Java_JniPrinterStatus_GetStatus. If you call your class MyPrinterStatus, or place it into package com.foobar, the JNI run-time won't be able to associate the C function with the declared Java native method. That's just how JNI was designed.
I got a little project where I have to compute a list. The computation depends on serveal factors.
The point is that these factors change from time to time and the user should be allowed to change this by it's self.
Up to now, the factors are hard-coded and no changes can be done without recompiling the code.
At the moment the code looks like this:
if (someStatement.equals("someString")) {
computedList.remove("something");
}
My idea is to make an editable and human readable textfile, configfile, etc. which is loaded at runtime/ at startup? This file should hold the java code from above.
Any ideas how to do that? Please note: The targeted PCs do not have the JDK installed, only an JRE.
An effective way of going about this is using a static initializer. Static Block in Java A good and concise explanation can be found under this link.
One option here that would allow this would be to use User Input Dialogs from the swing API - then you could store the users answer's in variables and export them to a text file/config file, or just use them right in the program without saving them. You would just have the input dialogs pop up at the very beginning of the program before anything else happens, and then the program would run based off those responses.
You could use Javascript for the configuration file language, instead of java. Java 7 SE and later includes a javascript interpreter that you can call from Java. it's not difficult to use, and you can inject java objects into the javascript environment.
Basically, you'd create a Javascript environment, insert the java objects into it which the config file is expected to configure, and then run the config file as javascript.
Okay, here we go... I found an quite simple solution for my problem.
I am using Janino by Codehaus (Link). This library has an integrated Java compiler and seems to work like the JavaCompiler class in Java 7.
BUT without having the JDK to be installed.
Through Janino you can load and compile *.java files(which are human readable) at runtime, which was exactly what I needed.
I think the examples and code-snippets on their homepage are just painful, so here's my own implementation:
Step one is to implement an interface with the same methods your Java file has which is loaded at runtime:
public interface ZuordnungInterface {
public ArrayList<String> Zuordnung(ArrayList<String> rawList);}
Then you call the Janino classloader when you need the class:
File janinoSourceDir = new File(PATH_TO_JAVAFILE);
File[] srcDir = new File[] { janinoSourceDir };
String encoding = null;
ClassLoader parentClassLoader = this.getClass().getClassLoader();
ClassLoader cl = new JavaSourceClassLoader(parentClassLoader, srcDir,
encoding);
And create an new instance
ZuordnungsInterface myZuordnung = (ZuordnungInterface) cl.loadClass("zuordnung")
.newInstance();
Note: The class which is loaded is named zuordnung.java, so there is no extension needed in the call cl.loadClass("zuordnung").
And finaly the class I want to load and compile at runtime of my program, which can be located wherever you want it to be (PATH_TO_JAVAFILE):
public class zuordnung implements ZuordnungInterface {
public ArrayList<String> Zuordnung(ArrayList<String> rawList){
ArrayList<String> computedList = (ArrayList<String>) rawList.clone();
if (Model.getSomeString().equals("Some other string")) {
computedList.add("Yeah, I loaded an external Java class");
}
return computedList;
}}
That's it. Hope it helps others with similar problems!
I want to create a GUI app in java for signing j2me app which is done by JadTool.jar but it is a Command Line Interface Apps. So I just want to use it as library and pass the parameters in program. How it can be done?
Check out Runtime. It will allow you to execute a command. You can use this to start your command line interface library.
Edit:
Ah, I didn't read care carefully earlier. If you're using a Java library starting a separate process is not the best solution.
Just reference the JadTool jar from your project. If the functionality you need isn't accessible in the library, edit the source and recompile. Make sure JadTool's license allows this.
If you're against editing the source (or not allowed) try using reflection to invoke the private run method you need.
A jar is just a library of classes, the fact that it can be run from the command line is caused by the presence of a main method in a class. As jadtool's source is available it's easy to see its very simple main:
public static void main(String[] args) {
int exitStatus = -1;
try {
new JadTool().run(args);
exitStatus = 0;
} catch (Exception e) {
System.err.println("\n" + e.getMessage() + "\n");
}
System.exit(exitStatus);
}
Unfortunately, that run() method is private, so calling it directly from another class won't work, leading to a reduced set of options:
#WilliamMorrison 's solution of going via Runtime - not really a library call, but it would work.
see Any way to Invoke a private method?
Is there a way in using externally stored sourcecode and loading it into a Java programm, so that it can be used by it?
I would like to have a program that can be altered without editing the complete source code and that this is even possible without compiling this every time. Another advantage is, that I can change parts of the code like I want.
Of course I have to have interfaces so that it is possible to send data into this and getting it back into the fixed source program again.
And of course it should be faster than a pure interpreting system.
So is there a way in doing this like an additional compiling of these external source code parts and a start of the programm after this is done?
Thank you in advance, Andreas :)
You need the javax.tools API for this. Thus, you need to have at least the JDK installed to get it to work (and let your IDE point to it instead of the JRE). Here's a basic kickoff example (without proper exception and encoding handling just to make the basic example less opaque, cough):
public static void main(String... args) throws Exception {
String source = "public class Test { static { System.out.println(\"test\"); } }";
File root = new File("/test");
File sourceFile = new File(root, "Test.java");
Writer writer = new FileWriter(sourceFile);
writer.write(source);
writer.close();
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
compiler.run(null, null, null, sourceFile.getPath());
URLClassLoader classLoader = URLClassLoader.newInstance(new URL[] { root.toURI().toURL() });
Class<?> cls = Class.forName("Test", true, classLoader);
}
This should print test in stdout, as done by the static initializer in the test source code. Further use would be more easy if those classes implements a certain interface which is already in the classpath. Otherwise you need to involve the Reflection API to access and invoke the methods/fields.
In Java 6 or later, you can get access to the compiler through the javax.tools package. ToolProvider.getSystemJavaCompiler() will get you a javax.tools.JavaCompiler, which you can configure to compile your source. If you are using earlier versions of Java, you can still get at it through the internal com.sun.tools.javac.Main interface, although it's a lot less flexible.
Java6 has a scripting API. I've used it with Javascript, but I believe you can have it compile external Java code as well.
http://java.sun.com/developer/technicalArticles/J2SE/Desktop/scripting/
Edit: Here is a more relevant link:
"Dynamic source" code in Java applications
I want to launch a java subprocess, with the same java classpath and dynamically loaded classes as the current java process. The following is not enough, because it doesn't include any dynamically loaded classes:
String classpath = System.getProperty("java.class.path");
Currently I'm searching for each needed class with the code below. However, on some machines this fails for some classes/libs, the source variable is null. Is there a more reliable and simpler way to get the location of libs that are used by the current jvm process?
String stax = ClassFinder.classPath("javax.xml.stream.Location");
public static String classPath(String qualifiedClassName) throws NotFoundException {
try {
Class qc = Class.forName( qualifiedClassName );
CodeSource source = qc.getProtectionDomain().getCodeSource();
if ( source != null ) {
URL location = source.getLocation();
String f = location.getPath();
f = URLDecoder.decode(f, "UTF-8"); // decode URL to avoid spaces being replaced by %20
return f.substring(1);
} else {
throw new ClassFinder().new NotFoundException(qualifiedClassName+" (unknown source, likely rt.jar)");
}
} catch ( Exception e ) {
throw new ClassFinder().new NotFoundException(qualifiedClassName);
}
}
See my previous question which covers getting the classpath as well as how to launch a sub-process.
I want to launch a java subprocess, with the same java classpath and dynamically loaded classes as the current java process.
You mean invoke a new JVM?
Given that...
it is possible to plug in all sorts of agents and instrumentation into a JVM that can transform classes at load time
it is possible to take a byte array and turn it into a class
it is possible to have complex class loader hierarchies with varying visibility between classes and have the same classes loaded multiple times
...there is no general, magic, catch-all and foolproof way to do this. You should design your application and its class loading mechanisms to achieve this goal. If you allow 3rd party plug-ins, you'll have to document how this works and how they have to register their libraries.
If you look at the javadoc for Class.getClassLoader, you'll see that the "bootstrap" classloader is typically represented as the null. "String.class.getClassLoader()" will return null on the normal sun jvm implementations. i think this implementation detail carries over into the CodeSource stuff. As such, I wouldn't imagine you would need to worry about any class which comes from the bootstrap classloader as long as your sub-process uses the same jvm impl as the current process.