What I'm basically trying to do is invoke a method on an object whose class is written in a String and compiled through javax.tools.JavaCompiler
That part is "easy", I've used something similar to this: https://sites.google.com/site/malenkov/java/081217
However, the object I want to invoke a method on is a field in a different class also written in a String and compiled through JavaCompiler. What I have is:
MemoryClassLoader mcl1 = new MemoryClassLoader("Class1", Class1Content);
MemoryClassLoader mcl2 = new MemoryClassLoader("Class2", Class2Content);
Class c1 = mcl1.loadClass("Class1");
Class c2 = mcl2.loadClass("Class2");
Field f = c1.getDeclaredField("current"); //current should be of type Class2
Object obj = f.get(c2.newInstance()); //trying to cast the Field to type Class2 so I can invoke Class2 methods on it
Method m = c2.getDeclaredMethod("Class2Method");
System.out.println(m.invoke(obj));
Important code in Class1 (aka in String variable Class1Content):
Class1Content = "public MemoryClassLoader mcl = new MemoryClassLoader(\"" + "Class2" + "\", Class2Content);\n" +
"Class c = mcl.loadClass(\"" + "Class2" + "\");\n" +
"public Object current;\n" + //the object I will try to invoke a method on
"public Class1()throws Exception{\n" +
"Field f = c.getDeclaredField(\"initialState\");" + // initialState is the name of the field in Class2 I'm trying to have in Class1
"current = f.get(c.newInstance()); c.cast(current);\n" +
"}\n";
When I try to run the first block of code I get an exception at line Object state = f.get(c2.newInstance());
Exception in thread "main" java.lang.IllegalArgumentException: Can not
set java.lang.Object field Class1.current to Class2
Is there any way I can do what I'm trying to achieve or do I have to go back to the drawing board?
Thanks!
MemoryClassLoader extends ClassLoader, so your two classes are loaded with different ClassLoaders. Unless you have specified some relationship between the ClassLoaders, classes loaded by one will not be seen by the other. I would try modifying the MemoryClassLoader so that one instance can load both classes.
Related
I was looking as the question : Instantiate a class from its string name which describes how to instantiate a class when having its name. Is there a way to do it in Java? I will have the package name and class name and I need to be able to create an object having that particular name.
Two ways:
Method 1 - only for classes having a no-arg constructor
If your class has a no-arg constructor, you can get a Class object using Class.forName() and use the newInstance() method to create an instance (though beware that this method is often considered evil because it can defeat Java's checked exceptions).
For example:
Class<?> clazz = Class.forName("java.util.Date");
Object date = clazz.newInstance();
Method 2
An alternative safer approach which also works if the class doesn't have any no-arg constructors is to query your class object to get its Constructor object and call a newInstance() method on this object:
Class<?> clazz = Class.forName("com.foo.MyClass");
Constructor<?> constructor = clazz.getConstructor(String.class, Integer.class);
Object instance = constructor.newInstance("stringparam", 42);
Both methods are known as reflection. You will typically have to catch the various exceptions which can occur, including things like:
the JVM can't find or can't load your class
the class you're trying to instantiate doesn't have the right sort of constructors
the constructor itself threw an exception
the constructor you're trying to invoke isn't public
a security manager has been installed and is preventing reflection from occurring
MyClass myInstance = (MyClass) Class.forName("MyClass").newInstance();
Using newInstance() directly is deprecated as of Java 8. You need to use Class.getDeclaredConstructor(...).newInstance(...) with the corresponding exceptions.
To make it easier to get the fully qualified name of a class in order to create an instance using Class.forName(...), one could use the Class.getName() method. Something like:
class ObjectMaker {
// Constructor, fields, initialization, etc...
public Object makeObject(Class<?> clazz) {
Object o = null;
try {
o = Class.forName(clazz.getName()).newInstance();
} catch (ClassNotFoundException e) {
// There may be other exceptions to throw here,
// but I'm writing this from memory.
e.printStackTrace();
}
return o;
}
}
Then you can cast the object you get back to whatever class you pass to makeObject(...):
Data d = (Data) objectMaker.makeObject(Data.class);
use Class.forName("String name of class").newInstance();
Class.forName("A").newInstance();
This will cause class named A initialized.
Use java reflection
Creating New Objects
There is no equivalent to method invocation for constructors, because invoking a constructor is equivalent to creating a new object (to be the most precise, creating a new object involves both memory allocation and object construction). So the nearest equivalent to the previous example is to say:
import java.lang.reflect.*;
public class constructor2 {
public constructor2()
{
}
public constructor2(int a, int b)
{
System.out.println(
"a = " + a + " b = " + b);
}
public static void main(String args[])
{
try {
Class cls = Class.forName("constructor2");
Class partypes[] = new Class[2];
partypes[0] = Integer.TYPE;
partypes[1] = Integer.TYPE;
Constructor ct
= cls.getConstructor(partypes);
Object arglist[] = new Object[2];
arglist[0] = new Integer(37);
arglist[1] = new Integer(47);
Object retobj = ct.newInstance(arglist);
}
catch (Throwable e) {
System.err.println(e);
}
}
}
which finds a constructor that handles the specified parameter types and invokes it, to create a new instance of the object. The value of this approach is that it's purely dynamic, with constructor lookup and invocation at execution time, rather than at compilation time.
Class.forName("ClassName") will solve your purpose.
Class class1 = Class.forName(ClassName);
Object object1 = class1.newInstance();
String str = (String)Class.forName("java.lang.String").newInstance();
something like this should work...
String name = "Test2";//Name of the class
Class myClass = Class.forName(name);
Object o = myClass.newInstance();
I have a basic understanding of OOP concepts, but here is a question I currently have.
Say I create this object:
Test test1 = new Test();
I then call a function within this Object
test1.toString();
And when overriding that toString() method I want to get the 'test1' object name from the main class file, so I can print it out like so...
System.out.println( "This is a test " + test1.toString() );
Prints:
This is a test test1
Thank you
The name of a local variable is only meaningful at compile time. There is no way to obtain the name of a reference.
Note: the reference and the Object are two different things.
What you can do is get the name of a field, however there is no way to find from an object where the object has been assigned.
The normal way to give an Object a name, is to give a field e.g. name
Test test1 = new Test("test1");
String str = test1.getName();
For enum there is an implicit name.
enum BuySell {
Buy, Sell;
}
BuySell bs = BuySell.Buy;
String s = bs.name(); // implicitly defined for all Enum
I have a class which contains a couple different objects.
I can use getDeclaredFields to get the name list of all objects,
but I want to call a method in these objects.
How can I do that?
ClassA a = new ClassA();
Class cls = c.getClass();
Field[] fields = cls.getDeclaredFields();
for(int i = 0; i< fields.length;i++) {
System.out.println("Field = " + fields[i].toString());
System.out.prontln(fields[i].method()) // how can I call the method from object fields[i]
}
more info: the reason I use reflection is I want write a test class which can be used to test all other classes' objects are properly existing.
testclass(class a), get all objects name in the class a, and use object.exists() method to verify the existing of this object.
here is my code: I have some dialog classes, each dialog class has some menuitem class, checkbox class,textfield class, I want write a class which can be used to verify all checboxes,textfields are exsting (use checkbox.exist(), textfield.exist() ...) in the given dialog.
ToolsMenu c = new ToolsMenu();
Class cls = c.getClass();
Field[] fields = cls.getDeclaredFields();
for(int i = 0; i< fields.length;i++) {
System.out.println("Field = " + fields[i].toString());
println( fields[i].getDeclaringClass().exists()
I can use getdeclaringclass to get the field[i] class, but how can i call method exists() which is defined in checkboxes,textfields class.
You can call it with something like this:
...
Class clazz= fields[i].get(c).getClass();
clazz.getMethod("methodName").invoke(fields[i].get(c));
...
Where "methodName" is name of the method which should be called. You can also pass some parameters to the method.
I'm not sure why you are using reflection at all. You can simply do
a.field.method()
If field and its method() declare the correct access modifiers.
Ttaking the following code, (source):
class Parent {
Integer a = 1;
static Integer b = 2;
}
class Child extends Parent {
static Integer a = 41;
Integer b = 42;
}
public class Test {
public static void main(String[] args) {
Parent parent = new Parent();
Child child = new Child();
Parent yo = new Child();
System.out.format("%d %d %d %d %d %d ",
parent.a,
parent.b,
child.a,
child.b,
yo.a,
yo.b);
}
}
Why is the result of yo.a and yo.b 1 and 2 respectively? I am confused since, yo points to a Child object, it would yield 41 and 2 as the result, since in Parent, a is non-static, thus the subclass's version of a will be printed instead of the superclass version.
Variables (fields) are not overridden, neither instance variables nor class variables.
An object always has all the instance variables from all the superclasses. A class has only the static variables it defines itself, though it also can access the superclasses' (and interfaces') variables (if not private).
If you redefine a variable in a subclass, you are shadowing the original one, i.e. can't directly access it. It is still existent.
Which variable is accessible only depends on the (compile-time) type used to access it, not on the concrete object's class.
There is no dynamic binding for fields, all bindings for fields are done at compile time. That is why , it is printed fields of parent class not child. And also, static modifier does not change any thing, you can remove all static modifier and also you get the same result..
You should keep in mind that, only instance methods are dynamically binded in Java language.
Maybe this modified example helps to clarify the decision on which fields are seen or hidden, based on the compile-time type:
public static void main(String[] args) {
Parent parent = new Parent();
Child child = new Child();
Parent yo = new Child();
System.out.println(parent.a + " " + parent.b);
System.out.println(child.a + " " + child.b);
// you said it's a Parent
System.out.println(yo.a + " " + yo.b);
// but now you're saying it's a child
System.out.println(((Child)yo).a + " " + ((Child)yo).b);
// you said Child, but now you're saying it's a Parent
System.out.println(((Parent)child).a + " " + ((Parent)child).b);
}
which gives output:
1 2
41 42
1 2
41 42
1 2
The compiler is deciding based on the information you give it.
There is no instance variable a in class Child objects. Or, more precisely, the only instance variable a in Child objects is the one inherited from Parent; class Child does not define its own instance variable named a.
Classes have fields. Instance fields cannot be overridden, only hidden in sub-classes. Local variables cannot be overridden or hidden. Static fields and method are bound to the class and attempting to use an instance variable is misleading because the instance variable is ignored.
e.g.
Parent yo = null;
System.out.println(yo.a); // prints 1
BTW: It is better to use int instead of Integer unless you really need an Integer.
public static <A, B> B convert(A instance,
Class<B> targetClass) throws Exception {
B target = (B)targetClass.newInstance();
for (Field targetField : targetClass.getDeclaredFields()) {
targetField.setAccessible(true);
Field field =
instance.getClass().getDeclaredField(targetField.getName());
field.setAccessible(true);
targetField.set(target, field.get(instance));
}
return target;
}
Above is the code I get from forum, When I try to reflect an single type object it works, but when I try on the complex type which mean inside ClassA I got ClassB object, I got the java.lang.NoSuchFieldException. Can anyone help me?
You have two different classes, with, most likely, different set of fields.
So if your Class A doesn't have the same fields as your class B, then the exception is thrown.
I'd suggest using BeanUtils.copyProperties(source, target) from apache commons-beanutils. You just create the second object yourself, and pass it to the method. It will not throw an exception if fields differ.
What is your ultimate goal with this piece of code?
Two suggestion:
(1) You can drop the downcast at the first line of the method:
B target = targetClass.newInstance();
(2) Add a try catch so that you can see the name of the missing field. This will help you sort out the issue you're having:
Field field = null;
try {
field = instance.getClass().getDeclaredField(targetField.getName());
}
catch(NoSuchFieldException e) {
throw new RuntimeException("Didn't find field named '" + targetField.getName() + "'");
}
...
Another answer.
If I understand your comment correctly it seems that you have inner classes: Class B (Target) is a class that is defined inside class A. Something like this:
class A {
int n;
class B {
int n;
}
}
Although these two classes seem to have the same fields, and therefore - should not inude a field not found error - they are not.
Inner classes (unless they are defined as static) has a hidden field inserted by the compiler. This field is of the type of the outer class and points to the object that created the inner class object. When using reflection this field is exposed. As A does not have such field, an exception is raised.