Add support for cloning maps.
Dieser Commit ist enthalten in:
Ursprung
f0e7b9aec7
Commit
d16e0bf1c6
@ -15,9 +15,15 @@
|
|||||||
<arguments>
|
<arguments>
|
||||||
</arguments>
|
</arguments>
|
||||||
</buildCommand>
|
</buildCommand>
|
||||||
|
<buildCommand>
|
||||||
|
<name>net.sourceforge.metrics.builder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
</buildSpec>
|
</buildSpec>
|
||||||
<natures>
|
<natures>
|
||||||
<nature>org.eclipse.m2e.core.maven2Nature</nature>
|
<nature>org.eclipse.m2e.core.maven2Nature</nature>
|
||||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||||
|
<nature>net.sourceforge.metrics.nature</nature>
|
||||||
</natures>
|
</natures>
|
||||||
</projectDescription>
|
</projectDescription>
|
||||||
|
@ -20,6 +20,8 @@ package com.comphenix.protocol.reflect.cloning;
|
|||||||
import java.lang.reflect.Array;
|
import java.lang.reflect.Array;
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to clone collection and array classes.
|
* Attempts to clone collection and array classes.
|
||||||
@ -43,7 +45,7 @@ public class CollectionCloner implements Cloner {
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
Class<?> clazz = source.getClass();
|
Class<?> clazz = source.getClass();
|
||||||
return Collection.class.isAssignableFrom(clazz) || clazz.isArray();
|
return Collection.class.isAssignableFrom(clazz) || Map.class.isAssignableFrom(clazz) || clazz.isArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@ -55,31 +57,32 @@ public class CollectionCloner implements Cloner {
|
|||||||
Class<?> clazz = source.getClass();
|
Class<?> clazz = source.getClass();
|
||||||
|
|
||||||
if (source instanceof Collection) {
|
if (source instanceof Collection) {
|
||||||
Collection<Object> copy = null;
|
Collection<Object> copy = cloneConstructor(Collection.class, clazz, source);
|
||||||
|
|
||||||
// Not all collections implement "clone", but most *do* implement the "copy constructor" pattern
|
|
||||||
try {
|
|
||||||
Constructor<?> constructCopy = clazz.getConstructor(Collection.class);
|
|
||||||
copy = (Collection<Object>) constructCopy.newInstance(source);
|
|
||||||
} catch (NoSuchMethodException e) {
|
|
||||||
copy = (Collection<Object>) cloneObject(clazz, source);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException("Cannot construct collection.", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Next, clone each element in the collection
|
// Next, clone each element in the collection
|
||||||
copy.clear();
|
copy.clear();
|
||||||
|
|
||||||
for (Object element : (Collection<Object>) source) {
|
for (Object element : (Collection<Object>) source) {
|
||||||
if (defaultCloner.canClone(element))
|
copy.add(getClone(element, source));
|
||||||
copy.add(defaultCloner.clone(element));
|
}
|
||||||
else
|
|
||||||
throw new IllegalArgumentException("Cannot clone " + element + " in collection " + source);
|
return copy;
|
||||||
|
|
||||||
|
} else if (source instanceof Map) {
|
||||||
|
|
||||||
|
Map<Object, Object> copy = cloneConstructor(Map.class, clazz, source);
|
||||||
|
|
||||||
|
// Next, clone each element in the collection
|
||||||
|
copy.clear();
|
||||||
|
|
||||||
|
for (Entry<Object, Object> element : ((Map<Object, Object>) source).entrySet()) {
|
||||||
|
Object key = getClone(element.getKey(), source);
|
||||||
|
Object value = getClone(element.getValue(), source);
|
||||||
|
copy.put(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return copy;
|
return copy;
|
||||||
|
|
||||||
// Second possibility
|
|
||||||
} else if (clazz.isArray()) {
|
} else if (clazz.isArray()) {
|
||||||
// Get the length
|
// Get the length
|
||||||
int lenght = Array.getLength(source);
|
int lenght = Array.getLength(source);
|
||||||
@ -110,6 +113,19 @@ public class CollectionCloner implements Cloner {
|
|||||||
throw new IllegalArgumentException(source + " is not an array nor a Collection.");
|
throw new IllegalArgumentException(source + " is not an array nor a Collection.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clone an element using the default cloner.
|
||||||
|
* @param element - the element to clone.
|
||||||
|
* @param container - where the element is stored.
|
||||||
|
* @return The cloned element.
|
||||||
|
*/
|
||||||
|
private Object getClone(Object element, Object container) {
|
||||||
|
if (defaultCloner.canClone(element))
|
||||||
|
return defaultCloner.clone(element);
|
||||||
|
else
|
||||||
|
throw new IllegalArgumentException("Cannot clone " + element + " in container " + container);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clone a primitive or immutable array by calling its clone method.
|
* Clone a primitive or immutable array by calling its clone method.
|
||||||
* @param component - the component type of the array.
|
* @param component - the component type of the array.
|
||||||
@ -138,6 +154,27 @@ public class CollectionCloner implements Cloner {
|
|||||||
return ((Object[]) source).clone();
|
return ((Object[]) source).clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clone an object by calling its clone constructor, or alternatively, a "clone" method.
|
||||||
|
* @param superclass - the superclass we expect in the clone constructor.
|
||||||
|
* @param clazz - the class of the object.
|
||||||
|
* @param source - the object itself.
|
||||||
|
* @return A cloned object.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private <T> T cloneConstructor(Class<?> superclass, Class<?> clazz, Object source) {
|
||||||
|
|
||||||
|
// Not all collections or maps implement "clone", but most *do* implement the "copy constructor" pattern
|
||||||
|
try {
|
||||||
|
Constructor<?> constructCopy = clazz.getConstructor(Collection.class);
|
||||||
|
return (T) constructCopy.newInstance(source);
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
return (T) cloneObject(clazz, source);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Cannot construct collection.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clone an object by calling "clone" using reflection.
|
* Clone an object by calling "clone" using reflection.
|
||||||
* @param clazz - the class type.
|
* @param clazz - the class type.
|
||||||
|
In neuem Issue referenzieren
Einen Benutzer sperren