Added the same NULL check to the generic Bukkit unwrapper.

This commit is contained in:
Kristian S. Stangeland 2012-10-12 00:01:05 +02:00
parent 57add8e26f
commit 768d169f27

View File

@ -1,113 +1,115 @@
/* /*
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland * Copyright (C) 2012 Kristian S. Stangeland
* *
* This program is free software; you can redistribute it and/or modify it under the terms of the * 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 * GNU General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version. * 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; * 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. * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. * 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; * 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 * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA * 02111-1307 USA
*/ */
package com.comphenix.protocol.injector; package com.comphenix.protocol.injector;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Collection; import java.util.Collection;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import com.comphenix.protocol.injector.PacketConstructor.Unwrapper; import com.comphenix.protocol.injector.PacketConstructor.Unwrapper;
import com.comphenix.protocol.reflect.instances.DefaultInstances; import com.comphenix.protocol.reflect.instances.DefaultInstances;
/** /**
* Represents an object capable of converting wrapped Bukkit objects into NMS objects. * Represents an object capable of converting wrapped Bukkit objects into NMS objects.
* <p> * <p>
* Typical conversions include: * Typical conversions include:
* <ul> * <ul>
* <li>org.bukkit.entity.Player -> net.minecraft.server.EntityPlayer</li> * <li>org.bukkit.entity.Player -> net.minecraft.server.EntityPlayer</li>
* <li>org.bukkit.World -> net.minecraft.server.WorldServer</li> * <li>org.bukkit.World -> net.minecraft.server.WorldServer</li>
* </ul> * </ul>
* *
* @author Kristian * @author Kristian
*/ */
public class BukkitUnwrapper implements Unwrapper { public class BukkitUnwrapper implements Unwrapper {
private static Map<Class<?>, Method> cache = new ConcurrentHashMap<Class<?>, Method>(); private static Map<Class<?>, Method> cache = new ConcurrentHashMap<Class<?>, Method>();
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
public Object unwrapItem(Object wrappedObject) { public Object unwrapItem(Object wrappedObject) {
// Special case // Special cases
if (wrappedObject instanceof Collection) { if (wrappedObject == null) {
return handleCollection((Collection<Object>) wrappedObject); return null;
} } else if (wrappedObject instanceof Collection) {
return handleCollection((Collection<Object>) wrappedObject);
Class<?> currentClass = wrappedObject.getClass(); }
Method cachedMethod = initializeCache(currentClass);
Class<?> currentClass = wrappedObject.getClass();
try { Method cachedMethod = initializeCache(currentClass);
// Retrieve the handle
if (cachedMethod != null) try {
return cachedMethod.invoke(wrappedObject); // Retrieve the handle
else if (cachedMethod != null)
return null; return cachedMethod.invoke(wrappedObject);
else
} catch (IllegalArgumentException e) { return null;
// Impossible
return null; } catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) { // Impossible
return null; return null;
} catch (InvocationTargetException e) { } catch (IllegalAccessException e) {
// This is REALLY bad return null;
throw new RuntimeException("Minecraft error.", e); } catch (InvocationTargetException e) {
} // This is REALLY bad
} throw new RuntimeException("Minecraft error.", e);
}
private Object handleCollection(Collection<Object> wrappedObject) { }
@SuppressWarnings("unchecked") private Object handleCollection(Collection<Object> wrappedObject) {
Collection<Object> copy = DefaultInstances.DEFAULT.getDefault(wrappedObject.getClass());
@SuppressWarnings("unchecked")
if (copy != null) { Collection<Object> copy = DefaultInstances.DEFAULT.getDefault(wrappedObject.getClass());
// Unwrap every element
for (Object element : wrappedObject) { if (copy != null) {
copy.add(unwrapItem(element)); // Unwrap every element
} for (Object element : wrappedObject) {
return copy; copy.add(unwrapItem(element));
}
} else { return copy;
// Impossible
return null; } else {
} // Impossible
} return null;
}
private Method initializeCache(Class<?> type) { }
// See if we're already determined this private Method initializeCache(Class<?> type) {
if (cache.containsKey(type)) {
// We will never remove from the cache, so this ought to be thread safe // See if we're already determined this
return cache.get(type); if (cache.containsKey(type)) {
} // We will never remove from the cache, so this ought to be thread safe
return cache.get(type);
try { }
Method find = type.getMethod("getHandle");
try {
// It's thread safe, as getMethod should return the same handle Method find = type.getMethod("getHandle");
cache.put(type, find);
return find; // It's thread safe, as getMethod should return the same handle
cache.put(type, find);
} catch (SecurityException e) { return find;
return null;
} catch (NoSuchMethodException e) { } catch (SecurityException e) {
return null; return null;
} } catch (NoSuchMethodException e) {
} return null;
} }
}
}