Background
When you want to get a deep copy of an object, you can use ObjectOutputStream
/ObjectInputStream
and serialize/deserialize the target object *1 ((Note that SerializationUtils.clone()
in Spring Framework requires the class of the target object implements Serializable
. ObjectOutputStream#writeObject()
doesn't have such restriction)).
Problem
In this method, you will get NotSerializableException
if the object contains non-serializable fields like MultipartFile
of Spring Framework.
To avoid this exception, you have to add the transient
modifier to the non-serializable fields. So you have to have control of the class of the object to adopt this workaround. For the class that you don't have control of or that is in libraries, you can't take this approach.
Solution
You can use Jackson's ObjectMapper#writeValueAsString()
and ObjectMapper#readValue()
to clone an object. This method throws InvalidDefinitionException
if the object has non-serializable fields. You can use @JsonIgnoreType
and ObjectMapper#addMixIn()
to ignore non-serializable fields according to their type without changing the definition of the class.
For example, you can ignore the MultipartFile
fields (for single file upload) and MultipartFile[]
fields (for multiple file upload) like this:
private Object makeClone(Object obj) { ObjectMapper mapper = new ObjectMapper(); mapper.addMixIn(MultipartFile.class, JacksonMixInForIgnoreType.class); mapper.addMixIn(MultipartFile[].class, JacksonMixInForIgnoreType.class); try { return mapper.readValue(mapper.writeValueAsString(obj), obj.getClass()); } catch (JsonProcessingException e) { throw new RuntimeException(e); } } @JsonIgnoreType class JacksonMixInForIgnoreType {}
Restriction
- You can't ignore the field like
List<MultipartFile> fileArray;
with this strategy. It seems there is no way to ignore the collection of a specific class. - If the target object has two or more references to a single instance, they will be different objects on the clone.