Inlining java code using eclipse jdt/ast - java

I'm trying to inline java method using eclipse jdt/ast.
For example, I'd like to make this code
class Hello {
static void hello() {
System.out.println("hello");
}
public static void main(String[] args) {
hello();
System.out.println("z");
hello();
System.out.println("h");
hello();
}
}
into this.
class Hello {
public static void main(String[] args) {
System.out.println("hello");
System.out.println("z");
System.out.println("hello");
System.out.println("h");
System.out.println("hello");
}
}
I could get the body block of hello() method stored in Block bl.
I also have the body block of main() method stored in Block block, and I could delete hello(); ExpressionStatements in the block.
Then, I need to insert the Block bl to where the hello(); is invoked.
I tried
block.statements().add(position, bl.getAST());
and
block.statements().add(position, bl);
where position is the location of hello() method in statements(), but both of them raises an error.
What might be wrong? As Block is Statement, I guess one can insert Block in Block#statements().
ADDED
Based on sevenforce answer, I could get the block inserted, but I have the { and } included.
class Hello {
public static void main(String[] args) {
{
System.out.println("hello");
}
System.out.println("z");
{
System.out.println("hello");
}
System.out.println("h");
{
System.out.println("hello");
}
}
}
Is there any way to remove them?
ADDED2
With this code:
ASTNode singleStmt = (ASTNode) bl.statements().get(0);
block.statements().add(position, ASTNode.copySubtree(bl.getAST(), singleStmt));
It shows only the first statement in hello() method. For example, with
static void hello() {
System.out.println("hello");
System.out.println("hello2");
}
I have only System.out.println("hello"); inlined.

There are several reasons for add throwing an exception.
Normally the specific exception should give you a hint. E.g. the node to be added must be in the same AST.
In your case I'd guess, that you attempt to add the same block object, which is already used in the MethodDeclaration node of hello() and each node is allowed to have just one parent.
A possible solution to that is copying the node:
block.statements().add(position, ASTNode.copySubtree(bl.getAST(), bl));
For extracting single statements the following should work:
ASTNode singleStmt = (ASTNode) bl.statements().get(0);
block.statements().add(position, ASTNode.copySubtree(bl.getAST(), singleStmt));
To add all statements from the block you can just loop over:
for (int i = 0; i < bl.statements().size(); i++) {
ASTNode singleStmt = (ASTNode) bl.statements().get(i);
block.statements().add(position + i,
ASTNode.copySubtree(bl.getAST(), singleStmt));
}

Instead of adding to the block you might think of replacing the method invocation.
final ASTRewrite rewriter = ASTRewrite.create(compilationUnit.getAST());
rewriter.replace(methodInvocationNode, blockNode, null);

Related

What does double initialization mean in Java methods

I only use double initialization in java for classes
ex:new ArrayList(){{add()}}
But I recently wrote a code as below by mistake and JVM did not get angry for my mistake.
public void test(){
{
{
....
}
}
}
After that made a simple example and saw the following but still didn' t understand anything expect order of running statements.
public class HelloWorld{
public static void main(String []args){
HelloWorld hw=new HelloWorld();
hw.test1();
System.out.println("----------");
hw.test2();
}
public void test1(){
{
{
System.out.println("1");
}
System.out.println("2");
}
System.out.println("3");
}
public void test2(){
System.out.println("a");
{
System.out.println("b");
{
System.out.println("c");
}
}
}
}
Result:
1
2
3
----------
a
b
c
So my question is that what does double or triple etc initializations mean in Java?
This is not double brace initilization. This is a block statement. From the docs:
A block is a group of zero or more statements between balanced braces and can be used anywhere a single statement is allowed.
A block statement encloses the statements within it in a different scope. So if you did:
public static int foo() {
{
int foo = 0;
}
return foo;
}
foo would not be in scope in the line return foo; and you would get an error
In your code, these nested blocks make no difference, as you are just printing, but each block will have a different scope

Static nested class can't use print

