Though my question seems repetition, but I am new to Reflections and could find solution to the exact problem.
I need to write a method, which any class can call to populate its data. For simplicity, I created a class say MappingHelper, with a Factory like method 'Create' which will create its own instance. I need to then populate this instance and return it.
public final Class MappingHelper{
public final Object getBENodeData(Class<?> classRef, String className){
Class myClass = Class.forName(classRef.getName());
Method method = classRef.getMethod("Create",(Class<?>[])null);
Object obj = method.invoke(null, (Object[]) null);
}
}
I need to typecast obj to same type as of 'classRef' so that I can call its instance methods.
Could someone help?
What you're trying to do is not possible with reflection and with your current setup. Even if you manage to cast the object to classRef, you wouldn't know what instance methods to call since getBENodeData presumably can take any type.
What you can do is call the method from a location where the type is known, and cast to it.
Object obj = getBENodeData(MyType1.class, MyType1.class.getName());
MyType1 myType1 = (MyType1) obj;
myType1.setId(..);
Object obj2 = getBENodeData(MyType2.class, MyType2.class.getName());
MyType2 myType2 = (MyType2) obj2;
myType2.setName(..);
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 need help I need to know if Java allows to create an object dynamically, using the value of a variable.
Example
// I have 2 classes:
public class Audit {
private Long idAudit
// constructors, get and set
}
publish class Example {
private Long idExample
// constructors, get and set
}
-------------------------------------------------- -----
// create Audit and Example class object
Audit objAudit = new Audit ();
Example objExample = new Example ();
my question is the following can you create an object either of type Audit or example using the value of a variable as I try to do in the following example. Example:
String className = "Audit"; // variable that contains the class of the Object to create
className auditObject = new ClassName (); // I use the variable classname to create the desired object
Clearly I get an error trying to create the object that way, my question is can I create an object dynamically or some other option to try to achieve what I need. Thank you
Reflection is what you are searching for
final String className = "Audit";
final Class<?> clazz = Class.forName(className);
final Object o = clazz.getConstructor().newInstance();
There are several ways you can do this.
One is called reflection, and I will let you read about it on your own.
The other one is called a factory pattern. You can create a class called ObjectFactory. in that class you will have a method public Object createObject(String type).
In the method you can check if the type you received is one of your known types, and based on the type you can create the instance of the correct class. It is better of your classes implement the same interface. Then of course your method would return the instance of that interface (or a common base class).
As I have learned, Object class is a top level class and it is a parent of all classes. If we do not know a type of class at compile time, we can assign it to a object of Object class.
I am trying to clone a object to object of a Object class. Also trying to get the object from HashMap which is already instantiated. I am having problem in doing this. Can you figure out it and explain the right ways of doing it? I have commented in which lines I get compile time error. My main doubts are:
If a parent class' object can be used for cloning, then it must work with Object class too as it is top level class.
And how to access object from map and use it for method call and cloning.
Code:
import java.util.HashMap;
import java.util.Map;
class Sample {
public void call(){
}
}
class Question extends Sample implements Cloneable {
#Override
public void call(){
System.out.println("hello");
}
#Override
public Object clone()throws CloneNotSupportedException{
return super.clone();
}
public static void main(String args[]) throws CloneNotSupportedException{
Map<Character,Object> map=new HashMap();
Question s=new Question();
Sample q=new Question();
Sample cl=(Question)s.clone();
Object ob=(Question)s.clone();//no compile time error
map.put('o',s);
s.call();//hello
q.call();//hello
cl.call();/hello
ob.call();//Compile time error: cannot find symbol call
map.get('o').call();//Compile time error: cannot find symbol call
Object obj=(Question) (map.get('o')).clone();// Compile time error: clone has protected access in Object
}
}
The following line can be simplified
Object ob=(Question)s.clone();//no compile time error
// the cast is unnecessary:
Object ob= s.clone();
But like you said, the ob will still contain a Question object. The problem is that once you start using this ob reference, java just knows it contains a value of Object, or a subclass of it. So for java ob could be a Number or a String or an Airplane.
Object ob = "airplane";
Once it gets to the line ob.call() it refuses. Because it's not sure that the ob object has a call method. For example, if it was a String or a Number it would be impossible.
For this reason you have to perform a simple cast first:
((Question)ob).call();
// or
((Sample)ob).call();
Just let java know that it's an object with a call method.
The map#call issue has the same reasoning:
map.get('o').call();
//could be any of these
((Sample)map.get('o')).call();
((Question)map.get('o')).call();
But the last problem is more tricky. Actually a lot gets clear when you split up your statement in multiple lines:
Object obj=(Question) (map.get('o')).clone();
// would be the same like writing:
Object value = map.get('o');
Object value2 = value.clone();
Object obj = (Question) value2; // The (Question) cast is actually unnecessary.
The problem is in the value.clone() step. It is true that the Object class has a clone method, but it's marked as protected whereas the clone methods in your Question and Sample classes are public.
So in short Object#clone is not accessible ; Sample#clone and Question#clone are accessible.
// so you want this:
Object value = map.get('o');
Object value2 = ((Question)value).clone(); // add a cast here
Object obj = value2;
If you prefer to do it all in 1 line:
Object obj=((Question) (map.get('o'))).clone();
My code looks like the following:
class MyObject {
MyField f = new MyField();
}
class MyField {
public void greatMethod();
}
Is there a way to invoke the greatMethod() using reflection on a object of the class MyObject?
I tried the following:
Field f = myObject.getClass().getDeclaredField("f");
Method myMethod = f.getDeclaringClass().getDeclaredMethod("greatMethod", new Class[]{});
myMethod.invoke(f);
But instead it is trying to call greatMethod() on my myObject directly and not on the field f in it. Is there a way to achieve this without need to modify the MyObject class (so that it would implement a method which calls the appropriate method on f).
You were close yourself, you just need to get the declared method and invoke it on the instance of the field that is containted within your object instance, instead of the field, like below
// obtain an object instance
MyObject myObjectInstance = new MyObject();
// get the field definition
Field fieldDefinition = myObjectInstance.getClass().getDeclaredField("f");
// make it accessible
fieldDefinition.setAccessible(true);
// obtain the field value from the object instance
Object fieldValue = fieldDefinition.get(myObjectInstance);
// get declared method
Method myMethod =fieldValue.getClass().getDeclaredMethod("greatMethod", new Class[]{});
// invoke method on the instance of the field from yor object instance
myMethod.invoke(fieldValue);
I'm trying to send a list of objects over a socket.
The objects in the list contain an unserializable object and so cannot be sent, however it's base class is fully serializable and contains all the fields I need.
So what I'm trying to do is convert the list to a list of the base class. The only way I could think so do this is as follows:
// subClassList is an ArrayList<SubClass>
ArrayList<BaseClass> baseClassList = new ArrayList<BaseClass>();
for(SubClass subClass: subClassList) {
// cast to the base class
baseClassList.add((BaseClass)subClass);
}
This however doesn't work as I still get the same NotSerializableException exception. From debugging the code I can see that the new list is still a list of the sub class, even though it has been cast.
Is there a way to achieve what I'm trying to do?
Casting a reference doesn't change the type of the actual object:
String foo = "hello";
Object bar = (Object) foo;
System.out.println(bar); // Hello
System.out.println(bar.getClass()); // java.lang.String
If you want to only have an instance of the base class, you could create a constructor in the base class which simply creates a new instance of the base class given an instance of it, without trying to perform any sort of deep copy:
public BaseClass(BaseClass other) {
this.x = other.x;
this.y = other.y;
this.z = other.z;
// etc
}
Then in the code you've shown:
baseClass.add(new BaseClass(subClass));
Your approach doesn't work because even though you can use a super class variable to refer to the subclass object, the object itself is of the sub class type.
The best way is to either serialize the subclass, or extract the data from subclass and write them to a newly created super class. Just have a static utility method to do the conversion build into the sub class....
Casting doesn't change the type of an object. It allows getting a reference of another type for the object iff the object has this other type. Upcasting is never necessary. You can use
String s = "hello";
Object o = s; // no cast needed
Downcasting is necessary, and will only work if the object has the type you cast it to:
Object o = "hello";
Object o2 = Integer.valueOf(5);
String s = (String) o; // OK because o is a String
String s2 = (String) o2; // ClassCastException, because o2 is not a String.
So, your code is equivalent to
ArrayList<BaseClass> baseClassList = new ArrayList<BaseClass>();
for(SubClass subClass: subClassList) {
// cast to the base class
baseClassList.add(subClass);
}
You must create a new object of the new type, using a copy constructor:
ArrayList<BaseClass> baseClassList = new ArrayList<BaseClass>();
for(SubClass subClass: subClassList) {
// cast to the base class
baseClassList.add(new BaseClass(subClass));
}
Your question embodies a contradiction in terms. If the base class is Serializable so are all its derived classes. If your derived class contains references to non-serializable objects, just make them transient.