I have a 2 POJO classes with getters and setters,now i am trying to get all the class instance variables of that class.
I got to know that we can use reflection how to do it?
This is my POJO Class which will extend my reflection class.
class Details{
private int age;
private String name;
}
Reflection class is like this:
class Reflection{
public String toString(){
return all the fields of that class
}
You could do something like this:
public void printFields(Object obj) throws Exception {
Class<?> objClass = obj.getClass();
Field[] fields = objClass.getFields();
for(Field field : fields) {
String name = field.getName();
Object value = field.get(obj);
System.out.println(name + ": " + value.toString());
}
}
This would only print the public fields, to print private fields use class.getDeclaredFields recursively.
Or if you would extend the class:
public String toString() {
try {
StringBuffer sb = new StringBuffer();
Class<?> objClass = this.getClass();
Field[] fields = objClass.getFields();
for(Field field : fields) {
String name = field.getName();
Object value = field.get(this);
sb.append(name + ": " + value.toString() + "\n");
}
return sb.toString();
} catch(Exception e) {
e.printStackTrace();
return null;
}
}
Adding one more line to the above code. If you want to access the private properties of the class use below line
field.setAccessible(true);
ClassLoader classLoader = Main.class.getClassLoader();
try {
Class cls = classLoader.loadClass("com.example.Example");
Object clsObject = cls.newInstance();
Field[] fields = cls.getFields();
for (Field field : fields) {
String name = field.getName();
Object value = field.get(clsObject);
System.out.println("Name : "+name+" Value : "+value);
}
System.out.println(cls.getName());
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
The resolution code or answer which mentioned above has one issue.
To access the value of a private varible their access type must be set to true
Field[] fields = objClass.getDeclaredFields();
for (Field field : fields) {
NotNull notNull = field.getAnnotation(NotNull.class);
field.setAccessible(true);
}
else it will throw java.lang.IllegalAccessException. Class Reflection can not access a member of class Details with modifiers "private"
Related
Why the value is null for the variable2 , if I instantiate the class using Reflection API?
Where, the value of Variable1 is returned correctly as per the set and here I instantiated the object normally.
How can I obtain the value of variable2 using ReflectionAPI?
package com.OP.app;
public class Bean {
private String variable1;
private String variable2;
public String getVariable1() {
return variable1;
}
public void setVariable1(String variable1) {
this.variable1 = variable1;
}
public String getVariable2() {
return variable2;
}
public void setVariable2(String variable2) {
this.variable2 = variable2;
}
}
package com.OP.app;
import java.lang.reflect.Method;
public class ObjectCall {
public static void main(String []args){
Bean beanobject = new Bean();
beanobject.setVariable1("Ram");
beanobject.setVariable2("Rakesh");
System.out.println(beanobject.getVariable1());
String path = "com.OP.app.Bean";
Class<?> newClass;
try {
newClass = Class.forName(path);
Object obj = newClass.newInstance();
String getMethod = "getVariable2";
Method getNameMethod = obj.getClass().getMethod(getMethod);
String name = (String) getNameMethod.invoke(obj);
System.out.println(name);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} // convert string classname to class
}
}
Output :
Ram
null
That is beause you are invoking the method on newly created object (e.g. obj) which does not have values set for variable1 and variable2, e.g.:
Object obj = newClass.newInstance();
The above will create a new Object of Bean class with null values for variable1 and variable2. If you want to print the values set in beanobject method then you need to invoke the getter method with beanobject. i.e. change
String name = (String) getNameMethod.invoke(obj);
to
String name = (String) getNameMethod.invoke(beanobject);
You create a new instance of the target class where no values set.
Object obj = newClass.newInstance();
Method getNameMethod = obj.getClass().getMethod(getMethod);
Change this line and it should work:
Method getNameMethod = beanobject.getClass().getMethod(getMethod);
Additional:
Your naming of variables isn't very good. I would refactoring the code to this for better reading:
public static void main(String[] args) {
Bean beanInstance = new Bean();
beanInstance.setVariable1("Ram");
beanInstance.setVariable2("Rakesh");
System.out.println("Value 1 of fresh bean instance: " + beanInstance.getVariable1());
String beanType = Bean.class.getName();
Class<?> beanClazz;
try {
beanClazz = Class.forName(beanType);
String getterMethodName = "getVariable2";
Method getterMethod = beanClazz.getMethod(getterMethodName);
Object returnValue = getterMethod.invoke(beanInstance);
System.out.println("Value 2 of by reflection loaded bean instance: " + String.valueOf(returnValue));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} // convert string classname to class
}
what am i missing here?
I get the exception: java.lang.IllegalArgumentException: object is not an instance of declaring class
public boolean onSave(Object entity,Serializable id,Object[] state, String[] propertyNames, Type[] types) {
Class<?> clazz=entity.getClass();
System.out.println(" Clazzz is:"+clazz);
Method[] methods = clazz.getMethods();
for(Method method : methods){
if(method.getName().startsWith("get") && String.class.equals(method.getReturnType())){
System.out.println("getter: " + method);
try {
String s=(String) method.invoke(clazz,(Object[]) null); //java.lang.IllegalArgumentException: object is not an instance of declaring class
System.out.println(" value in s is:"+s);
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
You need to write
String s=(String) method.invoke(entity, (Object[]) null);
The first parameter of Method.invoke is null for static methods or the object on which the method should be invoked.
I am trying to fetch Field name as well as field value using Reflection.
I am passing dynamic classes as per operation needed.
I have made a method to fetch field name and value, i am getting field name but not getting field value.
when I am using following code it gives me an error java.lang.IllegalAccessException stating that can not access private member of class.
Following is my UPDATED code :
public String SerializeCommand(ICommand command){
StringBuilder command_text = new StringBuilder();
Field [] f = command.getClass().getDeclaredFields();
for(Field field : f){
field.setAccessible(true);
command_text.append(field.getName() + ",");
try {
System.out.println(field.get(command.getClass()));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
return command_text.toString();
}
Here ICommand is a class name for it, suppose if operation is add then add class will be passed.
Any Idea what to do to solve this problem.
Instead of command.getClass() pass the object of command class. The value contains by object not by class
Please try this code.
public String SerializeCommand(ICommand command){
StringBuilder command_text = new StringBuilder();
Field [] f = command.getClass().getDeclaredFields();
try{
for(Field field : f){
field.setAccessible(true);
command_text.append(field.getName() + ",");
System.out.println("Value :: " + field.get(command));
}
}catch(IllegalArgumentException e){
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return command_text.toString();
}
Java also takes care of not being able to access private members, even when doing it via reflection. But constructors, methods, and fields are AccessibleObjects, which provides a method to flag the member as being accessible although it might be private:
field.setAccessible(true);
Afterwards you can read it and even set a new value on it.
An edit to make it clear. Consider the following simple record class:
public class Record {
private int length;
private String name;
public Record(int length, String name) {
this.length = length;
this.name = name;
}
public int getLength() { return length; }
public String getName() { return name; }
}
And now let's write a reflection test program:
public class ReflectionTest {
public static void main(String[] args) throws Exception {
Record record = new Record(42, "42");
Field[] fields = record.getClass().getDeclaredFields();
for (Field field : fields) {
System.out.println(field.getName() + " => " + field.get(record));
}
}
}
This will result in an IllegalAccessException, as the private fields cannot be accessed. Now change the foreach loop a little:
for (Field field : fields) {
field.setAccessible(true);
System.out.println(field.getName() + " => " + field.get(record));
}
This time you will see expected output:
length => 42
name => 42
Your mistake also was to call the get method on the class and not on the object. This would be like this little modification:
for (Field field : fields) {
field.setAccessible(true);
System.out.println(field.getName() + " => " + field.get(record.getClass()));
}
This time you will see an IllegalArgumentException (not an IllegalAccessException).
I have this method that is supposed to set a field in the given class to the specified value:
public void setValue(Class<?> instance, String fieldName, Object value) {
try {
Field field = instance.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(instance, value);
} catch (NoSuchFieldException e) {
if (instance.getSuperclass() != null) {
setValue(instance.getSuperclass(), fieldName, value);
} else {
try {
throw new NoSuchFieldException("Could not find field " + fieldName + " in any class.");
} catch (NoSuchFieldException ex) {
ex.printStackTrace();
e.printStackTrace();
}
}
} catch (SecurityException | IllegalArgumentException | IllegalAccessException exx) {
exx.printStackTrace();
}
}
However, it gives this error when I try to set any field:
java.lang.IllegalArgumentException: Can not set float field net.minecraft.server.v1_6_R2.Packet43SetExperience.a to java.lang.Class
I have tried using an Object(instead of an Class) but it never finds the field that I need, it only finds the fields that the Object class has.
I also tried using generics, but the same thing happened.
You need to have the actual instance of the object to pass in to the set method, not the Class object itself. Add a parameter to your method to take the actual instance:
public void setValue(Class<?> clazz, Object instance, String fieldName, Object value) {
I renamed the Class<?> parameter clazz for clarity, so it would need to be changed elsewhere:
Field field = clazz.getDeclaredField(fieldName);
And pass the actual instance to set:
field.set(instance, value);
I use this method to remove Html code from my Strings in classes:
public void filterStrings() {
Field[] fields = this.getClass().getDeclaredFields();
if (fields == null) {
return;
}
for (Field f : fields) {
if (f.getType() == java.lang.String.class) {
try {
String value = (String) f.get(this);
f.set(this, methodToRemoveHtml(value));
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
Works fine. Since I caught myself putting this method in many classes I use, I thought I'd let all those classes inherit from a BaseClass and implement the method only there.
But when I do this, I get a: java.lang.IllegalAccessException: access to field not allowed on every try.
Why is this happening and
How can I fix this?
I guess the fields are private, so they can only be accessed from code inside the class that contains them, and not a superclass.
You have to make them accessible by calling setAccessible(true); on them or making them public or protected.
for (Field f : fields) {
if (f.getType() == java.lang.String.class) {
try {
f.setAccessible(true); // make field accessible.
String value = (String) f.get(this);
// ...
May be you need to call:
f.setAccessible(true);