In general the convert method is not likely to work (for Lists or any other type).
Calling Field.setAccessible(true) allows read and write access to private fields but will not allow modification of final fields via Field.set() (an IllegalAccessException: Field is final exception is thrown).
Depending on the implementation of List you are trying to copy this may prevent it from working correctly. For example, using ArrayList such as:
// Note that this is an unchecked cast
List<ClassB> listB = (List<ClassB>) convert(listA, ArrayList.class);
fails when trying to copy serialVersionUID.
The following change to the posted code gets round this problem for static final serialVersionUID in ArrayList:
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);
// Ignore attempts to set final fields
try {
targetField.set(target, field.get(instance));
} catch (IllegalAccessException e) {
continue;
}
}
return target;
}
However, the next problem is that the convert method is performing a shallow copy. For Lists of different types this altered version of convert may appear to work correctly but it does not convert the ClassA objects in the list to ClassB (the unchecked cast above hides this). This will likely cause ClassCastExceptions to be thrown later in the application.
Fixing this problem can be achieved by adding another method to wrap convert:
public static <A, B extends List<C>, C> B convertList(
List<A> list, Class<B> targetListClass, Class<C> targetClass)
throws Exception {
B targetList = targetListClass.newInstance();
for (A object : list) {
targetList.add(convert(object, targetClass));
}
return targetList;
}
This will then need to be called as:
List<ClassB> listB = (List<ClassB>) convertList(
listA, ArrayList.class, ClassB.class);