Why Spring BeanUtils Fails to Copy Static Inner Classes—and How to Fix It
This article explains why Spring's BeanUtils.copyProperties cannot copy static inner class fields or list generics without proper getters/setters, demonstrates the problem with a reproducible demo, and provides practical solutions for correctly copying such objects in Java backend projects.
Background
In a recent integration project we needed to send an HTTP request to a third‑party service. The partner's SDK provides a MixAddRequest class, but it contains a bug that prevents serialization, so we rewrote the request class ( AddRequest) with the same properties, including a static inner class and two List fields.
After assembling the request parameters we used Spring's BeanUtils.copyProperties to copy properties from AddRequest to MixAddRequest. The request failed because a required field inside the static inner class Ticket was missing.
Demo Code
@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());Findings
The first attempt produced null for all fields because the classes lacked getters and setters (no @Data annotation). Adding @Data allowed the simple String field to be copied, but the static inner class remained null. This confirmed that BeanUtils does not copy properties of different static inner class types.
Solution
Copy the inner class separately, e.g.:
CopyTest1 test1 = new CopyTest1();
// set fields as before
CopyTest2 test2 = new CopyTest2();
test2.innerClass = new CopyTest2.InnerClass();
BeanUtils.copyProperties(test1, test2);
BeanUtils.copyProperties(test1.innerClass, test2.innerClass);
System.out.println(test2.toString());If the bean contains many nested objects, implement a recursive copy method; for a single‑level case the manual second copy is sufficient.
Additional Notes on Generics
Java generics are erased at runtime, so the List fields are treated as raw Object collections. After copying, MixAddRequest.orders holds a list of Order objects from AddRequest, not the partner's internal class, but because the downstream service parses JSON, the type mismatch does not cause an error.
Summary
Spring BeanUtils.copyProperties requires matching getter and setter methods for each property.
Static inner classes with identical structure but belonging to different outer classes are considered different types and are not copied automatically.
Generics provide compile‑time safety only; they do not enforce runtime type constraints.
Be aware that the source‑target parameter order differs between Spring and Apache Commons BeanUtils, so import the correct class and call the method with the proper argument order.
Final Note
The relevant Spring source shows that copyProperties uses the target's write method (setter) obtained via PropertyDescriptor.getWriteMethod(); therefore, a missing setter will cause the copy to fail.
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.
Java Backend Technology
Focus on Java-related technologies: SSM, Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading. Occasionally cover DevOps tools like Jenkins, Nexus, Docker, and ELK. Also share technical insights from time to time, committed to Java full-stack development!
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.