I have a static nested class StatClass, the file name is Example.java
class OuterClass
{
public static class StatClass
{
System.out.println("Hello"); // This line doesn't work
void pow()
{ System.out.println("Hello W");}
}
}
public class Example
{
public static void main(String[] args)
{
OuterClass.StatClass statInner1 = new OuterClass.StatClass();
statInner1.pow();
}
}
The first println statement doesn't work in the static nested class i.e if its removed then the program compiles, although the println statement works when inside the pow() method, couldn't understand this
Like in a normal class, you can't just put statements inside a class. You could put it in an initializer-block like this:
{
System.out.println("Hello");
}
Or in a constructor, or a method. Whatever you want.
I am just uniting the two answers so far:
one option is a static block
class OuterClass
{
public static class StatClass
{
static {
System.out.println("Hello"); // This line doesn't work
}
void pow()
{ System.out.println("Hello W");}
}
}
public class Example
{
public static void main(String[] args)
{
OuterClass.StatClass statInner1 = new OuterClass.StatClass();
statInner1.pow();
OuterClass.StatClass statInner2 = new OuterClass.StatClass();
statInner2.pow();
}
}
The main difference is how the block is executed by the JVM. In the first case it is executed once during the class initialization. Then the output will be :
Hello
Hello W
Hello W
Another option is initializer block in which case the code will be executed on each instantiation of the class.
class OuterClass
{
public static class StatClass
{
{
System.out.println("Hello"); // This line doesn't work
}
void pow()
{ System.out.println("Hello W");}
}
}
public class Example
{
public static void main(String[] args)
{
OuterClass.StatClass statInner1 = new OuterClass.StatClass();
statInner1.pow();
OuterClass.StatClass statInner2 = new OuterClass.StatClass();
statInner2.pow();
}
}
Then the output will be:
Hello Hello W Hello Hello W
Following statement is outside method that wont work
System.out.println("Hello"); // This line doesn't work
You have to wrap these statements inside static block as follows
static{
System.out.println("Hello"); // This line will work
}
this block will execute when JVM create static instances.
System.out.println("Hello");
This does not work because,the control never goes to the line. Unless you define this inside a function and use the object you created to call it OR use the static block which does not require an object to call it OR an initializer block, it will not work. I hope that helps

How to execute a particular function before main() in C and JAVA ?

I want to execute one function before main function in C and JAVA language.
I know one way that is, by using #pragma directive in C language. Is there any other way to do that in both languages?
I can think of two simple(-ish) ways to do it in Java:
Method #1 - static initializers
For example:
public class Test {
static {
System.err.println("Static initializer first");
}
public static void main(String[] args) {
System.err.println("In main");
}
}
Method #2 - A proxy main.
public class ProxyMain {
public static void main(String[] args) {
String classname = args[0];
// Do some other stuff.
// Load the class
// Reflectively find the 'public static void main(String[])' method
// Reflectively invoke it with the rest of the args.
}
}
You then launch this as:
java <jvm-options> ... ProxyMain <real-Main> arg ...
There is also a 3rd method, but it requires some "extreme measures". Basically you have to create your own JVM launcher that uses a different scheme for starting the application. Have this do the extra stuff before loading the entry point class and calling its main method. (Or do something different entirely.)
You could even replace the default classloader; e.g. How to change default class loader in Java?
in java you can use static block
public class JavaApplication2 {
static {
System.out.println("in static ");
}
public static void main(String[] args) {
System.out.println("in main ");
}
}
As an extension to the C standard gcc provides the function attribute constructor which allows functions to be called before main().
For details please see here (scroll down). Also this SO question and its answers help on this.
Try combining a static block and a static method containing what you want executed before your main method.
package test;
public class Main {
static {
beforeMain();
}
public static void main(String[] args) {
System.out.println("after");
}
private static void beforeMain() {
System.out.println("before");
}
}
Output:
before
after
It could be the first thing you call from your main function. That way it will run before your "real" main function.
Use that method(what you want to run before main method) as your main method.
Then it is so simple
Or use static block before main()
In java, execution of any other method is possible before main() method execution. We need a static initializer block for that. It starts with a static keyword.
Like:
static {
// statements
}
Now try to understand with actual code implementation.
public class BefourMain {
static int sum;
static {
sum = add(4,5,6);
System.out.println("Calling add() method: " + sum);
System.out.println("\ncalling main");
main(null);
System.out.println("Main end\n");
System.out.println("Now JVM calling main()\n");
}
public static void main(String[] args) {
int sum = add(1,2,3);
System.out.println(sum);
}
static int add(int a, int b, int c) {
return a + b + c;
}
}
Now try to understand with actual code implementation.
When we start executing this code the static initializer block will start execution first, in the static initializer block we are calling the add() method and storing the value in the static variable, and printing it. Next, we are calling the main() method, which will execute. when the static initializer block execution will complete JVM will call the main() method again.
Output
Output of the above code

