ProtocolLib/ProtocolLib/src/main/java/com/comphenix/protocol/reflect/ObjectCloner.java

88 lines
3.0 KiB
Java

/*
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.comphenix.protocol.reflect;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
* Can copy an object field by field.
*
* @author Kristian
*/
public class ObjectCloner {
// Cache structure modifiers
@SuppressWarnings("rawtypes")
private static ConcurrentMap<Class, StructureModifier<Object>> cache =
new ConcurrentHashMap<Class, StructureModifier<Object>>();
/**
* Copy every field in object A to object B.
* <p>
* The two objects must have the same number of fields of the same type.
* @param source - fields to copy.
* @param destination - fields to copy to.
* @param commonType - type containing each field to copy.
*/
public static void copyTo(Object source, Object destination, Class<?> commonType) {
if (source == null)
throw new IllegalArgumentException("Source cannot be NULL");
if (destination == null)
throw new IllegalArgumentException("Destination cannot be NULL");
StructureModifier<Object> modifier = cache.get(commonType);
// Create the structure modifier if we haven't already
if (modifier == null) {
StructureModifier<Object> value = new StructureModifier<Object>(commonType, null, false);
modifier = cache.putIfAbsent(commonType, value);
if (modifier == null)
modifier = value;
}
// Add target
StructureModifier<Object> modifierSource = modifier.withTarget(source);
StructureModifier<Object> modifierDest = modifier.withTarget(destination);
// Copy every field
try {
for (int i = 0; i < modifierSource.size(); i++) {
Object value = modifierSource.read(i);
modifierDest.write(i, value);
// System.out.println(String.format("Writing value %s to %s",
// value, modifier.getFields().get(i).getName()));
}
// Copy private fields underneath
Class<?> superclass = commonType.getSuperclass();
if (!superclass.equals(Object.class)) {
copyTo(source, destination, superclass);
}
} catch (FieldAccessException e) {
throw new RuntimeException("Unable to copy fields from " + commonType.getName(), e);
}
}
}