Get full command line from Java [duplicate] - java

This question already has answers here:
Determining location of JVM executable during runtime
(5 answers)
Closed 10 months ago.
The community reviewed whether to reopen this question 27 days ago and left it closed:
Original close reason(s) were not resolved
How can I from within Java code find out which and how the running JVM was launched?
My code shall spawn another Java process hence I'd be especially interested in the first parameter - which usually (in C, Pascal, Bash, Python, ...) points to the currently running executable.
So when a Java application is run like
d:\openjdk\bin\java -Xmx500g -Dprop=name -jar my.jar param1 param2
I can access command line parameters in my main method like
public class Main {
public static void main(String[] args) {
System.out.println("main called with " + args);
}
}
but that will deliver access to param1 and param2 only. How would I get the full command line?

Following Determining location of JVM executable during runtime I found the real answer to be:
ProcessHandle.current().info().commandLine().orElseThrow();
It returns the full command line as perceived by the operating system and thus contains all information: executable, options, main class, arguments, ...
Thank you, #XtremeBaumer

To get the command, use ProcessHandle adapted from your answer:
String command = ProcessHandle
.current()
.info()
.command()
.orElse("<unable to determine command>"); // .orElseThrow() to get Exception
Use the Runtime Management Bean RuntimeMXBean to obtain the VM arguments and the class path, like in:
RuntimeMXBean mxBean = ManagementFactory.getRuntimeMXBean();
String classPath = mxBean.getClassPath();
List<String> inputArgs = mxBean.getInputArguments();
This will return all arguments passed to the virtual machine, not the parameters passed to the main method.
The code source can be get from the ProtectionDomain of the class.

Related

Beginner: Can't run this program eventhough it is the solution [duplicate]

This question already has answers here:
Java ArrayIndexOutOfBound
(4 answers)
Closed 4 years ago.
public class Exercise10 {
public static void main(String[] args) {
System.out.println("args[0] = " + args[0]);
System.out.println("args[1] = " + args[1]);
System.out.println("args[2] = " + args[2]);
}
}
The error message I get is: Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0
The "args" String array argument to main() is populated by the command-line arguments you give to your program when you run it. Since you presumably haven't given it any, looking up the 0th one is quite reasonably an ArrayIndexOutOfBoundsException.
If you are invoking this with java on the command line, try $ java Exercise10 arg0 arg1 arg2
If you are invoking it from an IDE, you'll need to figure out how that IDE supports passing command line arguments. For example, in Eclipse, I believe there should be an Arguments tab in the Run dialog.
"Arg" as said in the names equals to Arguments, You haven't passed any Argument to your program hence it raises the error ArrayIndexOutOfBound, You can pass Arguments to your program by executing it as a jar in command prompt java -jar myJar.jar a b c

JAVA program accepting Devanagari(UTF8) charaters [duplicate]

This question already has answers here:
Passing command line unicode argument to Java code
(7 answers)
Closed 5 years ago.
What settings are needed so that Java class main method can accept Marathi/Devanagarai/UTF-8 characters.
e.g.
public static void main(String[] args) {
System.out.println(args[0]);
System.out.println("भारत");
}
In eclipse Java run arguments if I specify argument as "abc" it prints
abc
भारत
But If I specify Marathi/Devanagarai/UTF-8 string e.g. "कौशिक" then it prints
?????
भारत
What extra settings to be done in eclipse ?
Later I want to excute this program from jar using command and call it from PHP
e.g.
java -cp xyz.jar DevanagariTest कौशिक
What extra parameters will be needed at that time ?
I think it has something to do with your default system encoding. You can try to start the Java Programm with an additional Argument:
-Dfile.encoding=UTF-8

Making a jar that accepts names and values on command line

Relevant Links:
Java: Passing combination of named and unnamed parameters to executable Jar/Main Method
Passing arguments to JAR which is required by Java Interpreter
I understand how to pass strings from the command line to execute my main method:
java -jar myApp.jar "argument1"
My question is: is it possible to set up my main method in a way that would accept:
java -jar myApp.jar -parameter1 "argument1"
Here is my simple main method for context if you need it
public class myApp {
public static void main (String[] args){
System.out.println("Argument1: "+args[0]);
}
}
Thing is: whatever you pass on the command line goes into that args array. To be precise:
java xxx -jar JAR yyy
xxx: would be arguments to the JVM itself, like -Dprop:value for properties
yyy: are passed as arguments to your main method
So, when you pass "-parameter 'argument1'" then ... that is what you will see inside main!
In other words: the idea that some command line strings are "arguments"; and other are "-switches", or "--flags", or "-h" shortcuts ... you simply have to write the code to do all of that.
Luckily, there are plenty of libraries out there that help with that; see enter link description here

Finding Main Class in "Hello World" program in Java [duplicate]

This question already has answers here:
How to execute a java .class from the command line
(7 answers)
Closed 6 years ago.
I have a seemingly simple program in Java, but when I run it, I get the error:
Error: Could not find or load main class
Here is my code.
public class HelloPrinter
{
public static void main(String[] args)
{
System.out.println("Hello, World!");
}
}
I'm entirely new to the Java language, and I don't know what else to do. My program file is named "hello_world.java", and when attempting to run the program, I type in "java hello_world.java". Am I doing something fundamentally wrong? I've also attempted "java -cp hello_world", but that gave me the same error.
What am I doing wrong?
From what little information you've given, I'd say you're executing it the wrong way.
Make sure you run the following two commands:
javac HelloPrinter.java
java HelloPrinter
The first command compiles your source code into a .class file. The second command executes that class file.

