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).
Related
We have a use case where there is a class that has more than 130 attributes. There is a method that populates all the attributes and it is just very long just because of large number of attributes. Just the setters would make the method very long.
Just to give context about the source for these attributes, these are populated by different datasources. Few of them are from different micro services and few of them are from a mysql tables.
Our current solution is to group them into different groups based on the source or some similar business trait and update them in different methods. This has made some of the setters in different methods and just makes it very hard to read.
I have read else where about the builder pattern. But most of these attributes need some transformation after fetching from source and assigning each of the attributes to a temp variables and using them in the builder doesn't help much.
"Is there a design pattern...?" Nope.
First and foremost, reconsider whether this object even needs that many fields. "Our current solution is to group them into different groups" this suggests it doesn't.
If it genuinely needs that many fields and if the fields are identically named on both the source and target objects, i.e. the main instance with 130 fields is basically a composite of all the others, then you could consider using reflection.
e.g. for the following value objects
class Main {
private String a;
private Number b;
private String c;
private String d;
}
class A {
private final String a;
A(String a) {
this.a = a;
}
}
class B {
private final Integer b;
B(Integer b) { this.b = b; }
}
class C {
private final String c;
C(String c) { this.c = c; }
}
A simple example would be
public static void main(String[] args) throws Exception {
Main main = new Main();
A a = new A("a1");
B b = new B(2);
C c = new C("c3");
// Get all values from all sources
Map<String, Object> fieldToValue = new HashMap<>();
Stream.of(a, b, c).forEach(obj -> {
Field[] fields = getFieldsForInstance(obj);
for (Field field : fields) {
try {
Object prevValue = fieldToValue.put(field.getName(), field.get(obj));
if (prevValue != null) {
throw new RuntimeException("Duplicate source field " + field.getName());
}
}
catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
});
// Set the values on main instance
Field[] mainFields = getFieldsForInstance(main);
for (Field field : mainFields) {
if (fieldToValue.containsKey(field.getName())) {
Object value = fieldToValue.get(field.getName());
if (value != null) {
if (field.getType().isAssignableFrom(value.getClass())) {
field.set(main, value);
}
else {
throw new RuntimeException("Incompatible types for field " + field.getName());
}
}
}
else {
System.out.println("warning: field " + field.getName() + " is unset on main");
}
}
}
private static Field[] getFieldsForInstance(Object obj) {
Field[] fields = obj.getClass().getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
}
return fields;
}
I'd also consider whether you could use code generation at compile time, e.g. JavaPoet.
Given a class Person:
String name;
String surname;
String id;
String address;
I have an object obj1 with the following values:
name="Name"
surname=null
id="ABC123"
address="Here"
Through an api call I get the following json:
{
"name":"John",
"surname":"Doe",
"id":"A1B2C3"
}
which gets mapped into an object obj2like this:
name="John"
surname="Doe"
id="A1B2C3"
address=null
I want to copy all non-null (or empty string) values of obj2 into obj1 so the final result is this:
name="John"
surname="Doe"
id="A1B2C3"
address="Here"
I have two problems.
The first one is that I don't want to have to manually type the get/set call for each attribute of the object.
The second problem, is that I want the method to work for any type of object with no or minimal changes.
At the very least, I need the first problem solved. The second one is optional, but would be great to learn a solution too.
You can use reflection to get all the instance fields and use Field#set to copy over non-null values.
try {
for (Field field : Person.class.getDeclaredFields()) {
if (!Modifier.isStatic(field.getModifiers())) {
field.setAccessible(true);
Object val = field.get(obj2);
if (val != null) {
field.set(obj1, val);
}
}
}
System.out.println(obj1);
} catch (IllegalAccessException e) {
// Handle exception
}
Demo
public static void main(String[] args) {
MyClass obj1 = new MyClass(1,"1");
MyClass obj2 = new MyClass(2,"2");
System.out.println(obj2);
copy(obj1, obj2);
System.out.println(obj2);
}
public static MyClass copy(MyClass obj1, MyClass obj2){
Arrays.stream(obj1.getClass().getDeclaredFields()).forEach(f -> {
try {
f.set(obj2, f.get(obj1));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
});
return obj2;
}
static class MyClass {
int myInt;
String myString;
String emptyString = null;
public MyClass(int myInt, String myString) {
this.myInt = myInt;
this.myString = myString;
}
#Override
public String toString() {
return "MyClass{" +
"myInt=" + myInt +
", myString='" + myString + '\'' +
", emptyString='" + emptyString + '\'' +
'}';
}
}
in case you have private fields you can use
f.setAccessible(true);
but I don't suggest that.
Reading your question, seems like, you have two classes, in two distinct projects, which, exchange information in json.
So, It is easy if you can use Jackson(default in spring)
You could annotate the target class with the annotation of jackson #JsonInclude(JsonInclude.Include.NON_NULL)
I'm trying to use generics to access the field of an object.
For example, if I have an object called myObject and I know that most of its fields are of the data type float. So when I call this function getFieldValuesFloat(myObject, new String[]{"id"});
Then I got this error:
java.lang.IllegalAccessException: class se.danielmartensson.tools.GetClassInformation cannot access a member of class se.danielmartensson.entities.LX_Current with modifiers "private"
Here is the code I have problems with:
public static <T> Float[] getFieldValuesFloat(T object, String[] avoidTheseFields) {
String[] fieldNames = getFieldNames(object, avoidTheseFields);
Float[] fieldValues = new Float[fieldNames.length];
int i = 0;
for(String fieldName : fieldNames) {
try {
Field field = object.getClass().getDeclaredField(fieldName);
fieldValues[i] = field.getFloat(object);
i++;
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return fieldValues;
}
And the error focusing on this code row:
fieldValues[i] = field.getFloat(object);
This is weird, because I'm using this method to get the field names. And that method works. It also using generics, but instead, I'm reading the field names only from an object.
public static <T> String[] getFieldNames(T object, String[] avoidTheseFields) {
Field[] fields = object.getClass().getDeclaredFields();
String[] fieldNames = new String[fields.length - avoidTheseFields.length];
List<String> avoidTheseNamesList = Arrays.asList(avoidTheseFields);
int i = 0;
for(Field field : fields) {
String fieldName = field.getName();
if(avoidTheseNamesList.contains(fieldName))
continue;
fieldNames[i] = fieldName;
i++;
}
return fieldNames;
}
Question:
How can I get all values from an arbitary class using generics?
The field is probably not accessible, you can check that via
field.isAccessible()
and change it via
field.setAccessible(true)
This exception notify you about you have some field that has a private access level and you can't change the value for that field. You should change access level by command:
field.setAccessible(true);
And then try to change its value.
I need to capture field name of getter method dynamically for dynamic validation and dynamic formatting.
What is the best and efficient way of doing this.
public class Emp{
private String firstName;
private String lastName;
private String address;
private int age;
// getter and setters
}
public class MyImplementationClass{
public execute(Emp emp){
String fName=emp.getFirstName();
// field name need to be taken here using 'emp.getFirstName()'
// need field name and value of return value of 'emp.getFirstName()' for dynamic validation and dynamic formatting.
// here need to call method validateAndFormat() with field name and value.
}
}
private String validateAndFormat(String fieldName,String value){
// read the dynamic validation settings from the xml and validate/reformat the value
// this method will validate the field according to xml and return reformatted value.
}
private int validateAndFormat(String fieldName,int value){
//...
}
dynamic validation settings
<message>
<element field="firstName" length="22" defaultVal=""></element>
<element field="lastName" length="20" defaultVal="ibft"></element>
<element field="address" length="NA" defaultVal=""></element>
<element field="age" length="NA" defaultVal=""></element>
</message>
use getMethods get all public methods of the emp
then choose getXXX method and invoke it
Emp emp = new Emp();
emp.setAddress("myAdress");
emp.setAge(20);
emp.setFirstName("myFirstName");
emp.setLastName("myLastName");
Class clz = emp.getClass();
Method[] methods = clz.getMethods();
for (Method method : methods) {
String methodName = method.getName();
if (!Objects.equals(methodName, "getClass")
&& methodName.startsWith("get")
&& methodName.length() > 3
&& method.getParameterTypes().length == 0) {
String field = methodName.substring(3, 4).toLowerCase() + methodName.substring(4);
Object value = method.invoke(emp);
System.out.println("field:" + field + ",value:" + value);
}
}
you can also use getDeclaredFields get all private fields
and find getXXX method by field
Field[] fields = clz.getDeclaredFields();
for (Field field : fields) {
String fieldName = field.getName();
String methodName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
try {
Method method = clz.getMethod(methodName);
Object value = method.invoke(emp);
System.out.println("field:" + fieldName + ",value:" + value);
} catch (NoSuchMethodException e) {
System.out.println("no such method:" + methodName);
}
}
You can use Java reflection. But getting the field name from getter might not be a good design as the getter may not be backed by a field. Consider the below getter.
public int getExp(){
return today-joiningDate();
}
This is not backed by a field.
Instead, if you want only the field name and value, you can achieve as below.
Class class1 = employee.getClass();
Field[] fields= class1.getDeclaredFields();
for(Field field:fields){
try {
field.setAccessible(true);
System.out.println(field.getName()+":"+field.get(bean));
} catch (IllegalArgumentException | IllegalAccessException e) {
e.printStackTrace();
}
}
Hope this helps.
annotation would be a choose.
public #interface MyField {
String fieldName() default "";
}
and use it on you method
#MyField("firstName")
getFirstName(){
...
}
then get fieldName by reflection. i think this way is more flexible than generate field name from method name.
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"