I have been creating a program that writes and run java classes. So far I have been able to write a "Runable.java" class but not able to run it. I have tried to run a "runjava.bat" and get the .bat to run the "Runable.java" class but I keep getting a "Error: Could not find or load main class application.Runable.class". I was wondering what I am doing wrong or if there is a better way to go about running a java class from within a java program?
Here is my code(Simplify Slightly):
Main.java:
package application;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Platform;
import javafx.stage.FileChooser;
public class Main {
final static String Program =
"package application;\n"
+ "public class Runable {\n"
+ "public static void main(String[] args) {\n"
+ "System.out.println(\"Hello\");\n"
+ "}\n"
+ "}\n";
public static void main(String[] args) throws IOException {
Scanner s = new Scanner(System.in);
while(true){
System.out.println("State a comand.");
String Command = s.nextLine();
if (Command.equalsIgnoreCase("Write") || Command.equalsIgnoreCase("Save")){
FileChooser fileChooser = new FileChooser();
//Set extension filter
FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter("TXT files (*.txt)", "*.txt");
fileChooser.getExtensionFilters().add(extFilter);
//Show save file dialog
File file = new File("src/application/Runable.class");
if(file != null){
SaveFile(Program, file);
}
}
else if (Command.equalsIgnoreCase("Run") || Command.equalsIgnoreCase("Play")){
ProcessBuilder builder = new ProcessBuilder(
"src/runjava.bat");
builder.redirectErrorStream(true);
Process p = builder.start();
BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
while (true) {
line = r.readLine();
if (line == null) { break; }
System.out.println(line);
}
}
else if (Command.equalsIgnoreCase("End") || Command.equalsIgnoreCase("Exit")){
Platform.exit();
}
else{
System.err.println("Command not recognized.");
System.err.println("Please try again.");
}
}
}
private static void SaveFile(String content, File file){
try {
FileWriter fileWriter = null;
fileWriter = new FileWriter(file);
fileWriter.write(content);
fileWriter.close();
} catch (IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
runjava.bat:
javac "src\application\Runable.java"
java application.Runable.class
and Runable.java if you didn't get it from the Main.java:
package application;
public class Runable {
public static void main(String[] args) {
System.out.println("Hello");
}
}
The java command expects a class name, not a filename. Unless your class is called "class" in the package "application.Runable" (which it isn't) you probably wanted to use:
java application.Runable
Because you can't execute a .java file like that. You must first compile it to get a .class file, and change the code that executes the class to point to Runable.class
The reason it is not running, is because the .java file is the code you type, and the .class file is the compiled version of the code that Java Virtual Machine executes.
Another solution to compile and run the program compared to executing the .bat file is to use the javax.tools API or another library based off of it. I have found InMemoryJavaCompiler library that makes it easy to compile and run the programs. This approach means that the program will run on the same JVM as your UI which may be helpful.
The following code shows how you might invoke the program using the library.
try{
Class<?> clazz = InMemoryJavaCompiler.compile("apllication.Runable", Program);
clazz.getMethod("main", String[].class).invoke(null, new String[0]);
}catch(Exception e){
e.printStackTrace();
}
In your Main.java's "Run" block, you should have
ProcessBuilder builder = new ProcessBuilder("runjava.bat");
In your runjava.bat, you should have (as immibis said)
javac -d . src/application/Runable.java
java application.Runable
** not Runable.class in the second line.
And runjava.bat should be placed in parallel with the parent folder of application\ but not the src\application folder. In other words, you should have something like classes\runjava.bat, classes\application\Main.class and classes\application\Runable.class. Hope it helps.
Related
So the idea is that this line in the code below
Runtime.getRuntime().exec("cd /Users/fnord/Documents/workspace/LearningJava/src/PackA/; javac classA.java; cd ..; java PackA.classA");
should do the same thing as this line
cd /Users/fnord/Documents/workspace/LearningJava/src/PackA/; javac classA.java; cd ..; java PackA.classA
when that second line is run from a terminal. That is to compile and run the java code. Am I misunderstanding how exec() works? If so, what would be the best way to go about accomplishing what it is I want to accomplish?
package PackA;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
public class classA {
public static void main(String[] args) throws Exception{
ClassLoader loader = classA.class.getClassLoader();
//Sets the file path to the path of the current .java file
File file = new File(loader.getResource(classA.class.getPackage().getName()+"/"+classA.class.getSimpleName()+".class").toString().replaceAll("file:", "").replaceAll("bin", "src").replaceAll("sA.class", "sA.java"));
BufferedReader in = new BufferedReader(new FileReader(file)); //establishes the reader that will be used to read this .java file
StringBuffer string = new StringBuffer(); //the stringBuffer that will be used to hold the contents of this .java file
String stringRead = in.readLine(); //sets a string to the first line of this .java file
while((stringRead) != null){ //as long as we haven't reached the end of the file
string.append(stringRead); //append the line
string.append(System.getProperty("line.separator")); //go to the next line
stringRead = in.readLine(); //read the next line
}
Integer intToFind = new Integer(0); //the integer being looked for
if (intToFind<=10) { //as long as the intToFind is less than or equal to 10
//increment the intToFind in the stringBuffer
StringBuffer newProgram = new StringBuffer(string.toString().replaceFirst("[(]"+intToFind.toString(), "("+String.valueOf(++intToFind)));
//establishes the writer that will be used to write to the file
BufferedWriter out = new BufferedWriter(new FileWriter(file));
out.write(newProgram.toString()); //write the newProgram to this .java file with the incremented intToFind
in.close(); //close both the reader and writer
out.close();
//Go to the directory of the java file, compile the code, move down one directory, execute the .class file
Runtime.getRuntime().exec("cd /Users/fnord/Documents/workspace/LearningJava/src/PackA/; javac classA.java; cd ..; java PackA.classA");
}
}
}
cd is not a program, it's a shell command.
You could use ProcessBuilder instead, which would allow you to define the working directory context from which the command should be executed
Something like this for example
Abbriviated code from previous example, updated to provide the ability to specifiy the working directory
public int compile(String file, File workingDirectory) throws IOException, InterruptedException {
ProcessBuilder pb = new ProcessBuilder("javac", file);
pb.redirectError();
pb.directory(new File(workingDirectory));
Process p = pb.start();
InputStreamConsumer consumer = new InputStreamConsumer(p.getInputStream());
consumer.start();
int result = p.waitFor();
consumer.join();
System.out.println(consumer.getOutput());
return result;
}
public class InputStreamConsumer extends Thread {
private InputStream is;
private IOException exp;
private StringBuilder output;
public InputStreamConsumer(InputStream is) {
this.is = is;
}
#Override
public void run() {
int in = -1;
output = new StringBuilder(64);
try {
while ((in = is.read()) != -1) {
output.append((char) in);
}
} catch (IOException ex) {
ex.printStackTrace();
exp = ex;
}
}
public StringBuilder getOutput() {
return output;
}
public IOException getException() {
return exp;
}
}
Which you could call using something like...
compile("PackA/classA.java", new File("/Users/fnord/Documents/workspace/LearningJava/src"));
Now, if you're really courageous, you could take a look at How do you dynamically compile and load external java classes?, which uses javax.tools.JavaCompiler` class to compile a Java file...
I have most of it down but when I try to make the copy, no copy is made.
It finds the files in the specified directory like it is supposed to do and I think the copy function executes but there aren't any more files in the specified directory. Any help is appreciated. I made a printf function that isn't shown here. Thanks!
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Scanner;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.FileUtils;
import static java.nio.file.StandardCopyOption.*;
public class Stuff {
static String path, oldExtn, newExtn;
static Boolean delOrig = false;
private static void getPathStuff() {
printf("Please enter the desired path\n");
Scanner in = new Scanner(System.in);
path = in.next();
printf("Now enter the file extension to replace\n");
oldExtn = in.next();
printf("Now enter the file extension to replace with\n");
newExtn = in.next();
in.close();
}
public static void main(String[] args) {
getPathStuff();
File folder = new File(path);
printf("folder = %s\n", folder.getPath());
for (final File fileEntry : folder.listFiles()) {
if (fileEntry.getName().endsWith(oldExtn)) {
printf(fileEntry.getName() + "\n");
File newFile = new File(FilenameUtils.getBaseName(fileEntry
.getName() + newExtn));
try {
printf("fileEntry = %s\n", fileEntry.toPath().toString());
Files.copy(fileEntry.toPath(), newFile.toPath(),
REPLACE_EXISTING);
} catch (IOException e) {
System.err.printf("Exception");
}
}
}
}
}`
The problem is that the new file is created without a full path (only the file name). So your new file is created - only not where you expect...
You can see that it'll work if you'll replace:
File newFile = new File(FilenameUtils.getBaseName(fileEntry
.getName() + newExtn));
with:
File newFile = new File(fileEntry.getAbsolutePath()
.substring(0,
fileEntry.getAbsolutePath()
.lastIndexOf(".")+1) + newExtn);
I have the following code segment to run a bat file:
String workingDir = System.getProperty("user.dir");
ProcessBuilder pb = new ProcessBuilder("cmd", "/c",
"\"" + workingDir + File.separator + "midl.bat\"");
Process ddsBuildProc = pb.start();
ddsBuildProc.waitFor();
The workingDir includes spaces in the path. Eventhough I use quotes to enclose the workingDir+fileName string, the shell still splits the workingDir and doesn't run the bat file. If a try and copy-paste-execute the bat file path string in the Windows command window manually, it works as expected. What can be the problem here?
Also, please do not close this question as duplicate because I tried all the solutions in the other questions with no success.
Don't quote commands in a command list, unless the command been executed expects it, this will just stuff things up
user.dir is your programs current executing context...so it actually makes no sense to include it, you could just use midl.bat by itself (assuming the command exists within the current execution context)
I wrote a really simple batch file...
#echo off
dir
Which I put in my "C:\Program Files" directory, as I need a path with spaces and used....
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.logging.Level;
import java.util.logging.Logger;
public class RunBatch {
public static void main(String[] args) {
ProcessBuilder pb = new ProcessBuilder(
"cmd", "/c", "listme.bat"
);
pb.directory(new File("C:/Program Files"));
pb.redirectError();
try {
Process process = pb.start();
InputStreamConsumer.consume(process.getInputStream());
System.out.println("Exited with " + process.waitFor());
} catch (IOException | InterruptedException ex) {
ex.printStackTrace();
}
}
public static class InputStreamConsumer implements Runnable {
private InputStream is;
public InputStreamConsumer(InputStream is) {
this.is = is;
}
public static void consume(InputStream inputStream) {
new Thread(new InputStreamConsumer(inputStream)).start();
}
#Override
public void run() {
int in = -1;
try {
while ((in = is.read()) != -1) {
System.out.print((char) in);
}
} catch (IOException exp) {
exp.printStackTrace();
}
}
}
}
To run it without any issues...
I am trying to compile a java class file in another java class file by using javac command. It went well if these two file do not have any package name with them.
Class Laj
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
public class Laj {
private static void printLines(String name, InputStream ins) throws Exception {
String line = null;
BufferedReader in = new BufferedReader(
new InputStreamReader(ins));
while ((line = in.readLine()) != null) {
System.out.println(name + " " + line);
}
}
private static void runProcess(String command) throws Exception {
Process pro = Runtime.getRuntime().exec(command);
printLines(command + " stdout:", pro.getInputStream());
printLines(command + " stderr:", pro.getErrorStream());
pro.waitFor();
if(pro.exitValue() != 0){
System.out.println(command + " exitValue() " + pro.exitValue());
}
}
public static void main(String[] args) {
try {
runProcess("javac simpleTest.java");
runProcess("java simpleTest");
} catch (Exception e) {
e.printStackTrace();
}
}
}
Class SimpleTest
public class simpleTest {
public static void main(String[] args) {
System.out.println("What's wrong with it");
}
}
I can use the commands javac Laj.java and java Laj to compile and run them well. However if I add the package name, for example package compileTest in the front of these two classes and modify the runProcess part of the code in Laj to
runProcess("javac -d . compileTest.simpleTest.java");
runProcess("java compileTest.simpleTest");
the code would not work.
Can anyone help me, thank you.
Why do not you use 'JavaCompiler' class to compile your java file. Please see below example I have compiled a java class with package name.
Package Name = com.main
Class Name = MainClass.java
Source Dir = src
public void compileClass() {
System.setProperty("java.home", "G:\\Java\\Tools\\installed\\JDK"); // Set JDK path it will help to get compiler
File root = new File("/src"); // Source Directory
File sourceFile = new File(root, "com/main/MainClass.java"); // Java file name with package
sourceFile.getParentFile().mkdirs();
try {
new FileWriter(sourceFile).close(); // Read Java file
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
System.out.println(compiler.run(null, null, null, sourceFile.getPath()));
}
So lets say I have a txt file that I want to write to with a PrintWriter. How come the following code deletes the old contents of the file everytime its called?
Code:
import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
public class Test {
public static void main(String[] args) {
writeToFile("foo");
writeToFile("bar");
}
public static void writeToFile(String text) {
try {
PrintWriter printer = new PrintWriter(new File("myTextFile.txt"));
printer.println("Your text is:" + text);
printer.close();
} catch (FileNotFoundException fnfe) {
fnfe.printStackTrace();
}
}
}
Output:
Your text is:bar
I'm guessing its something to do with the fact that I'm creating a new PrintWriter or a new File every time the method is being called, but having only one instance being created in the main method failed to work as well.
If you want to add to a file's contents, you need to explicitly open the file for append; the default in most languages is overwrite.
To do so in Java, use new FileWriter("myfile.txt", true). You can then wrap a PrintWriter around that if desired.