I am trying to start a Java-process using Go but am unable to get Java to recognise the classpath. The code looks somewhat like:
args := []string{
"-Xmx64m",
"-Dmy.property=value,
"-cp",
"lib/jar1.jar:lib/jar2.jar",
"com.things.MyClass",
}
c := exec.Command(javaBinary, args...)
Unfortunately when executing this I get the dreaded Error: Could not find or load main class from the JVM. However if I take the output from c.Args and run it directly in a terminal it seems to work just fine, which to me indicates that I am somehow launching the process incorrectly.
Is there a better way of doing this?
Disregard this question please, the error was an extra space in the args array:
args := []string{
"-Xmx64m",
"-Dmy.property=value ", //<--trailing space
...
}
The extra space stops further parsing from continuing leading to a missing classpath.
Related
I have a variable toPath (contains path like C:/Program Files(x86)/bla).
This variable I pass as agrument: '[-operation update -contents ' + toPath + ']'
But because I have a space in this variable I get IllegalArgumentException.
How can I fix this?
I'm not sure but it looks like you are trying to do a typical newcomer mistake.
If you are trying to run a command that is build from multiple variables you can be vulnerable to injection attacks. To prevent this, use the subprocess module and hand in all parameters as a list. The module will take care of all the stuff to make it work with spaces as well.
For example ls -l should be run as:
subprocess.call(["ls", "-l"])
Your example caontains [] and might be rather different but without it would be:
subprocess.call(['-operation','update', '-contents', toPath])
Please note that there are other functions than call() (which returns the return code only) in the subprocess module.
Pass argument in double quotes.
toPath = "\"C:/Program Files(x86)/bla\"";
try
'[-operation update -contents "' + toPath + '"]'
I am working with a Java program that calls an external batch file and passes in an array of commands. I have a loop in the batch file that looks like this:
set paramCount=0
for %%x in (%*) do (
set /A paramCount+=1
set list[!paramCount!]=%%x
)
The parameters are a bunch of directories, stored as strings, like this:
String[] commands = {"cmd.exe",
"/C",
"C:\Users\user\Documents",
"C:\Users\user\Pictures",
"C:\Users\user\Videos"}
As you can see, my for loop is supposed to loop through the list of the arguments passed to the batch file (%*) and emulate an array within the script (Since the first two elements in the command array are used to start the command process, that only leaves the directories to be looped through). The program was working just fine until the other day, when I suddenly started getting an error saying the following:
Environment variable list[ not defined
I had not made any changes to the batch file at all and it seemed to stop working for no reason. In case it's necessary information, I'm using a process builder to run the process:
ProcessBuilder pb = new ProcessBuilder(commands);
Process p = pb.start();
Supposedly using this syntax for an array in a batch file is okay, so I'm not sure why it doesn't accept it. I appreciate any help you can provide in this matter. I've run into a lot of roadblocks with this program, and while I've been able to solve 90% of them, the remaining 10% have begun to drive me crazy! Thanks!
EDIT:
I have re-written the loop and added in some echo commands to make debugging easier. When I run the batch file, though, nothing prints to the screen as a result of the echo but I still get the same error:
#echo off
setlocal enableDelayedExpansion
set paramCount=0
for %%x in (%*) do (
echo !paramCount!
echo %%x
set list[!paramCount!]=%%x
set /A paramCount=paramCount+1
)
I also forgot to mention that the program works fine when I run the Java from Eclipse; it calls the batch files correctly and all works as expected. I don't get the error until I export the project to a runnable JAR and try running that.
EDIT 2:
After going through my batch file code again (I wrote it a while ago), I found only one line that looks like it might cause this problem. The odd thing is that I used an almost identical code example I found somewhere else to model it, and it worked for a long time without ever giving the error. It's a loop, designed to loop through the elements of the list "array" created in the first loop:
for /F "tokens=2 delims==" %%d in ('set list[') do (
set /A paramCount+=1
set _dir=%%d
set _dir=!_dir:"=!
if NOT "%%d"=="nul" set "dirs[!paramCount!]=!_dir!"
)
As you can see, the first line has a segment that says set list[, which looks odd to me. However, as I mentioned, it worked fine for quite a while.
The code you posted cannot give that error message. There must be some other code in your script that causes that error.
Only a SET statement without an = could give that error. After parsing and expansion, the offending statement must look like one of the following:
set list[
set "list[
set "list["
Actually, you could get that error in the presence of an = if there are quotes that are misplaced. For example, the following will give that error because all text after the last " is ignored:
set "list["1]=value
The 1]=value appears after the last " and is ignored, leaving set "list[".
You might consider enabling ECHO so that you can pinpoint exactly where the error message is occurring. Then you need to figure out what conditions could lead to the error at that point.
Update in response to "Edit 2:" in question
That IN() clause in the newly posted code is almost assuredly the point where the error message is generated. It indicates that the list "array" is not defined when the FOR /F loop is executed. The question is, why not? Things to look for:
Is something preventing the earlier FOR loop that defines the list "array" from running?
Are you sure the parameters are getting passed properly to the script? If there are no parameters, then there will not be an array.
Is something undefining the array before the 2nd FOR loop has a chance to execute?
I suggest you put in some diagnostic ECHO statements to help debug. For example, ECHO BEFORE 1ST LOOP immediately before the loop that defines the array to make sure the loop is being reached. Or ECHO ARGS = %* at the beginning of the script to make sure the parameters are getting passed properly. Happy sleuthing :-)
I tried the code bellow and it worked for me when calling from command line.
#echo off
setlocal enabledelayedexpansion
set paramCount=0
for %%x in (%*) do (
set /A paramCount=!paramCount!+1
set list[!paramCount!]=%%x
)
echo !list[1]!
echo !list[2]!
echo !list[3]!
I mentioned it in the comments but I figured I'd post an answer, for anyone else who's wondering:
As previously mentioned, the program was running fine in Eclipse, the batch files were being called and ran as expected. However, prior to making some changes to the batch files, I had created .exe's from them, and apparently was running the .exe's instad of the .bat's. It was a very stupid mistake on my part, and the problem was caused by some errors in the previous version of the batch file. If I remember correctly, that error was because the "array element" was empty. So I ended up doing a check to make sure it wasn't empty before operating on it. The following is the code i am currently using, and it works as expected:
#echo off
setlocal ENABLEDELAYEDEXPANSION
set /A paramCount=-3
for %%x in (%*) do (
set list[!paramCount!]=%%x
set /A paramCount=paramCount+1
)
set argA=%list[-3]%
set argB=%list[-2]%
set argC=%list[-1]%
for /F "tokens=2 delims==" %%a in ('set list[-') do SET "%%a="
set list[-3]=""
set list[-2]=""
set list[-1]=""
set paramCount=0
for /F "tokens=2 delims==" %%d in ('set list[') do (
if not "%%d"=="" (
set _dir=%%d
set _dir=!_dir:"=!
if NOT "%%d"=="nul" set "dirs[!paramCount!]=!_dir!"
)
set /A paramCount+=1 )
Thanks for all the answers, folks!
I would like to know if it is possible to get from code the command used to launch a java program.
E.g. if I launch a java program with:
java -cp lib1:lib2:... -jar mylib.jar com.foo.Bar
I would like to get the exact string (jvm parameters included).
Is it possible?
Comment on the bounty and the question
Thank you all for your responses. Unfortunately, I did not get the answer I was initally looking for. I was hoping there was some portable solution to get the complete java command from within the program itself (including classpath etc.). As it seems there are no portable solution and since I am using Linux I am using the responses of agodinhost and Luigi R. Viggiano to solve my problem. However I give the bounty to rahulroc for the most complete (portable) response. For the rest an upvote for all :)
The below mentioned code should show all JVM parameters, arguments passed to the main method as well as the main class name.
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.util.List;
public static void main(String[] args) {
RuntimeMXBean bean = ManagementFactory.getRuntimeMXBean();
List<String> jvmArgs = bean.getInputArguments();
for (int i = 0; i < jvmArgs.size(); i++) {
System.out.println( jvmArgs.get( i ) );
}
System.out.println(" -classpath " + System.getProperty("java.class.path"));
// print the non-JVM command line arguments
// print name of the main class with its arguments, like org.ClassName param1 param2
System.out.println(" " + System.getProperty("sun.java.command"));
}
javadoc for getInputArguments
Returns the input arguments passed to the Java virtual machine which
does not include the arguments to the main method. This method returns
an empty list if there is no input argument to the Java virtual
machine.
Some Java virtual machine implementations may take input arguments
from multiple different sources: for examples, arguments passed from
the application that launches the Java virtual machine such as the
'java' command, environment variables, configuration files, etc.
Typically, not all command-line options to the 'java' command are
passed to the Java virtual machine. Thus, the returned input arguments
may not include all command-line options.
You can also take a look at : jps
It's a Java program that is able to get the full command line for all
Java processes, including full class name of main class and JVM
options.
You can find a good summary of various JVM tools, including
Java Application Launcher links to :
ManagementFactory.getRuntimeMXBean() - Returns the managed bean for the runtime system of the Java virtual machine.
getInputArguments() javadoc
determine if JVM is running in debug mode
You can use this to retrieve the VM parameters :
public static void main(String args[]) {
List<String> inputArguments = ManagementFactory.getRuntimeMXBean().getInputArguments();
System.out.println("input arguments = " + inputArguments);
}
However it won't give you all the command line (only gives the JVM arguments, no main class nor parameters). Sample output:
input arguments = [-Dfile.encoding=UTF-8, -XX:-UseTLAB, -Xms2000m, -Xmx2000m, -XX:+PrintCompilation, -XX:+PrintGC]
It only works on Sun Oracle JVM: System.getProperty("sun.java.command")
Additionally, you can have a look at JavaSysMon, it can report command line of active processes. To check which is the current JVM Process check here: How can a Java program get its own process ID?
in a linux machine would be easier to run:
ps -ef | grep java
this command will list all java programs running with it's used parameters.
Not sure about what can be used in a windows environment.
In the task manager on Win2003 you can enable the display of a column that displays the command like it does on linux. Or, you can do it from the command line like so:
wmic.exe PROCESS where "name like '%java%'" get Processid,Caption,Commandline
I know that I can get the command-line arguments in the "main" method, but I need to be able to get them indirectly.
Thanks for your help.
Following expression is exactly what you want:
System.getProperty("sun.java.command")
You can list the threads, find the main thread, and crawl down the stack trace until you find the call to main, and pull out the args.
update a comment points out that this won't work all by itself, and I think the comment is correct. I misremembered the capabilities of stack introspection or mentally mixed in JVMTI.
So, here's plan B. Connect to yourself with JMX. The VM Summary MBean has the args.
Connection name:
pid: 77090 com.basistech.jdd.JDDLauncher -config src/main/config/benson-laptop-config.xml
All this having been said, what you should do is call System.getProperty and live with the need to use -D to pass parameters from the outside world down into your cave.
You could write a wrapper to take the cli and re-format it to use -DPROP=VAL
int main(int argc, char*argv[])
{
std::vector<std::string> in (argv+1,argv+argc), out();
out.push_back("java.exe");
out.push_back("-cp");
out.push_back("my-jar.jar");
out.push_back("main.class")
for( auto it = in.begin(); it!=in.end(); ++in)
{
//process CLI args. turn "-abc","BLAH" into "-Darg.a=true","-Darg.b=true","-Darg.c=BLAH" and push to out
//Do additional processing. Maybe evn use get_opt() or Boost.ProgramOptions
}
//use exec or CreateProcess to launch java with the proper args
//or even use something like WinRun4J's methods to load the jvm.dll
//Then your program shows up as "MyExe.exe" instead of "java.exe"
//Use System.getProperty("arg.a","false") to get the value of a
}
Of course, you could always just tell you users to invoke a bash/batch script with the proper -DA=true type arguments
I've been trying to use Matlab's javabuilder package under Windows XP, but I'm getting a strange error when trying to instantiate any javabuilder class. To illustrate the problem, I've created a simple program that prints the MCRROOT and PATH system variables (to check if they're correctly set) and tries to create a MWCharArray:
import com.mathworks.toolbox.javabuilder.*;
import com.mathworks.toolbox.javabuilder.internal.MCRConfiguration;
class Main
{
public static void main(String[] args)
{
System.out.println("MCRROOT: " + System.getenv("MCRROOT"));
System.out.println("PATH: " + System.getenv("PATH"));
System.out.println(MCRConfiguration.isInstalledMCR());
MWCharArray test = new MWCharArray("Test");
}
}
When I execute the program, the output is:
MCRROOT: C:\Program files\MATLAB\MATLAB Compiler Runtime\v710
PATH: C:\Program files\CollabNet Subversion Client;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\Program files\MATLAB\MATLAB Compiler Runtime\v710
false
Exception in thread "main" java.lang.ExceptionInInitializerError
at com.mathworks.toolbox.javabuilder.internal.MCRConfiguration.getMCRRoot(MCRConfiguration.java:77)
at com.mathworks.toolbox.javabuilder.internal.MCRConfiguration$ModuleDir.<clinit>(MCRConfiguration.java:51)
at com.mathworks.toolbox.javabuilder.internal.MCRConfiguration.getModuleDir(MCRConfiguration.java:56)
at com.mathworks.toolbox.javabuilder.internal.MWMCR.<clinit>(MWMCR.java:1447)
at com.mathworks.toolbox.javabuilder.MWUtil.GetUnknownClassID(MWUtil.java:1258)
at com.mathworks.toolbox.javabuilder.MWClassID.<clinit>(MWClassID.java:41)
at com.mathworks.toolbox.javabuilder.MWCharArray.<init>(MWCharArray.java:75)
at Main.main(Main.java:11)
Caused by: java.lang.StringIndexOutOfBoundsException: String index out of range: -1
at java.lang.String.substring(String.java:1937)
at com.mathworks.toolbox.javabuilder.internal.MCRConfiguration$MCRRoot.get(MCRConfiguration.java:70)
at com.mathworks.toolbox.javabuilder.internal.MCRConfiguration$MCRRoot.<clinit>(MCRConfiguration.java:72)
... 8 more
Java Result: 1
First of all, are MCRROOT's and PATH's values correct? I've tried google for finding out how to set MCRROOT, but there are conflicting results: some sources say that I should include de version dir, others say the opposite. Also, why is the isInstalledMCR method returning false? I've double-checked the MCR installation (and even uninstalled and installed it to be sure), so why isn't the library finding it?
Thanks on advance for any help!
Edit: I've also tried setting MCRROOT with no version string, and it also fails.
Just wild guessing! Java is messing around with strings, while your 'mcrroot' contains white spaces. I might change the mcr install path to something like C:\MATLAB\MATLABCompilerRuntime\v710, omitting any white spaces and special characters.
I've found the solution, so I'm post a self answer for future reference: Besides adding the javabuilder.jar to the program's classpath, you also have to add the path to the MCR's runtime libraries to the java.library.path JDK parameter.
My mistake was that, instead of setting the path as the path to the libraries at the MCR installation directory (On my case, C:\MATLAB\MCR\v710\runtime\win32), I copied the runtime directory to my project's dir and used it instead. It seems that the javabuilder library uses the java.library.path variable the guess the MCROOT, what would explain the weird "StringIndexOutOfBoundsException".