I have a class which is basically a copy of another class.
public class A {
int a;
String b;
}
public class CopyA {
int a;
String b;
}
What I am doing is putting values from class A
into CopyA
before sending CopyA
through a webservice call. Now I would like to create a reflection-method that basically copies all fields that are identical (by name and type) from class A
to class CopyA
.
How can I do this?
This is what I have so far, but it doesn't quite work. I think the problem here is that I am trying to set a field on the field I am looping through.
private <T extends Object, Y extends Object> void copyFields(T from, Y too) {
Class<? extends Object> fromClass = from.getClass();
Field[] fromFields = fromClass.getDeclaredFields();
Class<? extends Object> tooClass = too.getClass();
Field[] tooFields = tooClass.getDeclaredFields();
if (fromFields != null && tooFields != null) {
for (Field tooF : tooFields) {
logger.debug("toofield name #0 and type #1", tooF.getName(), tooF.getType().toString());
try {
// Check if that fields exists in the other method
Field fromF = fromClass.getDeclaredField(tooF.getName());
if (fromF.getType().equals(tooF.getType())) {
tooF.set(tooF, fromF);
}
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchFieldException 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();
}
}
}
I am sure there must be someone that has already done this somehow
The first argument to
tooF.set()
should be the target object (too
), not the field, and the second argument should be the value, not the field the value comes from. (To get the value, you need to callfromF.get()
-- again passing in a target object, in this casefrom
.)Most of the reflection API works this way. You get
Field
objects,Method
objects, and so on from the class, not from an instance, so to use them (except for statics) you generally need to pass them an instance.I didn't want to add dependency to another JAR file because of this, so wrote something which would suit my needs. I follow the convention of fjorm https://code.google.com/p/fjorm/ which means that my generally accessible fields are public and that I don't bother to write setters and getters. (in my opinion code is easier to manage and more readable actually)
So I wrote something (it's not actually much difficult) which suits my needs (assumes that the class has public constructor without args) and it could be extracted into utility class
Dozer
UPDATE Nov 19 2012: There's now a new ModelMapper project too.
Spring has a built in
BeanUtils.copyProperties
method. But it doesn't work with classes without getters/setters. JSON serialization/deserialization can be another option for copying fields. Jackson can be used for this purpose. If you are using Spring In most cases Jackson is already in your dependency list.My solution:
Here is a working and tested solution. You can control the depth of the mapping in the class hierarchy.