Is there a way to store code as variables in java? - java

In Java, is there a way to store, edit, convert, print, access, evaluate and compare blocks of code (possibly user entered), while also being able to execute them?
An example for where this would be useful is if someone codes an software that is designed to teach people how to code, where the user would input code to the system, and the program would check if the user developed code is
I'm looking for something like this:
CodeBlock line20And21 = `String x = "hello"; System.out.println(x);`; // stores a block of code
line20And21.replace("ln",""); //edits the block of code
System.out.println(line20And21.toString()); // converts/prints the block of code
CodeBlock usersCode = Scanner.nextCodeBlock(); // accesses block of code
if(! line20And21.wouldThrowError()); // evaluates block of code
if(line20And21.wouldDoTheSameThingAs(line18And19)) // compares blocks of code
line20And21.execute(); // executes the block of code
The code I would be using is of course much more complicated than just defining a String and printing it, but I'm sure the idea would be the same.
I really appriciate any help with this. Thanks!

Since Java 9, Java includes a shell to evaluate snippets, called JShell. JShell is programatically available via jdk.shell.
First you have to create an instance of the JShell via JShell js = JShell.create().
Evaluating a String as Java code (a so called code Snippet) is done via js.eval("System.out.println(/"Hello World/")");, which returns a list of SnippetEvents you can inspect to find out what effect the execution of the code snippet had.
Since the code is stored as a String, you can edit it as you would edit any String.
Here is an example of JShell taking user inputted code and storing/evaluating it, taken from the official java docs, where code is read as string from stdin and executed:
import java.io.ByteArrayInputStream;
import java.io.Console;
import java.util.List;
import jdk.jshell.*;
import jdk.jshell.Snippet.Status;
class ExampleJShell {
public static void main(String[] args) {
Console console = System.console();
try (JShell js = JShell.create()) {
do {
System.out.print("Enter some Java code: ");
String input = console.readLine();
if (input == null) {
break;
}
List<SnippetEvent> events = js.eval(input);
for (SnippetEvent e : events) {
StringBuilder sb = new StringBuilder();
if (e.causeSnippet == null) {
// We have a snippet creation event
switch (e.status) {
case VALID:
sb.append("Successful ");
break;
case RECOVERABLE_DEFINED:
sb.append("With unresolved references ");
break;
case RECOVERABLE_NOT_DEFINED:
sb.append("Possibly reparable, failed ");
break;
case REJECTED:
sb.append("Failed ");
break;
}
if (e.previousStatus == Status.NONEXISTENT) {
sb.append("addition");
} else {
sb.append("modification");
}
sb.append(" of ");
sb.append(e.snippet.source());
System.out.println(sb);
if (e.value != null) {
System.out.printf("Value is: %s\n", e.value);
}
System.out.flush();
}
}
} while (true);
}
System.out.println("\nGoodbye");
}
}

You can do things like this with BeanShell, a Java interpreter written in Java:
import bsh.Interpreter;
class Test {
public static void main(String[] args) throws Exception {
String code = "String x = \"hello\"; System.out.println(x);";
String newCode = code.replace("ln", "");
System.out.println("Here's the result of running: " +newCode);
Interpreter p = new Interpreter();
p.eval(newCode);
}
}
If compiled and built with the right dependencies, you can evaluate the snippet:
$ javac -cp bsh-2.0b4.jar:. Test.java && java -cp bsh-2.0b4.jar:. Test
Here's the result of running: String x = "hello"; System.out.print(x);
hello$
You can run the code and get its output or return values, or whether it throws an exception. Sandboxing and comparing the output of two snippets is up to you.