Is *this* really the best way to start a second JVM from Java code?

This is a followup to my own previous question and I'm kind of embarassed to ask this... But anyway: how would you start a second JVM from a standalone Java program in a system-independent way? And without relying on for instance an env variable like JAVA_HOME as that might point to a different JRE than the one that is currently running. I came up with the following code which actually works but feels just a little awkward:
public static void startSecondJVM() throws Exception {
String separator = System.getProperty("file.separator");
String classpath = System.getProperty("java.class.path");
String path = System.getProperty("java.home")
+ separator + "bin" + separator + "java";
ProcessBuilder processBuilder =
new ProcessBuilder(path, "-cp",
classpath,
AnotherClassWithMainMethod.class.getName());
Process process = processBuilder.start();
process.waitFor();
}
Also, the currently running JVM might have been started with some other parameters (-D, -X..., ...) that the second JVM would not know about.
I think that the answer is "Yes". This probably as good as you can do in Java using system independent code. But be aware that even this is only relatively system independent. For example, in some systems:
the JAVA_HOME variable may not have been set,
the command name used to launch a JVM might be different (e.g. if it is not a Sun JVM), or
the command line options might be different (e.g. if it is not a Sun JVM).
If I was aiming for maximum portability in launching a (second) JVM, I think I would do it using wrapper scripts.
It's not clear to me that you would always want to use exactly the same parameters, classpath or whatever (especially -X kind of stuff - for example, why would the child need the same heap settings as its parents) when starting a secondary process.
I would prefer to use an external configuration of some sort to define these properties for the children. It's a bit more work, but I think in the end you will need the flexibility.
To see the extent of possible configuration settings you might look at thye "Run Configurations" settings in Eclipse. Quite a few tabs worth of configuration there.
To find the java executable that your code is currently running under (i.e. the 'path' variable in your question's sample code) there is a utility method within apache ant that can help you. You don't have to build your code with ant - just use it as a library, for this one method.
It is:
org.apache.tools.ant.util.JavaEnvUtils.getJreExecutable("java")
It takes care of the sort of special cases with different JVM vendors that others have mentioned. (And looking at the source code for it, there are more special cases than I would have imagined.)
It's in ant.jar. ant is distributed under the Apache license so hopefully you can use it how you want without hassle.
Here's a way that determines the java executable which runs the current JVM using ProcessHandle.current().info().command().
The ProcessHandle API also should allow to get the arguments. This code uses them for the new JVM if available, only replacing the current class name with another sample class. (Finding the current main class inside the arguments gets harder if you don't know its name, but in this demo it's simply "this" class. And maybe you want to reuse the same JVM options or some of them, but not the program arguments.)
However, for me (openjdk version 11.0.2, Windows 10), the ProcessInfo.arguments() is empty, so the fallback else path gets executed.
package test;
import java.lang.ProcessBuilder.Redirect;
import java.lang.management.ManagementFactory;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class TestStartJvm {
public static void main(String[] args) throws Exception {
ProcessHandle.Info currentProcessInfo = ProcessHandle.current().info();
List<String> newProcessCommandLine = new LinkedList<>();
newProcessCommandLine.add(currentProcessInfo.command().get());
Optional<String[]> currentProcessArgs = currentProcessInfo.arguments();
if (currentProcessArgs.isPresent()) { // I know about orElse, but sometimes isPresent + get is handy
for (String arg: currentProcessArgs.get()) {
newProcessCommandLine.add(TestStartJvm.class.getName().equals(arg) ? TargetMain.class.getName() : arg);
}
} else {
System.err.println("don't know all process arguments, falling back to passed args array");
newProcessCommandLine.add("-classpath");
newProcessCommandLine.add(ManagementFactory.getRuntimeMXBean().getClassPath());
newProcessCommandLine.add(TargetMain.class.getName());
newProcessCommandLine.addAll(List.of(args));
}
ProcessBuilder newProcessBuilder = new ProcessBuilder(newProcessCommandLine).redirectOutput(Redirect.INHERIT)
.redirectError(Redirect.INHERIT);
Process newProcess = newProcessBuilder.start();
System.out.format("%s: process %s started%n", TestStartJvm.class.getName(), newProcessBuilder.command());
System.out.format("process exited with status %s%n", newProcess.waitFor());
}
static class TargetMain {
public static void main(String[] args) {
System.out.format("in %s: PID %s, args: %s%n", TargetMain.class.getName(), ProcessHandle.current().pid(),
Stream.of(args).collect(Collectors.joining(", ")));
}
}
}
Before ProcessHandle was added in Java 9, I did something like this to query the current JVM's command-line:
Let the user pass or configure a "PID to command-line" command template; under Windows, this could be wmic process where 'processid=%s' get commandline /format:list.
Determine PID using java.lang.management.ManagementFactory.getRuntimeMXBean().getPid().
Expand command template; execute; parse its output.

Categories