Recompiling the object during runtime - java

I am developing a project in java in which ,after running main file , some java files get altered and if i run that file again during the same execution the output does not show the changes done in the java file
For example there are 2 files. Main.java and file1.java
main.java
public static void main(string[] argv)
{
file1 obj = new file1();
obj.view();
Scanner in = new Scanner(System.in);
String x = in.nextLine();
//before entering any value i manually updated the content of file1.java
obj = new file1();
obj.view();
}
file1.java (Before updation)
public class file1
{
public void view()
{
system.out.println("This is test code!!");
}
}
file1.java (After updation)
public class file1
{
public void view()
{
system.out.println("That was done for Testing!!");
}
}
Output :
This is test code!!
This is test code!!

You have to recompile the code in order to see the changes.
What you can do is compile a string (after reading it from the file) with java and call methods of classes through reflection.
HERE is a step by step guide on how to compile a string programatically.

Updating a Java file will not impact the runtime instructions executed by the JVM.
When the compile a Java application the .java source code files are compiled into .class files containing byte code instructions which are in turn interpreted by the JVM. When the JVM requires a class it loads the appropriate .class file into memory via a special object known as a classloader.
Applying this to your example - when you first reference the class File1 the JVM will load the File1 class into memory. This in memory representation of the class will persist until either the classloader is destroyed or the JVM is restarted. No change to the file1.java class is visible to the JVM - firstly because the classloader wont reload the definition and secondly because the definition wont change until the file1.java class is recompiled.
To change an object's behaviour at runtime you can use the reflection API see here.

You don't need to compile source code to accomplish anything close to your example.
public class MyView
{
String the_string;
public MyView (String string) { the_string = string; }
public void setString (String string) { the_string = string; }
public void view () { system.out.println (the_string); }
}
public static void main(string[] argv)
{
MyView obj = new MyView("This is test code!!");
obj.view();
Scanner in = new Scanner(System.in);
obj.setString (in.nextLine());
obj.view();
}

Related

How to set/get a value from another JVM

I have a class Normal with the following code:
public class Normal {
private static String myStr = "Not working...";
private static boolean running = true;
public static void main(String[] args) {
while(running) {
System.out.println(myStr);
}
}
}
And I have another class named Injector in another project. Its purpose is to change the values of Normal even though they are not in the same JVM:
public class Injector {
public static void main(String[] args) {
String PID = //Gets PID, which works fine
VirtualMachine vm = VirtualMachine.attach(PID);
/*
Set/Get field values for classes in vm?
*/
}
}
What I want to do is change the values myStr and running in the class Normal to "Working!" and false respectively without changing the code in Normal (Only in Injector).
Thanks in advance
You'll need two JARs:
One is Java Agent that uses Reflection to change the field value. Java Agent's main class should have agentmain entry point.
public static void agentmain(String args, Instrumentation instr) throws Exception {
Class normalClass = Class.forName("Normal");
Field myStrField = normalClass.getDeclaredField("myStr");
myStrField.setAccessible(true);
myStrField.set(null, "Working!");
}
You'll have to add MANIFEST.MF with Agent-Class attribute and pack the agent into a jar file.
The second one is a utility that uses Dynamic Attach to inject the agent jar into the running VM. Let pid be the target Java process ID.
import com.sun.tools.attach.VirtualMachine;
...
VirtualMachine vm = VirtualMachine.attach(pid);
try {
vm.loadAgent(agentJarPath, "");
} finally {
vm.detach();
}
A bit more details in the article.

how to solve package does not exist error in java