Mostly: No.
Java code goes through a compilation step, code needs to be in methods (which need to be in types), and the reasons for this take quite a while to explain. The compiler does not need to be there at runtime (and often isn't).
So, if you really want to do this:
Code has to be 'complete', including a package statement, a class declaration, a method, etc.
You need to ship the compiler with the app. For javac, that's tricky (GPL); you could ship ecj (eclipse's compiler) which is MIT licensed. It's quite a dep.
You can then 'store' code as strings.
ecj can then turn this into bytecode for you, but you'll have quite a time managing the classpath properly to make this code compile correctly.
You can then dynamically load this bytecode by using a classloader which has a learning curve of a few days all by itself.
In addition, looking at code without executing it to determine if it would throw an exception or not is literally impossible - this is called the halting problem. There exists proof that it is unsolvable. You can't go faster than light. You can't determine from arbitrary code written in a 'turing complete' language (and java is turing complete) if it halts or not (or in this case, if it throws or not).
Similar rules apply to 'would this do the same thing as'.

Related

How to Use Command Line Arguments to Dictate Flow of Program?

I have scoured all of Google it seems and I cannot find anything regarding how to use command line arguments to tell the Java program which subsequent method to perform. I am trying to create a Java program with several different aspects of a student grading application.
The main program is a GUI form where the user can input grades for each student in a specific class. Along with this, I need a control program that accepts 3 command arguments. The first is a number to indicate the type of file to load (1. XML 2. JSON 3. TXT). The second is a letter to indicate the file material (C indicates Course data, S indicates Student data). The last argument is the name of the specific data file to upload, which will then be extracted and uploaded to a database to be used by the GUI program.
I have the rest of the program already coded except for the command arguments because I have absolutely no idea what I am doing. The command argument code is supposed to look something like this:
public class Load
{
//Define global variables
static String inputDataChoice;
static String inputTableChoice;
static String inputFileName;
public static void main(String[] arg)
{
if (userChose == arg[0], arg[3], arg[5])
{
//If user chose 1 (XML), S (Student), and xmltest.xml
//Go to ParseXMLStudentFile();
}
if (userChose == arg[1], arg[4], arg[6])
{
//If user chose 2 (JSON), C (Course), and jsontest.json
//Go to ParseJSONCourseFile();
}
if (userChose == arg[2], arg[3], arg[7])
{
//If user chose 3 (TXT), S (Student), and test.txt
//Go to ParseTXTStudentFile();
}
}
}
I know that the above code is bogus, but that is the general idea. How do I accept command arguments from the user and then use that input to decide which method is executed? Would this program use the console window to accept user input? Please help!
arg contains the parameters passed to the command line, i.e. if you call the prog with prog.jar XML S xmltest.xml:
String fileType = arg[0]; // == XML
String material = arg[1]; // == S
String fileName = arg[2]; // == xmltest.xml
if (fileType.equals("XML") && material.equals("S")) {
parseXMLStudentFile(fileName);
} else { // ...
}

Java - algorithm to find executable lines of code