Calling the static methods of a java/groovy object using reflection

I'm working on a groovy unit-testing class that contains a collection of rules for whether or not the contents of a file are correctly formatted. (Not using a proper rules engine, it just takes advantage of Groovy's assertion capabilities to do validation in a way that vaguely resembles what a rules engine would do.) I was thinking that I could create a method called FireAllRules that looks like this:
public static void FireAllRules(File file)
{
for(def method in Class.getMethods)
{
if(method.name.indexOf("rule" == 0) method.invoke(file);
}
}
All the methods that I want the loop to pick up on are static, and I noticed during the debugging process none of my rule methods are included in the Class.getMethods() enumeration. Ideally, I would like to only loop over the methods that I personally wrote into the class rather than sorting through dozens of uninteresting methods that come in along with java.Object. Is there a way to use reflection to iterate over these static methods at runtime?
Given:
class Test {
public static testThis() {
println "Called testThis"
}
public static woo() {
println "Called woo"
}
public static testOther() {
println "Called testOther"
}
}
You can do:
Test.metaClass.methods.grep { it.static && it.name.startsWith( 'test' ) }.each {
it.invoke( Test )
}
To print:
Called testOther
Called testThis
A more generic method to execute the static test methods of a class would be:
def invokeClass( clazz ) {
clazz.metaClass.methods.grep { it.static && it.name.startsWith( 'test' ) }.each {
it.invoke( clazz )
}
}
invokeClass( Test )
Static methods are included in the methods returned by getMethods(). Your issue might be method.name.indexOf("rule" == 0). This should be method.name.indexOf("rule") == 0, or better yet method.name.startsWith("rule").
Also, are your rule methods public? If not, you can use getDeclaredMethods(). To invoke them, you will have to call setAccessible() first.
The java version would be something like this (I've removed the imports and exceptions for clarity).
public class FindAndRunStaticMethods {
public static void main(String[] args) {
fireAllRules();
}
public static void fireAllRules() {
for(Method method : StaticMethodClass.class.getDeclaredMethods()) {
findAndRunRules(method);
}
}
private static void findAndRunRules(Method method) {
if (!Modifier.isStatic(method.getModifiers())) return;
if (!method.getName().startsWith("rule")) return;
if (!method.getReturnType().equals(Void.TYPE)) return;
Class[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length != 1) return;
if (!parameterTypes[0].equals(File.class)) return;
method.invoke(null, new File("dummy"));
}
}
A sample test class could look like this
public class StaticMethodClass {
public static void ruleHere(File x) { System.out.println("should print"); }
public static void ruleRun(File x) { System.out.println("should print"); }
public void ruleNotSelected() { System.out.println("not run"); }
}

Java: Can't access variable?

So i'm having a bit of a problem trying to compare two strings declared in the Main class. I've messed around with it and i really can't get it to work! The problem is in the if() statement where i compare the variables...
public class Main {
public String oldContent = "";
public String newContent = "";
public static void main(String[] args) throws InterruptedException {
Main downloadPage = new Main();
downloadPage.downloadPage();
oldContent = newContent;
for (;;) {
downloadPage.downloadPage();
if (!oldContent.equals(newContent)) { // Problem
System.out.println("updated!");
break;
}
Thread.currentThread().sleep(3000);
}
}
private void downloadPage() {
// Code to download a page and put the content in newContent.
}
}
the variables are instance members, whereas the for happens in a static method.
try moving the actual function to an instance method (not static), or conversely make the data members static as well.
You may use name of the object you have created (downloadPage ) to access to the parameters:
in the main finction use following instead of parameter names only:
downloadPage.oldContent
downloadPage.newContent
The variables are inside the Main object:
public static void main(String[] args) throws InterruptedException {
Main downloadPage = new Main();
downloadPage.downloadPage(); // Access them like you accessed the method
downloadPage.oldContent = downloadPage.newContent;
for (;;) {
downloadPage.downloadPage();
if (!downloadPage.oldContent.equals(downloadPage.newContent)) {
System.out.println("updated!");
break;
}
Thread.currentThread().sleep(3000);
}
}
Do consider using getters and setters instead of exposing the fields.
See non static/ static variable error

Categories

Resources