I am trying to compile my java file name Test.java. Test.java calling a class com.api.APIUser.java which is available in a user.jar file. I have added user.jar in lib folder. But Test.java is unable to pick APIUser.java. While I am compiling Test.java using javac I am getting error
"package com.api does not exist".
Test.java
import com.api.APIUser;
public class Test{
APIUser ap = new APIUser();
ap .login();
public static void main(String[] args){
//to do
}
}
APIUser
package com.api
public class APIUser{
public string login(){
//to do
return string;
}
}
If any one have idea why I am getting this error.please suggest me solution.
Thanks in advance.
put a semicolon after the package com.api like as below
package com.api;
clean and build the project and run if any issue inform
You have multiple issues in your code.
You have no line termination present for the com.api import in the APIUser class;
You have a syntax error in your login method.
Below is the improved code:
import com.api.APIUser;
public class Test {
// APIUser ap = new APIUser(); // This call should be in the method body,
// there is no use to keep it at the class level
// ap.login(); // This call should be in method body
public static void main(String[] args) {
// TO DO
APIUser ap = new APIUser();
ap.login();
}
}
APIUser
package com.api; // added termination here
public class APIUser {
//access specifier should be public
public string login(){
//to do
//return string;//return some value from here, since string is not present this will lead to error
return "string";
}
}
Also be sure that the JAR file is present in the classpath. If you are not using any IDE, you must use the -cp switch along with the JAR file path, so that a class can be loaded from there.
You can use the code below to understand how to compile your class using classpath from command prompt.
javac -cp .;/lib/user.jar; -D com.api.Test.java

Java rejects public static void main method, requests public static void main method

I am trying to follow a piece of code to open and read a text file. To do this I have a package called readText. Within I build a class readLocalFile to open and read the file, and a main method to call it. Below are these two classes.
public class readFileLocal {
private String path;
public readFileLocal(String file_path){
path = file_path;
}
int readLines() throws IOException{
FileReader file_to_read = new FileReader(path);
BufferedReader lines = new BufferedReader (file_to_read);
int numberOfLines = 0;
while(lines.readLine()!= null) {
numberOfLines ++;
}
lines.close();
return numberOfLines;
}
public String[] openFile() throws IOException{
FileReader freader = new FileReader (path);
BufferedReader textReader = new BufferedReader (freader);
int numberOfLines = readLines();
String[] textData = new String[numberOfLines];
int i; /* put all the lines of text from the file to the array*/
for (i=0; i<numberOfLines; i++){
textData[i] = textReader.readLine();
}
textReader.close();
return textData;
}
}
Then I have a main class to call it. The code is below:
public class fileData {
public static void main(String[] args) throws IOException{
String file_name = "F:/Testfile.exl";
try{
readFileLocal file = new readFileLocal(file_name);
String[] arylines = file.openFile();
int i;
for (i=0; i<arylines.length; i++){
System.out.println(arylines[i]);
}
}
catch(IOException e) {
System.out.println(e.getMessage());
}
}
}
When I ran it, Eclipse gave me this error message:
Error: Main method not found in class readText.fileData, please define the main method as:public static void main(String[] args) or a JavaFX application class must extend javafx.application.Application
Any idea what went wrong?
You probably should start a new project. Eclipse thinks that you are running a JavaFX program (in which case filedata should extend Application).
Just do a normal build without JavaFX.
Probably, you have declared your own String class in the same package. In this case Eclipse doesn't recognize expected java.lang.String in your main method. Edit your main method declaration as
public static void main(java.lang.String[] args)
and try to run it.
I loaded your code into my copy of Eclipse and it ran the main method without a problem. One curious thing, when I saved the file, I got a message about characters being encoded as "Cp1252" encoding rather than the expected UTF-8. I cut and paste your code into Eclipse from StackOverflow. Maybe this has something to do with the problem?
In Eclipse, you can check what is going on by selecting
Run > Run Configurations...
The "Main" tab will display what Eclipse thinks is the main method to be invoked, and other tabs will show if there are any arguments being sent in.
Also, it might be worth running
Project > Clean
for you project.
Crazy thing to check: are there any other classes with the same name?
Do you have more than one class defined on the same class document?
Another thing to check, navigate to the class document, "fileData" (really should be FileData, follow conventions because otherwise it adds to everyone's confusion who is trying to help or work with you), and right click. Does the right click give you the following?
Run As > 1) Java Application
Or does it show this?
Run As > Run Configurations...
The first case indicates it found the main method, in the second case, no main method was found.
The stuff about JavaFX can be ignored. You aren't running JavaFX according to any code I see displayed, so that issue is moot.
BTW, in your main method, you catch IOException in the try/catch, so there is no need to include "throws IOException" in the main method.

save file from unit test to project tree