I wrote a java program which scans and finds Executable lines of codes (ELOC), blank lines of codes(BLOC) and comments (CLOC) for only java and c++ codes. Following is my code:
if(extension.contains("java") || extension.contains("c++"))
{
Scanner input = new Scanner(fileObject);
while(input.hasNext())
{
String s = input.nextLine();
if(s.length()==0)
{
bloc++;
}
else if(s.contains("/*") || s.startsWith("/*"))
{
cloc++;
while(!s.contains("*/"))
{
cloc++;
s = input.nextLine();
}
}
else if(s.contains("//"))
{
cloc++;
}
else
{
eloc++;
}
}//while
System.out.println("ELOC: "+(eloc));
System.out.println("Blank Lines: "+bloc);
System.out.println("Comment Lines: "+cloc);
}
I ran different java and c++ source codes but it does not always give the correct answer. What Can I do to make it better? Is there any java code online that I can use?
For this question, I'm only counting the executable lines of codes. If a line looks like following:
int x=0;//some comment
then the line above should be counted as one executable line. Following is my updated code:
String extension=getExtension(fileObject.getName());
if(extension.contains("java") || extension.contains("c++"))
{
Scanner input = new Scanner(fileObject);
String s;
while(input.hasNext())
{
s = input.nextLine().trim();
eloc++;
if(s.equals(""))
{
bloc++;
}
if(s.startsWith("//"))
{
cloc++;
}
if(s.contains("/*") && !s.contains("*\\"))
{
cloc++;
while(!s.contains("*/"))
{
cloc++;
eloc++;
s = input.nextLine();
}
}
else if(s.contains("/*") && s.contains("*\\"))
{
cloc++;
}
}
System.out.println("Total number of lines: "+eloc);
System.out.println("ELOC: "+(eloc-(cloc+bloc)));
System.out.println("Blank Lines: "+bloc);
System.out.println("Comment Lines: "+cloc);
}
Any comment/advice will be appreciated..Thanks!
On a Unix system you could simply use cloc. This gives you the following output:
src$ cloc .
51 text files.
51 unique files.
285 files ignored.
http://cloc.sourceforge.net v 1.53 T=0.5 s (82.0 files/s, 5854.0 lines/s)
-------------------------------------------------------------------------------
Language files blank comment code
-------------------------------------------------------------------------------
Java 39 618 119 2145
XML 2 8 0 37
-------------------------------------------------------------------------------
SUM: 41 626 119 2182
-------------------------------------------------------------------------------
Code lines do not contain comments or blanks, but do include something like block brackets or import statements using cloc for Java.
There are other tools available, but this is the most simple if you just need to count the code lines. Hope this helps.
Blank lines might not have a length of zero. Their content might contain whitespace, at least mine do. Try trimming it before checking length to get a more accurate count.
The only thing else I can say is that your numbers will be off if you have lines that contain code and comments. It looks like the code you have now will consider an entire line a comment if it even partially contains a comment. For example:
Validate(input); // This validates user input
This will not be counted as ELOC but as CLOC. This may not be a problem if the coding style is more like this:
// Validate user input
Validate(input);
But not every developer will use the second way. I personally use a mix of both depending on context.
Example which does not produce expected counts:
int a;
a = 7; // comment, yeah
int b /* my favorite variable */ = 3;
executeMethod(dataField,
moreData,excitingBoolean,resultSetFromMyGrandma,
anotherParameterTakingAnotherWholeLine);
Your program is not handling comments or multi-line statements very gracefully.
Edit
I would suggest parsing it fully into a tree, recognizing comments and executable lines of code by the grammar that Java compilers use, and counting from there. There are plenty of exceptions that simple checks might skip over. Additionally, consider the line:
String commentCodeFun = " // not a real comment ";
It's a nightmare for your current approach

Split a string containing command-line parameters into a String[] in Java

