Issue while compiling a hello world class using Javassist - java

I am using Javassist to write a HelloWorld class with main method. When I compile , I get an error as below. I am not sure what's wrong with String[] args in the main method ?
javassist.CannotCompileException: [source error] syntax error near "ng[] args)"
at javassist.CtNewMethod.make(CtNewMethod.java:78)
at javassist.CtNewMethod.make(CtNewMethod.java:44)
This is my code
public void createClass() {
ClassPool cp = ClassPool.getDefault();
CtClass ct = cp.makeClass("HelloClass");
try {
CtMethod m = CtNewMethod.make("public void sayHello() { System.out.println(\"Hello World\");}",ct);
ct.addMethod(m);
String str="public static void main(String[] args)";
CtMethod n = CtNewMethod.make(str,ct);
n.setBody("HelloClass a = new HelloClass();a.sayHello();");
ct.addMethod(n);
ct.writeFile();
} catch (CannotCompileException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
public static void main(String[] args) {
JavaAssistExample inject = new JavaAssistExample();
inject.createClass();
}

As the javadoc for CtNewMethod states
The source code must include not only the method body but the whole declaration
It must therefore contain the {}, like
String str = "public static void main(String[] args){}";
However, two more things will give you problems.
First, you don't have a default (or a no arg) constructor. Add one
ct.addConstructor(CtNewConstructor.defaultConstructor(ct));
Second, the CtMethod#setBody(..) method completely replaces the method body. So you can't do what you are doing. If you want all of those calls, you'll need to put them together
n.setBody("{HelloClass a = new HelloClass();a.sayHello();}");

Related

Java Reflection : Initialize object using interface but using String value for class name

Lets say I have the following setup
an interface
public interface TestInterface {
public void draw();
}
and two implementations
public class Square implements TestInterface {
#Override
public void draw() {
System.out.println("Square");
}
}
and
public class Circle implements TestInterface {
#Override
public void draw() {
System.out.println("Circle");
}
}
Now I can easily do
TestInterface a = new Square();
a.draw();
and I correctly get Square. Next, I wanted to try out reflection.
Class<?> clazz = null;
try {
clazz = Class.forName(className);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Constructor<?> constructor = null;
try {
constructor = clazz.getConstructor();
} catch (NoSuchMethodException | SecurityException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
Object instance = null;
try {
instance = constructor.newInstance();
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException
| InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Method method = null;
try {
method = instance.getClass().getMethod(methodName);
} catch (NoSuchMethodException | SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
method.invoke(instance);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
and for className as some.package.Square and methodName as draw I again get Square. Which is correct.
The problem is that my application has access to the interface but not the actual implementations. Hence I know which methods to invoke, but I have to specify the implemented classes as well and I dont know which package they may reside in. What if I only know the name of the class but not the package?
Is there a way where I can still use the initialization form of
TestInterface a = new <some_parameter>();
a.draw();
Is there a way to generalize it? Or is the approach using reflection that I showed above, the only way to achieve something like this? Lastly, would it make any difference if I used an abstract class instead of an interface?
You need to pass:
#param className the fully qualified name of the desired class.
When you have for example three class with the Same name but in diferent packages
--package1
----Test
--package2
----Test
Main
Test
And in Main you have:
public static void main(String[] args) throws UnsupportedEncodingException {
Class<?> clazz = null;
try {
clazz = Class.forName("Test");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
It will call the one that is level of Main. For calling the others you will need to pass the fully quallifed name.
clazz = Class.forName("package1.Test");
clazz = Class.forName("package2.Test");
What if I only know the name of the class but not the package? So you need to know in what level you want. Because as you know that different packages the classes can have same names. So which Class do you need if you have that issue.
You have to know the full name of the class. Only the name of the class is not enough to load it in the memory and to use it through reflection. However, you can determine the implementations of your interface using the reflections library.
Maybe this discussion thread can help you: How can I get a list of all the implementations of an interface programmatically in Java?

LogRecord gives "<init>" as source method name [duplicate]

What does <init> signify in a Java exception?
For example:
BlahBlahException...
at java.io.FileInputStream.<init>(FileInputStream.java:20)
That the exception is thrown in the construction of the object, there are two options:
in the constructor
while initializing variables
Check out this demo I wrote: http://ideone.com/Mm5w5
class Main
{
public static void main (String[] args) throws java.lang.Exception
{
try
{ new Test(); } catch (Exception e) { e.printStackTrace(); }
try
{ new Test2(); } catch (Exception e) { e.printStackTrace(); }
try
{ new Test3(); } catch (Exception e) { e.printStackTrace(); }
}
static class Test
{
Object obj = getObject();
Object getObject()
{ throw new RuntimeException("getObject"); }
}
static class Test2
{
Test2()
{
throw new RuntimeException("constructor");
}
}
static class Test3
{
Object obj1 = null;
String str = obj1.toString();
}
}
Produces:
java.lang.RuntimeException: getObject
at Main$Test.getObject(Main.java:24)
at Main$Test.<init>(Main.java:22)
at Main.main(Main.java:9)
java.lang.RuntimeException: constructor
at Main$Test2.<init>(Main.java:31)
at Main.main(Main.java:12)
java.lang.NullPointerException
at Main$Test3.<init>(Main.java:38)
at Main.main(Main.java:15)
<init>
is called
Instance Initialization method
which is created by your java compiler from the constructor you have defined. Though it is not valid method definition, your JVM expects this and anything that you put in the constructor will be executed in method. So when you an exception with from , you can be sure that it is from the constructor of the executed java class. Read more about this on Bill venner's design technique articles on Object Initialization.

Dynamically load a class in java

Here is my classes.
package com.psu.janibot;
public class Janibot implements Runnable {
public void move() {
System.out.println("move");
}
#Override
public void run() {
}
// main method
public static void main(String[] args) {
try {
Janibot janibot = (Janibot) Class.forName("Janitor").newInstance();
janibot.run();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
import com.psu.janibot.Janibot;
public class Janitor extends Janibot {
public void run() {
move();
}
}
package com.psu.janibot;
public class Janitor2 extends Janibot{
public void run() {
move();
}
}
if i type >java Janitor it will run the Janitor class
if i type >java Janitor2 it will run the Janitor2 class
I want to do is to run Janitor or Janitor2 without typing the class name in forName method like this Janibot janibot = (Janibot) Class.forName("Janitor").newInstance();
Class.forName() takes a String as a parameter, so you need to pass it somehow, so I presume you mean not hard coded.
Pass the String in as the arguments to the program and read them from the args array
java Janibot Janitor
....
Class.forName(args[0]).newInstance()
Other options exist such as read from file, using a Scanner, etc.

In Java Invoking a method using Reflection is not able to find method, when method has baseclass as parameter

Below is the code snippet, I am trying to invoke the usingClass method using REFLECTION. Calling the usingClass() method directly(w/o reflection) works when I pass an object of type Child, though when I try to achieve the same thing using Reflection it throws NoSuchMethodFoundException. Would like to understand if I am missing something or is there any logic behind this? Please help
package Reflection;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class TestMethodInvocation {
/**
* #param args
*/
public static void main(String[] args) {
TestMethodInvocation test = new TestMethodInvocation();
Child child = new Child();
Parent parent = (Parent)child;
Class<? extends Parent> argClassType = parent.getClass();
Class<? extends TestMethodInvocation> thisClassType = test.getClass();
test.usingClass(child);
Method methodToCall;
try {
methodToCall = thisClassType.getDeclaredMethod("usingClass", argClassType);
methodToCall.invoke(test, parent);
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void usingClass(Parent p){
System.out.println("UsingClass: " + p.getClass());
}
}
Output is as below.
UsingClass: class Reflection.Child
java.lang.NoSuchMethodException: Reflection.TestMethodInvocation.usingClass(Reflection.Child)
at java.lang.Class.getDeclaredMethod(Unknown Source)
at Reflection.TestMethodInvocation.main(TestMethodInvocation.java:20)
The reason your code does not work is that getClass() is dynamically bound. Casting to Parent does not affect the runtime type of your object and so the variables child and parent contain the same class object.
Unless you explicitly query your instance for its parent class via getGenericSuperclass() or something similar, you will have to use the static way mentioned by dystroy.
You should use
methodToCall = thisClassType.getDeclaredMethod("usingClass", Parent.class);
because the precise exact class of parent (which is Child), is used at runtime and the type of the variable holding it changes nothing.
Another (too heavy) way to solve it would be :
Class<? extends Parent> argClassType2 = (new Parent()).getClass();
...
methodToCall = thisClassType.getDeclaredMethod("usingClass", argClassType2);

How to load a Java class dynamically on android/dalvik?

I'm wondering if and how one can load dex or class files dynamically
in dalvik, some quick'n'dirty test function I wrote was this:
public void testLoader() {
InputStream in;
int len;
byte[] data = new byte[2048];
try {
in = context.getAssets().open("f.dex");
len = in.read(data);
in.close();
DexFile d;
Class c = defineClass("net.webvm.FooImpl", data, 0, len);
Foo foo = (Foo)c.newInstance();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
whereas the Foo interface is this
public interface Foo {
int get42();
}
and f.dex contains some dx'ed implementation of that interface:
public class FooImpl implements Foo {
public int get42() {
return 42;
}
}
The above test driver throws at defineClass() and it doesn't
work and I investigated the dalvik code and found this:
http://www.google.com/codesearch/p?hl=en#atE6BTe41-M/vm/Jni.c&q=Jni.c...
So I'm wondering if anyone can enlighten me if this is possible in
some other way or not supposed to be possible. If it is not possible,
can anyone provide reasons why this is not possible?
There's an example of DexClassLoader in the Dalvik test suite. It accesses the classloader reflectively, but if you're building against the Android SDK you can just do this:
String jarFile = "path/to/jarfile.jar";
DexClassLoader classLoader = new DexClassLoader(
jarFile, "/tmp", null, getClass().getClassLoader());
Class<?> myClass = classLoader.loadClass("MyClass");
For this to work, the jar file should contain an entry named classes.dex. You can create such a jar with the dx tool that ships with your SDK.

Categories

Resources