Why Spring BeanUtils Fails to Copy Static Inner Classes and Lists (and How to Fix It)
This article explains why Spring's BeanUtils.copyProperties cannot copy static inner class fields and List properties without proper getters/setters, demonstrates the issue with demo code, and provides practical solutions to ensure successful property copying.
Background
In a project we needed to call a third‑party API. The original SDK’s Request class had a bug that prevented serialization, so we rewrote the request class (AddRequest) with the same fields, including a static inner class and two List fields.
We used Spring’s BeanUtils.copyProperties to copy properties from AddRequest to the SDK’s MixAddRequest. The request failed because a required field inside the static inner class (Ticket) was missing.
Investigation showed that BeanUtils only copies properties that have both getter and setter methods. Moreover, when the source and target contain static inner classes with the same structure but different class definitions, BeanUtils treats them as different types and does not copy them.
private List<Order> orders;
private AddRequest.Ticket ticket;
private List<Payment> payments;To reproduce the issue we created two demo classes (CopyTest1 and CopyTest2) each with a static inner class and a List of that inner class, then called BeanUtils.copyProperties. Without Lombok’s @Data (or explicit getters/setters) the target fields were null. Even with getters/setters, the inner‑class property remained null.
@ToString
@Data
public class CopyTest1{
public String outerName;
public CopyTest1.InnerClass innerClass;
public List<CopyTest1.InnerClass> clazz;
@ToString
@Data
public static class InnerClass{
public String InnerName;
}
}
@ToString
@Data
public class CopyTest2{
public String outerName;
public CopyTest2.InnerClass innerClass;
public List<CopyTest2.InnerClass> clazz;
@ToString
@Data
public static class InnerClass{
public String InnerName;
}
}
CopyTest1 test1 = new CopyTest1();
test1.outerName = "hahaha";
CopyTest1.InnerClass innerClass = new CopyTest1.InnerClass();
innerClass.InnerName = "hohoho";
test1.innerClass = innerClass;
System.out.println(test1.toString());
CopyTest2 test2 = new CopyTest2();
BeanUtils.copyProperties(test1, test2);
System.out.println(test2.toString());The fix is to copy the inner‑class properties separately, e.g.:
CopyTest2 test2 = new CopyTest2();
test2.innerClass = new CopyTest2.InnerClass();
BeanUtils.copyProperties(test1, test2);
BeanUtils.copyProperties(test1.innerClass, test2.innerClass);Summary
BeanUtils.copyProperties requires getters and setters for each property.
Identical‑named static inner classes are considered different types, so they are not copied automatically.
Java generics are compile‑time only; at runtime a List is just a collection of Objects, so generic type differences do not prevent copying.
Be aware that Spring’s BeanUtils and Apache Commons BeanUtils have source and target parameters in opposite order.
Finally, the Spring source shows that copyProperties uses reflection to find write methods (setters) and read methods (getters), so missing setters cause failure.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
