ProtocolLib/src/main/java/com/comphenix/protocol/utility/ObjectReconstructor.java

76 lines
2.7 KiB
Java

package com.comphenix.protocol.utility;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
/**
* This class can be used to reconstruct objects.
*
* Note that it is limited to classes where both the order and number of member variables matches the order and number
* of arguments for the first constructor. This means that this class is mostly useful for classes generated by lambdas.
*
* @param <T> The type of the object to reconstruct.
* @author Pim
*/
public class ObjectReconstructor<T> {
private final Class<T> clz;
private final Field[] fields;
private final Constructor<?> ctor;
public ObjectReconstructor(final Class<T> clz) {
this.clz = clz;
this.fields = clz.getDeclaredFields();
for (Field field : fields)
field.setAccessible(true);
this.ctor = clz.getDeclaredConstructors()[0];
this.ctor.setAccessible(true);
}
/**
* Gets the values of all member variables of the provided instance.
* @param instance The instance for which to get all the member variables.
* @return The values of the member variables from the instance.
*/
public Object[] getValues(final Object instance) {
final Object[] values = new Object[fields.length];
for (int idx = 0; idx < fields.length; ++idx)
try {
values[idx] = fields[idx].get(instance);
} catch (IllegalAccessException e) {
throw new RuntimeException("Failed to access field: " + fields[idx].getName() +
" for class: " + clz.getName(), e);
}
return values;
}
/**
* Gets the fields in the class.
* @return The fields.
*/
public Field[] getFields() {
return fields;
}
/**
* Creates a new instance of the class using the new values.
* @param values The new values for the member variables of the class.
* @return The new instance.
*/
public T reconstruct(final Object[] values) {
if (values.length != fields.length)
throw new RuntimeException("Mismatched number of arguments for class: " + clz.getName());
try {
return (T) ctor.newInstance(values);
} catch (InstantiationException e) {
throw new RuntimeException("Failed to reconstruct object of type: " + clz.getName(), e);
} catch (IllegalAccessException e) {
throw new RuntimeException("Failed to access constructor of type: " + clz.getName(), e);
} catch (InvocationTargetException e) {
throw new RuntimeException("Failed to invoke constructor of type: " + clz.getName(), e);
}
}
}