Similar to this thread for C#, I need to split a string containing the command line arguments to my program so I can allow users to easily run multiple commands. For example, I might have the following string:
-p /path -d "here's my description" --verbose other args
Given the above, Java would normally pass the following in to main:
Array[0] = -p
Array[1] = /path
Array[2] = -d
Array[3] = here's my description
Array[4] = --verbose
Array[5] = other
Array[6] = args
I don't need to worry about any shell expansion, but it must be smart enough to handle single and double quotes and any escapes that may be present within the string. Does anybody know of a way to parse the string as the shell would under these conditions?
NOTE: I do NOT need to do command line parsing, I'm already using joptsimple to do that. Rather, I want to make my program easily scriptable. For example, I want the user to be able to place within a single file a set of commands that each of which would be valid on the command line. For example, they might type the following into a file:
--addUser admin --password Admin --roles administrator,editor,reviewer,auditor
--addUser editor --password Editor --roles editor
--addUser reviewer --password Reviewer --roles reviewer
--addUser auditor --password Auditor --roles auditor
Then the user would run my admin tool as follows:
adminTool --script /path/to/above/file
main() will then find the --script option and iterate over the different lines in the file, splitting each line into an array that I would then fire back at a joptsimple instance which would then be passed into my application driver.
joptsimple comes with a Parser that has a parse method, but it only supports a String array. Similarly, the GetOpt constructors also require a String[] -- hence the need for a parser.
Here is a pretty easy alternative for splitting a text line from a file into an argument vector so that you can feed it into your options parser:
This is the solution:
public static void main(String[] args) {
String myArgs[] = Commandline.translateCommandline("-a hello -b world -c \"Hello world\"");
for (String arg:myArgs)
System.out.println(arg);
}
The magic class Commandline is part of ant. So you either have to put ant on the classpath or just take the Commandline class as the used method is static.
If you need to support only UNIX-like OSes, there is an even better solution. Unlike Commandline from ant, ArgumentTokenizer from DrJava is more sh-like: it supports escapes!
Seriously, even something insane like sh -c 'echo "\"un'\''kno\"wn\$\$\$'\'' with \$\"\$\$. \"zzz\""' gets properly tokenized into [bash, -c, echo "\"un'kno\"wn\$\$\$' with \$\"\$\$. \"zzz\""] (By the way, when run, this command outputs "un'kno"wn$$$' with $"$$. "zzz").
You should use a fully featured modern object oriented Command Line Argument Parser I suggest my favorite Java Simple Argument Parser. And how to use JSAP, this is using Groovy as an example, but it is the same for straight Java. There is also args4j which is in some ways more modern than JSAP because it uses annotations, stay away from the apache.commons.cli stuff, it is old and busted and very procedural and un-Java-eques in its API. But I still fall back on JSAP because it is so easy to build your own custom argument handlers.
There are lots of default Parsers for URLs, Numbers, InetAddress, Color, Date, File, Class, and it is super easy to add your own.
For example here is a handler to map args to Enums:
import com.martiansoftware.jsap.ParseException;
import com.martiansoftware.jsap.PropertyStringParser;
/*
This is a StringParser implementation that maps a String to an Enum instance using Enum.valueOf()
*/
public class EnumStringParser extends PropertyStringParser
{
public Object parse(final String s) throws ParseException
{
try
{
final Class klass = Class.forName(super.getProperty("klass"));
return Enum.valueOf(klass, s.toUpperCase());
}
catch (ClassNotFoundException e)
{
throw new ParseException(super.getProperty("klass") + " could not be found on the classpath");
}
}
}
and I am not a fan of configuration programming via XML, but JSAP has a really nice way to declare options and settings outside your code, so your code isn't littered with hundreds of lines of setup that clutters and obscures the real functional code, see my link on how to use JSAP for an example, less code than any of the other libraries I have tried.
This is a direction solution to your problem as clarified in your update, the lines in your "script" file are still command lines. Read them in from the file line by line and call JSAP.parse(String);.
I use this technique to provide "command line" functionality to web apps all the time. One particular use was in a Massively Multiplayer Online Game with a Director/Flash front end that we enabled executing "commands" from the chat like and used JSAP on the back end to parse them and execute code based on what it parsed. Very much like what you are wanting to do, except you read the "commands" from a file instead of a socket. I would ditch joptsimple and just use JSAP, you will really get spoiled by its powerful extensibility.
/**
* [code borrowed from ant.jar]
* Crack a command line.
* #param toProcess the command line to process.
* #return the command line broken into strings.
* An empty or null toProcess parameter results in a zero sized array.
*/
public static String[] translateCommandline(String toProcess) {
if (toProcess == null || toProcess.length() == 0) {
//no command? no string
return new String[0];
}
// parse with a simple finite state machine
final int normal = 0;
final int inQuote = 1;
final int inDoubleQuote = 2;
int state = normal;
final StringTokenizer tok = new StringTokenizer(toProcess, "\"\' ", true);
final ArrayList<String> result = new ArrayList<String>();
final StringBuilder current = new StringBuilder();
boolean lastTokenHasBeenQuoted = false;
while (tok.hasMoreTokens()) {
String nextTok = tok.nextToken();
switch (state) {
case inQuote:
if ("\'".equals(nextTok)) {
lastTokenHasBeenQuoted = true;
state = normal;
} else {
current.append(nextTok);
}
break;
case inDoubleQuote:
if ("\"".equals(nextTok)) {
lastTokenHasBeenQuoted = true;
state = normal;
} else {
current.append(nextTok);
}
break;
default:
if ("\'".equals(nextTok)) {
state = inQuote;
} else if ("\"".equals(nextTok)) {
state = inDoubleQuote;
} else if (" ".equals(nextTok)) {
if (lastTokenHasBeenQuoted || current.length() != 0) {
result.add(current.toString());
current.setLength(0);
}
} else {
current.append(nextTok);
}
lastTokenHasBeenQuoted = false;
break;
}
}
if (lastTokenHasBeenQuoted || current.length() != 0) {
result.add(current.toString());
}
if (state == inQuote || state == inDoubleQuote) {
throw new RuntimeException("unbalanced quotes in " + toProcess);
}
return result.toArray(new String[result.size()]);
}
Expanding on Andreas_D's answer, instead of copying, use CommandLineUtils.translateCommandline(String toProcess) from the excellent Plexus Common Utilities library.
I use the Java Getopt port to do it.

Programs that reproduces itself

Is it possible to make a Java program that prints its source code to a new file, and compiles it, and runs the compiled program?
Update:
Okay, might as well make it autorun. Enjoy the madness. Run at your own risk.
Yes it's possible, because I actually wrote it up. It doesn't do the RUN part (that's just too crazy, because as others have mentioned, it will cause an infinite loop), but here it is: Quine.java
import java.io.*;
public class Quine {
public static void main(String[] args) throws Exception {
char q = 34;
String out = "Quine$";
String text = (
"import java.io.*; " +
"public class [OUT] { " +
"public static void main(String[] args) throws Exception { " +
"char q = 34; String out = `[OUT]$`; String text = `[TEXT]`; " +
"PrintWriter pw = new PrintWriter(out + `.java`); " +
"pw.format(text, 34, out, text); " +
"pw.close(); Runtime runtime = Runtime.getRuntime(); " +
"runtime.exec(`javac ` + out + `.java`).waitFor(); " +
"runtime.exec(`java ` + out); " +
"} " +
"}"
).replace("`", "%1$c").replace("[OUT]", "%2$s").replace("[TEXT]", "%3$s");
PrintWriter pw = new PrintWriter(out + ".java");
pw.format(text, 34, out, text);
pw.close();
Runtime runtime = Runtime.getRuntime();
runtime.exec("javac " + out + ".java").waitFor();
runtime.exec("java " + out);
}
}
So here's how to get the craziness to start:
javac Quine.java to compile
java Quine to run it
It will produce, compile and run Quine$
I've made sure Quine.java is as readable as possible, so the major difference from Quine$.java are formatting and the 3x replace. The minor difference is that Quine$.java has out set to Quine$$.
Quine$ will produce, compile and run Quine$$
Quine$$ will produce, compile and run Quine$$$
Quine$$$ will produce, compile and run Quine$$$$
...
Do note that this doesn't do any reverse-engineering or cheat by reading the .java source code, etc. Quine is a quine-generator because it produces a different code differently formatted, but Quine$ is pretty much a true self-contained quine: it does reproduce itself, it just relabels it Quine$$ (which reproduces itself and relabels to Quine$$$ etc).
So technically there's no infinite loop: it will eventually come to a halt when the file system can't handle another $. I was able to manually stop the madness by forcefully deleting all Quine$* files, but run at your own risk!!!
Yes, it is possible.
A trivial implementation would be: have the source code contain itself in a string, save the string to a file and fill its own string with the same string (otherwise, the initial string would be of infinite size, due to the recursive manner of this implementation), compile the file, and run the compiled file (which will, in turn, do the very same).
Non-trivial implementations are significantly harder.
Sure it works - Have a look at rosetta code and navigate to Quine, which is a self-referential program that can, without any external access, output its own source.
There's one example for a quine in Java.
Programs that reproduces itself or Self Replicating Programs are known as Quine Programs
Sample Program in Java which reproduces itself.
public class QuineProgram {
public static void main(String[] args){
String f = "public class QuineProgram { "
+ "public static void main(String[] args)"
+ "{ String f =%c%s%1$c;"
+ " System.out.printf(f,34,f);}} ";
System.out.printf(f, 34, f);
}
}
Output:
public class QuineProgram { public static void main(String[] args){ String f ="public class QuineProgram { public static void main(String[] args){ String f =%c%s%1$c; System.out.printf(f,34,f);}} "; System.out.printf(f,34,f);}}
You could use the Java Compiler API (JSR-199) for this. Below, code from the JSR-199 that compiles code from a String (slightly modified to make it compile). The code actually compiles source code from the String into a byte array (i.e. it doesn't write to disk), loads it and then executes it via reflection:
MemoryFileManager.java: A file manager for compiling strings to byte arrays.
ByteArrayClassLoader.java: A class loader which loads classes from byte arrays.
CompileFromString.java: The class that wrap everything together.
That could be a starting point (credits to Peter Van der Ahé, the original author).
BTW, you need of course a JDK to use this API.
I don't know exactly what you want, but I think BeanShell is something you can use.
BeanShell is an interpreter. You can run uncompiled Java-code (So you give it a String with code and he runs it).
Of course if you really want to do what you wrote, the machine where the program is running needs a JDK to compile your program.
Hope this helps
I dont think it will work in Java. Wouldn't that involve overwriting a running class file.
Suppose your program is in Quine.java compiled to Quine.class.
Now Quine.class will attempt to write its output to Quine.java (so far so good), and compile it to Quine.class. This is gonna be a problem as Quine.class is already running
Yes - don't forget to use a JDK instead of a JRE:
Bundle the app's source code files with the app. The app would copy the source files to a new set of source code files, compile the new source files, bundle the new source code with the new class files into a new app, and then spawn the new app.
or
Bundle a decompiler with the app. The app would run the decompiler on its own class files to generate new source code files, compile the new source files, bundle the decompiler with the new class files into a new app, and then spawn the new app.
Here's a Java Quine using preview text block feature (-source 13 --enable-preview) where output is formatted the same as input:
package org.sample.quine;
public class QuineProgram
{
public static void main(String...args)
{
String f ="""
package org.sample.quine;
public class QuineProgram
{
public static void main(String...args)
{
String f =""%c%c%s%1$c"";
System.out.printf(f, 34, 10, f);
}
}
""";
System.out.printf(f, 34, 10, f);
}
}
Output:
package org.sample.quine;
public class QuineProgram
{
public static void main(String...args)
{
String f ="""
package org.sample.quine;
public class QuineProgram
{
public static void main(String...args)
{
String f =""%c%c%s%1$c"";
System.out.printf(f, 34, 10, f);
}
}
""";
System.out.printf(f, 34, 10, f);
}
}
Heavily Commented Version:
package org.sample.quine;
public class Quine
{
public static void main(String...args)
{
// Inside text block use "" followed by token or token followed by "" so that we don't prematurely close text block
String f ="""
package org.sample.quine;
public class Quine
{
public static void main(String...args)
{
// Inside text block use "" followed by token or token followed by "" so that we don't prematurely close text block
String f =""%c%c%s%1$c"";
/* Tokens in template text block, each prefixed with percent symbol
* 1(c) third quote (34) of open block delimiter
* 2(c) new line (10) of open block delimiter
* 3(s) String f text block that goes between two text block delimiters
* 4(1$c) first quote (34) of close block delimiter,
* 1$ means first argument after template argument
* 2$ would be second argument after template argument
*/
// Arguments - 1 template (String f); 2 "; 3 newline; 4 template again without replacing tokens
System.out.printf(f, 34, 10, f);
}
}
""";
/* Tokens in template text block, each prefixed with percent symbol
* 1(c) third quote (34) of open block delimiter
* 2(c) new line (10) of open block delimiter
* 3(s) String f text block that goes between two text block delimiters
* 4(1$c) first quote (34) of close block delimiter,
* 1$ means first argument after template argument
* 2$ would be second argument after template argument
*/
// Arguments - 1 template (String f); 2 "; 3 newline; 4 template again without replacing tokens
System.out.printf(f, 34, 10, f);
}
}

Is there a way to know if a Java program was started from the command line or from a jar file?

I want to either display a message in the console or a pop up, so in case a parameter is not specified, I want to know to which should I display
Something like:
if( !file.exists() ) {
if( fromCommandLine()){
System.out.println("File doesn't exists");
}else if ( fromDoubleClickOnJar() ) {
JOptionPane.showMessage(null, "File doesn't exists");
}
}
The straight forward answer is that you cannot tell how the JVM was launched.
But for the example use-case in your question, you don't really need to know how the JVM was launched. What you really need to know is whether the user will see a message written to the console. And the way to do that would be something like this:
if (!file.exists()) {
Console console = System.console();
if (console != null) {
console.format("File doesn't exists%n");
} else if (!GraphicsEnvironment.isHeadless()) {
JOptionPane.showMessage(null, "File doesn't exists");
} else {
// Put it in the log
}
}
The javadoc for Console, while not water tight, strongly hints that a Console object (if it exists) writes to a console and cannot be redirected.
Thanks #Stephen Denne for the !GraphicsEnvironment.isHeadless() tip.
I'm not clear on the question but I'm going to interpret it as you want to differentiate between the following 2
java -jar fred.jar
and
java package.Main
Here is an outline line of the program
import sun.jvmstat.monitor.*;
...
HostIdentifier hostId = new HostIdentifier("localhost");
MonitoredHost monitoredHost = MonitoredHost.getMonitoredHost(hostId);
Set jvms = monitoredHost.activeVms();
for (Object i: jvms) {
VmIdentifier id = new VmIdentifier("//" + i + "?mode=r");
MonitoredVm vm = monitoredHost.getMonitoredVm(id, 0);
System.out.println(i);
System.out.println("\t main class: " + MonitoredVmUtil.mainClass(vm, false));
System.out.println("\t main args: " + MonitoredVmUtil.mainArgs(vm));
System.out.println("\t jvmArgs: " + MonitoredVmUtil.jvmArgs(vm));
monitoredHost.detach(vm);
}
The call MonitoredVmUtil.mainClass(vm, false) will either return 'jar' or the name of your main class eg Main.
You have to use $JAVA_HOME/lib/tools.jar to compile and run.
The System.console() trick seems to do the work.
Here's an alternative: there's a method in the class Class getProtectionDomain() which may be used to know the source of the code the the location from there.
The funny is, this method is available since 1.2
I knew I used this before, here's the original answer by erickson
Here's the proof of concept:
public class FromJar {
public static void main( String [] args ) {
if ( FromJar.class
.getProtectionDomain()
.getCodeSource()
.getLocation()
.getFile()
.endsWith(".jar") ) {
javax.swing.JOptionPane.showMessageDialog( null, "Launched from Jar" );
} else {
System.out.println("Launched NOT from Jar :P ");
}
}
}
Here's a short ( 1m aprox ) video to see this code running ( and being written with cat :-o )
You can try with:
if (System.console() != null) {
// Console attached to the JVM: command prompt output
System.out.println("...");
} else {
// No console: use Swing
}
From http://java.itags.org/java-essentials/15972/
try {
GraphicsEnvironment.getLocalGraphicsEnvironment();
} catch(Throwable ex) {
System.out.println("No graphical environment is available.");
}
it's true that it is impossible to tell how the JVM was invoked.
but... there's a way to side step this.
you assumed that when the user double clicked on a JAR, then there's GUI running...
ok. so let's extend this assumption.
check.. from where the class was invoked, the directory.
check that directory..
assuming it's a normal usage, when there's a *.jar file, then the user must've started the app from a jar..
but one flaw is that the user can also click on the main class file.
hahahaha
You can get all the input arguments with RuntimeMBean.getInputArguments(), this can be used to detect when debugging is enabled.
EDIT: However, the -jar argument isn't one of them. :(

Categories

Resources