diff --git a/modules/API/src/main/java/com/comphenix/protocol/utility/CachedPackage.java b/modules/API/src/main/java/com/comphenix/protocol/utility/CachedPackage.java index e9e2616b..ec6c1870 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/utility/CachedPackage.java +++ b/modules/API/src/main/java/com/comphenix/protocol/utility/CachedPackage.java @@ -1,20 +1,19 @@ -/* +/** * 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 + * 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. + * 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 + * 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.utility; import java.util.Map; @@ -33,7 +32,7 @@ class CachedPackage { private final Map>> cache; private final String packageName; private final ClassSource source; - + /** * Construct a new cached package. * @param packageName - the name of the current package. @@ -44,16 +43,20 @@ class CachedPackage { this.cache = Maps.newConcurrentMap(); this.source = source; } - + /** * Associate a given class with a class name. * @param className - class name. * @param clazz - type of class. */ public void setPackageClass(String className, Class clazz) { - cache.put(className, Optional.>fromNullable(clazz)); + if (clazz != null) { + cache.put(className, Optional.> of(clazz)); + } else { + cache.remove(className); + } } - + /** * Retrieve the class object of a specific class in the current package. * @param className - the specific class. @@ -61,28 +64,30 @@ class CachedPackage { * @throws RuntimeException If we are unable to find the given class. */ public Class getPackageClass(String className) { - try { - Optional> result = cache.get(Preconditions.checkNotNull(className, "className cannot be NULL")); + Preconditions.checkNotNull(className, "className cannot be null!"); - // Concurrency is not a problem - we don't care if we look up a class twice - if (result == null) { - // Look up the class dynamically - result = Optional.>fromNullable(source.loadClass(combine(packageName, className))); - if (!result.isPresent()) - throw new IllegalArgumentException("Source " + source + " returned NULL for " + className); - - cache.put(className, result); - } - - // Class has been looked for and hasn't been found in the past + // See if we've already looked it up + if (cache.containsKey(className)) { + Optional> result = cache.get(className); if (!result.isPresent()) { - throw new ClassNotFoundException(); + throw new RuntimeException("Cannot find class " + className); } return result.get(); - } catch (ClassNotFoundException e) { - setPackageClass(className, null); - throw new RuntimeException("Cannot find class " + combine(packageName, className), e); + } + + try { + // Try looking it up + Class clazz = source.loadClass(combine(packageName, className)); + if (clazz == null) { + throw new IllegalArgumentException("Source " + source + " returned null for " + className); + } + + cache.put(className, Optional.> of(clazz)); + return clazz; + } catch (ClassNotFoundException ex) { + cache.put(className, Optional.> absent()); + throw new RuntimeException("Cannot find class " + className, ex); } } diff --git a/modules/API/src/main/java/com/comphenix/protocol/utility/MinecraftReflection.java b/modules/API/src/main/java/com/comphenix/protocol/utility/MinecraftReflection.java index 5e2018a2..6ea2a5b6 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/utility/MinecraftReflection.java +++ b/modules/API/src/main/java/com/comphenix/protocol/utility/MinecraftReflection.java @@ -63,8 +63,8 @@ import com.comphenix.protocol.reflect.fuzzy.FuzzyClassContract; import com.comphenix.protocol.reflect.fuzzy.FuzzyFieldContract; import com.comphenix.protocol.reflect.fuzzy.FuzzyMatchers; import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract; -import com.comphenix.protocol.utility.RemappedClassSource.RemapperUnavaibleException; -import com.comphenix.protocol.utility.RemappedClassSource.RemapperUnavaibleException.Reason; +import com.comphenix.protocol.utility.RemappedClassSource.RemapperUnavailableException; +import com.comphenix.protocol.utility.RemappedClassSource.RemapperUnavailableException.Reason; import com.comphenix.protocol.wrappers.nbt.NbtFactory; import com.comphenix.protocol.wrappers.nbt.NbtType; import com.google.common.base.Joiner; @@ -934,6 +934,9 @@ public class MinecraftReflection { return getMinecraftClass("MinecraftServer"); } catch (RuntimeException e) { useFallbackServer(); + + // Reset cache and try again + setMinecraftClass("MinecraftServer", null); return getMinecraftClass("MinecraftServer"); } } @@ -982,8 +985,10 @@ public class MinecraftReflection { try { return getMinecraftClass("ServerConfigurationManager", "PlayerList"); } catch (RuntimeException e) { - // Try again useFallbackServer(); + + // Reset cache and try again + setMinecraftClass("ServerConfigurationManager", null); return getMinecraftClass("ServerConfigurationManager"); } } @@ -1628,8 +1633,10 @@ public class MinecraftReflection { try { return getMinecraftClass("AttributeModifier"); } catch (RuntimeException e) { - // Initialize first getAttributeSnapshotClass(); + + // Reset cache and try again + setMinecraftClass("AttributeModifier", null); return getMinecraftClass("AttributeModifier"); } } @@ -2108,7 +2115,7 @@ public class MinecraftReflection { // Attempt to use MCPC try { return classSource = new RemappedClassSource().initialize(); - } catch (RemapperUnavaibleException e) { + } catch (RemapperUnavailableException e) { if (e.getReason() != Reason.MCPC_NOT_PRESENT) reporter.reportWarning(MinecraftReflection.class, Report.newBuilder(REPORT_CANNOT_FIND_MCPC_REMAPPER)); } catch (Exception e) { diff --git a/modules/API/src/main/java/com/comphenix/protocol/utility/RemappedClassSource.java b/modules/API/src/main/java/com/comphenix/protocol/utility/RemappedClassSource.java index 1b5e92a9..7a2fb91e 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/utility/RemappedClassSource.java +++ b/modules/API/src/main/java/com/comphenix/protocol/utility/RemappedClassSource.java @@ -28,7 +28,7 @@ import org.bukkit.Server; import com.comphenix.protocol.reflect.FieldUtils; import com.comphenix.protocol.reflect.MethodUtils; -import com.comphenix.protocol.utility.RemappedClassSource.RemapperUnavaibleException.Reason; +import com.comphenix.protocol.utility.RemappedClassSource.RemapperUnavailableException.Reason; class RemappedClassSource extends ClassSource { private Object classRemapper; @@ -53,7 +53,7 @@ class RemappedClassSource extends ClassSource { /** * Attempt to load the MCPC remapper. * @return TRUE if we succeeded, FALSE otherwise. - * @throws RemapperUnavaibleException If the remapper is not present. + * @throws RemapperUnavailableException If the remapper is not present. */ public RemappedClassSource initialize() { try { @@ -64,14 +64,14 @@ class RemappedClassSource extends ClassSource { String version = server.getVersion(); if (!version.contains("MCPC") && !version.contains("Cauldron")) { - throw new RemapperUnavaibleException(Reason.MCPC_NOT_PRESENT); + throw new RemapperUnavailableException(Reason.MCPC_NOT_PRESENT); } // Obtain the Class remapper used by MCPC+/Cauldron this.classRemapper = FieldUtils.readField(getClass().getClassLoader(), "remapper", true); if (this.classRemapper == null) { - throw new RemapperUnavaibleException(Reason.REMAPPER_DISABLED); + throw new RemapperUnavailableException(Reason.REMAPPER_DISABLED); } // Initialize some fields and methods used by the Jar Remapper @@ -82,7 +82,7 @@ class RemappedClassSource extends ClassSource { return this; - } catch (RemapperUnavaibleException e) { + } catch (RemapperUnavailableException e) { throw e; } catch (Exception e) { // Damn it @@ -115,7 +115,7 @@ class RemappedClassSource extends ClassSource { } } - public static class RemapperUnavaibleException extends RuntimeException { + public static class RemapperUnavailableException extends RuntimeException { private static final long serialVersionUID = 1L; public enum Reason { @@ -139,7 +139,7 @@ class RemappedClassSource extends ClassSource { private final Reason reason; - public RemapperUnavaibleException(Reason reason) { + public RemapperUnavailableException(Reason reason) { super(reason.getMessage()); this.reason = reason; }