I have classes which aim to contain many attributes of different types. I would want to automatically deep clone all of them rather than writing an instruction for each of them:
class AttributesContainer implements Cloneable {
Type1 a1 = new Type1(...), a2 = new Type1(...);
Type2 b1 = new Type2(...);
...
public AttributesContainer clone() {
AttributesContainer ac = (AttributesContainer) super.clone();
// Regroup that like using a loop
ac.a1 = a1.clone();
ac.a2 = a2.clone();
ac.b1 = b1.clone();
...
return ac;
}
}
I have thought about adding the fields in a table each time but I could not change the reference of the fields:
class ContainerAbstract implements Cloneable {
public <T> T add(T t) {
// adds the reference into a list
return t;
}
public ContainerAbstract clone() {
ContainerAbstract ca = (ContainerAbstract) super.clone();
// copy the attributes
return ca;
}
}
class AttributesContainer extends ContainerAbstract implements Cloneable {
Type1 a1 = add(new Type1(...)), a2 = add(new Type1(...));
Type2 b1 = add(new Type2(...));
...
public AttributesContainer clone() {
AttributesContainer ac = (AttributesContainer) super.clone();
return ac;
}
}
I have also thought that I could return a wrapper in the add() method but it would introduce an extra method get() to call each time I want to access an attribute:
AttributesContainer ac = new AttributesContainer();
ac.get()...;
It there a way to change the fields to there source, like we could achieve that in C using a pointer?
NB: I already checked Copy fields between similar classes in java, How do you make a deep copy of an object in Java? and http://www.java2s.com/Tutorial/Java/0125__Reflection/Returnalistofallfieldswhateveraccessstatusandonwhateversuperclasstheyweredefinedthatcanbefoundonthisclass.htm.
EDIT: One of the reasons I don't use the serialization is that in fact, I have a final property for which I just want a fresh new instance.
I thought about making it transient and then giving it a new object but I can't, since it is final:
class A {
private Double d = new Double(2);
public final transient B b = new B();
public A copy() {
A a = (A) DeepCopy.copy(this);
a.b = new B(); // Error, b is final
return a;
}
}
Finally, the only answer I found without needing to change a final attribute is to change in the class DeepCopy in http://javatechniques.com/blog/faster-deep-copies-of-java-objects/ the ObjectOutputStream method to replace attributes of the class Type with new ones.
ObjectOutputStream out = new ObjectOutputStream(fbos) {
{
enableReplaceObject(true);
}
@Override
protected Object replaceObject(Object arg0) throws IOException {
// TODO Auto-generated method stub
if(arg0 instanceof Type) {
for(Constructor<?> constructor : arg0.getClass().getConstructors()) {
Class<?>[] parameterTypes = constructor.getParameterTypes();
if(parameterTypes.length == 0 /* Number of arguments in the constructor of new Type(...) */)
try {
return constructor.newInstance(/* Arguments to the constructor */);
} catch (InstantiationException | IllegalAccessException
| IllegalArgumentException
| InvocationTargetException e) {
e.printStackTrace();
}
}
try {
throw new Exception("The constructor needed to create a new Type was not found.");
} catch(Exception e) {
e.printStackTrace();
}
return null;
} else {
return super.replaceObject(arg0);
}
}
};
out.writeObject(orig);
out.flush();
out.close();