In the unit tests as a side effect I am creating screenshots for various parts of the GUI.
I want to use these screenshots when compiling the documentation.
Therefore I want to save them to a directory within the source tree.
Is there any reliable way to get the source directory root when running a junit test?
If not, how can I make sure that unit tests run with cwd=project root when using eclipse, and when using maven?
wether you execute tests on eclipse or using maven, if you don't specify a path when you create the file it's automatically created at project root directory.
so if you specify a relative folder your files will go there :
public class TestFileCreation {
#Test
public void testFileCreation() throws IOException {
File f = new File("src/main/resources/hello.txt");
OutputStream ostream = new FileOutputStream(f);
String data = "Hello there !";
ostream.write(data.getBytes());
ostream.close();
}
}
will create a file inside the $PROJECT/src/main/resources.
Hope my answer helps
You can base on your classes location. Proposed solution here is to use class that will surely be in classpath. Then you can use class.getResource(""). Example
public class ResouceRoot {
public static String get() {
String s = ResouceRoot.class.getResource("").toString();
if (s.startsWith("jar:")) {
s = s.replace("jar:", "").replaceAll("!.*", "");
} else {
s = s.replaceAll("classes.*", "classes");
}
File f = new File(s.replace("file:", ""));
return f.getParentFile().getParentFile().getAbsolutePath();
}
public static void main(String[] args) throws IOException {
System.out.println(get());
}
}
(this code will give base dir for netbeans projects if they are launched from netbeans or by java -jar ... )

select and run a java class or call a method in a class using JFileChooser on an other class (GUI)

I have a file A.java containing a class A with a method aMethod() that is saved on a folder on the PC (not inside the package or workspace).
I have a JFileChooser on another class (GUI).
I want to be able to select class A and run it, or call A::aMethod() using the JFileChooser.
Is this possible?
You need to load class A into a custom class load so you can execute it.
There are a number of issues involved with this. The first revolves around package names, the second revolves around actually calling the classes methods.
The following example basically uses a URLClassLoader to point to a directory of classes, these classes are layout our in there correct package structure. The essentially provides the custom class loader with it's class path
try {
URLClassLoader classLoader = new URLClassLoader(new URL[] {new File("path/to/classes/").toURI().toURL()});
Class<?> loadClass = classLoader.loadClass("dynamicclasses.TestClass");
Object newInstance = loadClass.newInstance();
System.out.println(newInstance);
} catch (Exception ex) {
ex.printStackTrace();
}
The example also relies on the loaded classes toString method to return a result. In my test, I simply dumped the classes class loader reference.
The second problem is a little more difficult to overcome. You have two basic chooses.
You can define a common interface which is available to both the current runtime and the dynamically loaded class. This allows you to cast the loaded class to some known interface which provides you with the ability to call the loaded classes methods (as you have established a contract between the two)
Use reflection to call the methods on the loaded class.
I prefer the first option, but it does mean if you change the interface, you need to compile both sides again.
So I have made some progress. Not where I want to be but it's good...
My GUI has a button that does the following:
btnButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
runFAQm();
}
});
the method called in the GUI when the button is clicked is runFAQm(). Method runFAQm() uses Runtime to run a java file that is saved in an other directory.
public static void runFAQm(){
try {
String[] cmdArray = new String[2];
// first argument is the program we want to open
cmdArray[0] = "java";
// second argument is a txt file we want to open with notepad
cmdArray[1] = "FAQm";
// print a message
// create a file which contains the directory of the file needed
File dir = new File(
"c:/Documents and Settings/AESENG/My Documents/MK/Selenium_Practice/workspace/TestCDM/src");
// create a process and execute cmdArray and currect environment
Process p = Runtime.getRuntime().exec(cmdArray, null, dir);
BufferedReader in = new BufferedReader(new InputStreamReader(
p.getInputStream()));
String line = null;
while ((line = in.readLine()) != null) {
System.out.println(line);
textArea.append(line);
}
} catch (IOException e) {
e.printStackTrace();
}
The java file (called FAQm.java) that is run via the runtime() inside the runFAQm() method, starts a Firefox browser. Of course I have sun Javac.
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import static org.junit.Assert.*;
import org.openqa.selenium.*;
public class FAQm {
static WebDriver driver = new FirefoxDriver();
public static void main(String[] args) throws Exception {
System.out.print("inside FAQm main" );
}
My problem now is that I can run Class FAQm from command line, and from eclipse, but it hangs when i run it from GUI by clicking on button. It hangs only when the Webdriver is initiated. If i comment out //static WebDriver driver = new FirefoxDriver(); the program runs fine.

Categories