Java runtime compiler using reflections not working properly - java

I have a JavaFX app where there is an editor. In the editor, the user will be able to write java code and I have a button to compile this code and run the main method. For example the editor will contain this code:
public class Test {
public static void main(String[] args) {
System.out.println("hello");
}
}
The button on click, will run this code:
runButton.setOnAction(e -> {
compiler.set(editor.getText());
try {
compiler.createFile();
} catch (IOException e1) {
e1.printStackTrace();
}
compiler.compile();
compiler.run();
});
In the compiler class, there is the following implementation:
public class CodeCompiler {
public String className;
public String code;
public void set(String code) {
try {
this.className = code.substring(code.indexOf(" class ") + 6, code.indexOf(" {")).trim();
} catch(StringIndexOutOfBoundsException e) {
}
this.code = code;
}
public void createFile() throws IOException {
PrintWriter pw = new PrintWriter("speech2code/src/main/java/" + className + ".java");
pw.close();
FileWriter writer = new FileWriter("speech2code/src/main/java/" + className + ".java", true);
writer.write(code);
writer.flush();
writer.close();
}
public void compile() {
File file = new File("speech2code/src/main/java/" + className + ".java");
File classFile = new File("speech2code/src/main/java/" + className + ".class");
classFile.delete(); // delete class file f it exists
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
compiler.run(null, null, null, file.getPath());
}
public void run() {
Class<?> cls = null;
try {
cls = Class.forName(className);
System.out.println(cls == null);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Method meth = null;
try {
meth = cls.getMethod("main", String[].class);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
String[] params = null;
try {
meth.invoke(null, (Object) params);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
Now the code above successfully creates the java file, class file and runs correctly the first time. Now when I change the editor code to print something else, it outputs the result of the first time the code was running. So, in this case, it will still print 'hello' instead of whatever it's current value.
Any problem what might be wrong?
Thanks!

You need to create a new classloader for the new class. The class does not get reloaded just because you compiled it.
URLClassLoader classLoader = URLClassLoader.newInstance(new URL[] {classFile});
Then you can ask this loader for the class:
Class<?> cls = Class.forName(className, true, classLoader);

Related

Increment number every time program runs

I want to increment the count every time my program runs. I tried running below code but it keeps on printing 1 every time i run the program. Also anything special i need to do to increase the date.
public class CounterTest {
int count = 0;
public static void main(String[] args) {
CounterTest test1 = new CounterTest();
test1.doMethod();
}
public void doMethod() {
count++;
System.out.println(count);
}
}
You could simply create a properties file for your application to keep track of such things and application configuration details. This of course would be a simple text file containing property names (keys) and their respective values.
Two small methods can get you going:
The setProperty() Method:
With is method you can create a properties file and apply whatever property names and values you like. If the file doesn't already exist then it is automatically created at the file path specified:
public static boolean setProperty(String propertiesFilePath,
String propertyName, String value) {
java.util.Properties prop = new java.util.Properties();
if (new java.io.File(propertiesFilePath).exists()) {
try (java.io.FileInputStream in = new java.io.FileInputStream(propertiesFilePath)) {
prop.load(in);
}
catch (java.io.FileNotFoundException ex) { System.err.println(ex); }
catch (java.io.IOException ex) { System.err.println(ex); }
}
try (java.io.FileOutputStream outputStream = new java.io.FileOutputStream(propertiesFilePath)) {
prop.setProperty(propertyName, value);
prop.store(outputStream, null);
outputStream.close();
return true;
}
catch (java.io.FileNotFoundException ex) {
System.err.println(ex);
}
catch (java.io.IOException ex) {
System.err.println(ex);
}
return false;
}
If you don't already contain a specific properties file then it would be a good idea to call the above method as soon as the application starts (perhaps after initialization) so that you have default values to play with if desired, for example:
if (!new File("config.properties").exists()) {
setProperty("config.properties", "ApplicationRunCount", "0");
}
The above code checks to see if the properties file named config.properties already exists (you should always use the .properties file name extension). If it doesn't then it is created and the property name (Key) is applied to it along with the supplied value for that property. Above we are creating the ApplicationRunCount property which is basically for your specific needs. When you look into the config.properties file created you will see:
#Mon Sep 28 19:07:08 PDT 2020
ApplicationRunCount=0
The getProperty() Method:
This method can retrieve a value from a specific property name (key). Whenever you need the value from a particular property contained within your properties file then this method can be used:
public static String getProperty(String propertiesFilePath, String key) {
try (java.io.InputStream ips = new java.io.FileInputStream(propertiesFilePath)) {
java.util.Properties prop = new java.util.Properties();
prop.load(ips);
return prop.getProperty(key);
}
catch (java.io.FileNotFoundException ex) { System.err.println(ex); }
catch (java.io.IOException ex) { System.err.println(ex); }
return null;
}
Your Task:
What is confusing here is you say you want to keep track of the number of times your Program is run yet you increment your counter variable named count within a method named doMethod(). This would work if you can guarantee that this method will only run once during the entire time your application runs. If this will indeed be the case then you're okay. If it isn't then you would possibly get a count total that doesn't truly represent the actual number of times your application was started.
In any case, with the scheme you're currently using, you could do this:
public class CounterTest {
// Class Constructor
public CounterTest() {
/* If the config.properties file does not exist
then create it and apply the ApplicationRunCount
property with the value of 0. */
if (!new java.io.File("config.properties").exists()) {
setProperty("config.properties", "ApplicationRunCount", "0");
}
}
public static void main(String[] args) {
new CounterTest().doMethod(args);
}
private void doMethod(String[] args) {
int count = Integer.valueOf(getProperty("config.properties",
"ApplicationRunCount"));
count++;
setProperty("config.properties", "ApplicationRunCount",
String.valueOf(count));
System.out.println(count);
}
public static String getProperty(String propertiesFilePath, String key) {
try (java.io.InputStream ips = new
java.io.FileInputStream(propertiesFilePath)) {
java.util.Properties prop = new java.util.Properties();
prop.load(ips);
return prop.getProperty(key);
}
catch (java.io.FileNotFoundException ex) { System.err.println(ex); }
catch (java.io.IOException ex) { System.err.println(ex); }
return null;
}
public static boolean setProperty(String propertiesFilePath,
String propertyName, String value) {
java.util.Properties prop = new java.util.Properties();
if (new java.io.File(propertiesFilePath).exists()) {
try (java.io.FileInputStream in = new java.io.FileInputStream(propertiesFilePath)) {
prop.load(in);
}
catch (java.io.FileNotFoundException ex) { System.err.println(ex); }
catch (java.io.IOException ex) { System.err.println(ex); }
}
try (java.io.FileOutputStream outputStream = new java.io.FileOutputStream(propertiesFilePath)) {
prop.setProperty(propertyName, value);
prop.store(outputStream, null);
return true;
}
catch (java.io.FileNotFoundException ex) {
System.err.println(ex);
}
catch (java.io.IOException ex) {
System.err.println(ex);
}
return false;
}
}
Whenever you start your application you will see the run count within the Console Window. Other useful methods might be removeProperty() and renameProperty(). Here they are:
/**
* Removes (deletes) the supplied property name from the supplied property
* file.<br>
*
* #param propertiesFilePath (String) The full path and file name of the
* properties file you want to remove a property name from.<br>
*
* #param propertyName (String) The property name you want to remove from
* the properties file.<br>
*
* #return (Boolean) Returns true if successful and false if not.
*/
public static boolean removeProperty(String propertiesFilePath,
String propertyName) {
java.util.Properties prop = new java.util.Properties();
if (new java.io.File(propertiesFilePath).exists()) {
try (java.io.FileInputStream in = new java.io.FileInputStream(propertiesFilePath)) {
prop.load(in);
prop.remove(propertyName);
}
catch (java.io.FileNotFoundException ex) { System.err.println(ex); return false; }
catch (java.io.IOException ex) { System.err.println(ex); return false; }
}
try (java.io.FileOutputStream out = new java.io.FileOutputStream(propertiesFilePath)) {
prop.store(out, null);
return true;
}
catch (java.io.FileNotFoundException ex) { System.err.println(ex); }
catch (java.io.IOException ex) { System.err.println(ex); }
return false;
}
/**
* Renames the supplied property name within the supplied property file.<br>
*
* #param propertiesFilePath (String) The full path and file name of the
* properties file you want to rename a property in.<br>
*
* #param oldPropertyName (String) The current name of the property you want
* to rename.<br>
*
* #param newPropertyName (String) The new property name you want to use.<br>
*
* #return (Boolean) Returns true if successful and false if not.
*/
public static boolean renameProperty(String propertiesFilePath, String oldPropertyName,
String newPropertyName) {
String propertyValue = getProperty(propertiesFilePath, oldPropertyName);
if (propertyValue == null) { return false; }
java.util.Properties prop = new java.util.Properties();
if (new java.io.File(propertiesFilePath).exists()) {
try (java.io.FileInputStream in = new java.io.FileInputStream(propertiesFilePath)) {
prop.load(in);
prop.remove(oldPropertyName);
}
catch (java.io.FileNotFoundException ex) { System.err.println(ex); return false; }
catch (java.io.IOException ex) { System.err.println(ex); return false ;}
}
try (java.io.FileOutputStream out = new java.io.FileOutputStream(propertiesFilePath)) {
prop.store(out, null);
}
catch (java.io.FileNotFoundException ex) { System.err.println(ex); return false; }
catch (java.io.IOException ex) { System.err.println(ex); return false; }
return setProperty(propertiesFilePath, newPropertyName, propertyValue);
}
Try this.
public class CounterTest {
static final Path path = Path.of("counter.txt");
int count;
CounterTest() throws IOException {
try {
count = Integer.valueOf(Files.readString(path));
} catch (NoSuchFileException | NumberFormatException e) {
count = 0;
}
}
public void doMethod() throws IOException {
++count;
System.out.println(count);
Files.writeString(path, "" + count);
}
public static void main(String[] args) throws IOException {
CounterTest c = new CounterTest();
c.doMethod();
}
}
You can't the only way is to use a Database or simpler use a txt file to save the number and every time you run your app reads the txt file and gets the number.
Here is How to do it:
This is the Main class:
package main;
import java.io.File;
import java.io.IOException;
public class Main {
public static void main(String[] args) {
String path = "C:\\Example.txt";
int number = 0;
try {
ReadFile file = new ReadFile(path);
String[] aryLines = file.OpenFile();
try {
number = Integer.parseInt(aryLines[0]);
} catch (Exception e) {
}
} catch (IOException e) {
System.out.println(e.getMessage());
}
System.out.println(number);
number++;
File txtfile = new File(path);
if (txtfile.exists()) {
txtfile.delete();
try {
txtfile.createNewFile();
WriteFile data = new WriteFile(path, true);
data.writeToFile(number + "");
} catch (IOException ex) {
}
} else {
try {
System.out.println("no yei");
txtfile.createNewFile();
WriteFile data = new WriteFile(path, true);
data.writeToFile(number + "");
} catch (IOException ex) {
}
}
}
}
the class that writes anything you need:
package main;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.io.IOException;
public class WriteFile {
public String path;
public boolean append_to_file = false;
public WriteFile(String file_path) {
path = file_path;
}
public WriteFile(String file_path, boolean append_value) {
path = file_path;
append_to_file = append_value;
}
public void writeToFile(String textline) throws IOException {
FileWriter write = new FileWriter(path, append_to_file);
PrintWriter print_line = new PrintWriter(write);
print_line.printf("%s" + "%n", textline);
print_line.close();
}
}
And this one is the one that gets the text on the file:
package main;
import java.io.IOException;
import java.io.FileReader;
import java.io.BufferedReader;
public class ReadFile {
private static String path;
public ReadFile(String file_path){
path = file_path;
}
public String[] OpenFile() throws IOException {
FileReader fr = new FileReader(path);
BufferedReader textReader = new BufferedReader(fr);
int numberOfLines = readLines();
String[] textData = new String[numberOfLines];
for (int j = 0; j < numberOfLines; j++) {
textData[j] = textReader.readLine();
}
textReader.close();
return textData;
}
static int readLines() throws IOException {
FileReader file_to_read = new FileReader(path);
BufferedReader bf = new BufferedReader(file_to_read);
String aLine;
int numberOfLines = 0;
while((aLine = bf.readLine()) != null){
numberOfLines++;
}
bf.close();
return numberOfLines;
}
}

How to solve Function1 (Context) in Function1 cannot be applied to ()

I have the following problems:
I would like to call a function from another class so I added this line of code
Function1 func = new Function1(); and I get an error saying
Function1 (Context) in Function1 cannot be applied to ()
Furthermore, relating to this function and its error, I intend calling the aforementioned function which takes a JSON object and a Filename as parameters and it returns a file, however, when I enter it, I get the following error
Wrong 2nd argument type, found Java.lang.String required Java.io.File
The code in question is this:
JSONObject export = jsonArray1.getJSONObject(index);
File file = func.exportToFile(export, "Export.json");
The fuction in question starts like this:
public void exportToFile(JSONObject objectToExport, File fN)
{
String output = objectToExport.toString();
file_ = fN;
if (!file_.exists()) {
try {
file_.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
try{
FileOutputStream fOut = new FileOutputStream(file_);
fOut.write(output.getBytes());
fOut.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
N.B.: I have tried to call the function like this:
File file = func.exportToFile(export, func.file);
but I only get the error saying incompatible types
Required Java.io.file
Found Void
What have I done wrong?
this func.exportToFile(export, func.file); will not return anything since exportToFile it's a void method .
change your method to make it return file this way :
public File exportToFile(JSONObject objectToExport, File fN) {
String output = objectToExport.toString();
file_ = fN;
if (!file_.exists()) {
try {
file_.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
try{
FileOutputStream fOut = new FileOutputStream(file_);
fOut.write(output.getBytes());
fOut.close();
return file_;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}

Using parsed input from text file as parameter for new Event

I've working on an assignment that asks me to alter a method in a class to take content from a textfile and use it to create multiple instances of various subclasses of the Event Class. Here is the text file:
Event=ThermostatNight,time=0
Event=LightOn,time=2000
Event=WaterOff,time=8000
Event=ThermostatDay,time=10000
Event=Bell,time=9000
Event=WaterOn,time=6000
Event=LightOff,time=4000
Event=Terminate,time=12000
The Event=* is the name of the subclass, while time=* is a parameter that is used in the subclass' constructor. The Event class itself is an abstract class and is used for inheritance.
public class Restart extends Event {
Class eventClass;
String eventInput;
Long timeDelay;
public Restart(long delayTime, String filename) {
super(delayTime);
eventsFile = filename;
}
public void action() {
List<String> examples = Arrays.asList("examples1.txt", "examples2.txt", "examples3.txt", "examples4.txt");
for (String example : examples) {
//finding pattern using Regex
Pattern pattern = Pattern.compile(example);
Matcher matcher1 = pattern.matcher(eventsFile);
if (matcher1.find()) {
File file = new File(example);
String line;
try {
FileReader fileReader = new FileReader(file);
Scanner sc = new Scanner(file);
BufferedReader bufferedReader =
new BufferedReader(fileReader);
while ((line = bufferedReader.readLine()) != null) {
sc.useDelimiter("\n");
//Parsing through text
while (sc.hasNext()) {
String s = sc.next();
String[] array1 = s.split(",");
String[] array2 = array1[0].split("=");
eventInput = array2[1];
String[] array3 = array1[1].split("=");
String timeInput = array3[1];
try {
eventClass = Class.forName(eventInput);
timeDelay = Long.parseLong(timeInput);
try {
addEvent(new eventClass(timeDelay));
}
//catch block
catch(NoSuchMethodException e){
System.out.println("No Such Method Error");
} catch (Exception e) {
System.out.println("error");
}
//catch block
} catch (ClassNotFoundException ex) {
System.out.println("Unable to locate Class");
} catch (IllegalAccessException ex) {
System.out.println("Illegal Acces Exception");
} catch (InstantiationException ex) {
System.out.println("Instantiation Exception");
}
}
}
//Close bufferedReader
bufferedReader.close();
}
//catch block
catch (FileNotFoundException ex) {
System.out.println(
"Unable to open file '" +
file + "'");
} catch (IOException ex) {
ex.printStackTrace();
}
break;
}
//if input match is not found
else {
System.out.println("No Match Found");}
}
}
I seem to be able to parse fine, and find the strings i'm looking for, but I'm not able to use eventInput which I've pulled from the text file as a parameter to create a new event.
eventClass = Class.forName(eventInput);
doesn't seem to be turning my string into an acceptable parameter either.
Any help would be much appreciated!
I know I'm probably missing something key here, but I've been staring at it too long that it seems like a lost cause.
Here is the Event class:
public abstract class Event {
private long eventTime;
protected final long delayTime;
public Event(long delayTime) {
this.delayTime = delayTime;
start();
}
public void start() { // Allows restarting
eventTime = System.currentTimeMillis() + delayTime;
}
public boolean ready() {
return System.currentTimeMillis() >= eventTime;
}
public abstract void action();
} ///:~
I think you've misunderstood how reflection works. Once you have a Class object (the output from Class.forName(), you have to find the appropriate constructor with
Constructor<T> constructor = eventClass.getConstructor(parameter types)
and then create a new instance with
constructor.newInstance(parameters);
For a no-arg constructor there's a shortcut
eventClass.newInstance();
I strongly suggest you read the tutorials on reflection before proceeding.

Java abstract class "instance variables"

I don't know if my mind just fools me or this is really not working.
I need different type of Logging-classes so I created a abstract-class, the only definition that all classes will have the same is the way the writeToLog is handled:
public abstract class LoggerTemplate {
protected String filename ="log/";
protected File logfile;
protected FileWriter fw;
public void writeToLog(String message) {
if(fw != null) {
try {
message = new SimpleDateFormat("dd-MM-hh:mm").format(new Date()) + " " + message;
fw.write(message);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
The concrete sub-classes will implement rest of the logic in their constructor, ie one of them:
public class JitterBufferLogger extends LoggerTemplate {
public JitterBufferLogger() {
super();
filename += new SimpleDateFormat("yyyyddMMhhmm'.log'").format(new Date());
if(!new File("log/").exists())
new File("log").mkdir();
logfile = new File(filename);
try {
logfile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
try {
fw = new FileWriter(logfile);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
But when I debug I can see that when calling the writeToLog for a specific logger, it jumps into the LoggerTemplate method, and therefore fw and logfile are null. So it's not working.
Isn't it supposed to work or do I just mess something a bit up and should go into weekend ;-)
It should work, it is normal, that the debugger stepped into the LoggerTemplate class upon entering the writeToLog() method. What is strange that the attributes in the base class have null values.
I have tested your code with the following short test program:
public class Test {
public static void main(String[] args) {
LoggerTemplate lt = new JitterBufferLogger();
lt.writeToLog("Hello");
}
}
After adding fw.flush() to the LoggerTemplate.writeToLog() method just after the fw.write() call, it worked for me, the log file had been created and it contained the log message.
Maybe the new File("log").mkdir() or some other calls throw an exception which you cannot see, because stderr had been redirected somewhere.
So what may be missing?
- filewriter flushing could have helped.
- I can't reproduce the null values with the original code, don't know what happened.
- but as everybody, including me, said: it should work and it does.
Why was nothing in the logfile?
- maybe the flush of fw was missing..
anyhow I wrapped it with a Printwriter:
public abstract class LoggerTemplate {
protected String filename ="log/";
protected File logfile;
protected PrintWriter pw;
public void writeToLog(String message) {
try {
pw = new PrintWriter(new FileWriter(logfile,true));
message = new SimpleDateFormat("dd-MM-hh:mm").format(new Date()) + " " + message + "\n";
pw.write(message);
pw.flush();
pw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
and now it's working like it should and was expected to be.
Note that the fw instantiation in the concrete sub-classes is not needed anymore.

Need help to find the filename

I used the following code to run an exe I load through my code.
private static String filelocation = "";
.
load_exe.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
try {
JFileChooser file_Choose = new JFileChooser();
file_Choose.showOpenDialog(frame);
JavaSamp.filelocation = file_Choose.getCurrentDirectory()
.toString()
+ "\\" + file_Choose.getSelectedFile().getName();
System.out.println("FileLocation" + JavaSamp.filelocation);
} catch (Exception expobj) {
// TODO Auto-generated catch block
}
Runtime rt = Runtime.getRuntime();
try {
System.out.println("File Run Location" + JavaSamp.filelocation);
proc = rt.exec(JavaSamp.filelocation);
} catch (IOException e4) {
e4.printStackTrace();
} catch (Exception e2) {
}
}
});
My problem is, the above execution of the JavaSamp.filelocation, should have to done many times. First time only I load the exe. Next time I wont. I need to store the exe in a string to run for the successive times.
Any suggestion pls
If you want remember the used file just initialize the filelocation with null and test for it. BTW: Storing it as File makes more sense and your way of constructing the absolute path is a bit intricate - compared to just calling getAbsolutePath()
private static File filelocation = null;
private static void test() {
load_exe.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// Check if file-name to execute has already been set
if (filelocation != null) {
try {
JFileChooser file_Choose = new JFileChooser();
file_Choose.showOpenDialog(frame);
JavaSamp.filelocation = file_Choose.getSelectedFile();
System.out.println("FileLocation"
+ JavaSamp.filelocation.getAbsolutePath());
} catch (Exception expobj) {
}
}
Runtime rt = Runtime.getRuntime();
try {
System.out.println("File Run Location"
+ JavaSamp.filelocation.getAbsolutePath());
Process proc = rt.exec(JavaSamp.filelocation
.getAbsolutePath());
} catch (IOException e4) {
e4.printStackTrace();
}
}
};
}

Categories

Resources