diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/reflect/cloning/CollectionCloner.java b/ProtocolLib/src/main/java/com/comphenix/protocol/reflect/cloning/CollectionCloner.java index dbb56115..ef23cb51 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/reflect/cloning/CollectionCloner.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/reflect/cloning/CollectionCloner.java @@ -17,6 +17,7 @@ package com.comphenix.protocol.reflect.cloning; +import java.io.Serializable; import java.lang.reflect.Array; import java.lang.reflect.Constructor; import java.util.Collection; @@ -55,32 +56,37 @@ public class CollectionCloner implements Cloner { throw new IllegalArgumentException("source cannot be NULL."); Class clazz = source.getClass(); - + if (source instanceof Collection) { Collection copy = cloneConstructor(Collection.class, clazz, source); - + // Next, clone each element in the collection - copy.clear(); - - for (Object element : (Collection) source) { - copy.add(getClone(element, source)); + try { + copy.clear(); + + for (Object element : (Collection) source) { + copy.add(getClone(element, source)); + } + } catch (UnsupportedOperationException e) { + // Immutable - we can't do much about that } - return copy; } else if (source instanceof Map) { - Map copy = cloneConstructor(Map.class, clazz, source); // Next, clone each element in the collection - copy.clear(); - - for (Entry element : ((Map) source).entrySet()) { - Object key = getClone(element.getKey(), source); - Object value = getClone(element.getValue(), source); - copy.put(key, value); + try { + copy.clear(); + + for (Entry element : ((Map) source).entrySet()) { + Object key = getClone(element.getKey(), source); + Object value = getClone(element.getValue(), source); + copy.put(key, value); + } + } catch (UnsupportedOperationException e) { + // Immutable - we can't do much about that } - return copy; } else if (clazz.isArray()) { @@ -163,12 +169,14 @@ public class CollectionCloner implements Cloner { */ @SuppressWarnings("unchecked") private 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) { + if (source instanceof Serializable) + return (T) new SerializableCloner().clone(source); + // Delegate to serializable if possible return (T) cloneObject(clazz, source); } catch (Exception e) { throw new RuntimeException("Cannot construct collection.", e); diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/reflect/cloning/SerializableCloner.java b/ProtocolLib/src/main/java/com/comphenix/protocol/reflect/cloning/SerializableCloner.java index 8358a9a0..5df7db09 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/reflect/cloning/SerializableCloner.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/reflect/cloning/SerializableCloner.java @@ -21,7 +21,7 @@ public class SerializableCloner implements Cloner { @Override public Object clone(Object source) { - return clone(source); + return SerializableCloner.clone((Serializable)source); } /** diff --git a/ProtocolLib/src/test/java/com/comphenix/protocol/reflect/cloning/AggregateClonerTest.java b/ProtocolLib/src/test/java/com/comphenix/protocol/reflect/cloning/AggregateClonerTest.java new file mode 100644 index 00000000..737e889a --- /dev/null +++ b/ProtocolLib/src/test/java/com/comphenix/protocol/reflect/cloning/AggregateClonerTest.java @@ -0,0 +1,24 @@ +package com.comphenix.protocol.reflect.cloning; + +import static org.junit.Assert.*; + +import java.util.Arrays; +import java.util.List; + +import org.junit.BeforeClass; +import org.junit.Test; + +import com.comphenix.protocol.BukkitInitialization; + +public class AggregateClonerTest { + @BeforeClass + public static void initializeBukkit() throws IllegalAccessException { + BukkitInitialization.initializePackage(); + } + + @Test + public void testArrays() { + List input = Arrays.asList(1, 2, 3); + assertEquals(input, AggregateCloner.DEFAULT.clone(input)); + } +}