From c1ed088897da806cd9700d01b961e65fe00ea8be Mon Sep 17 00:00:00 2001 From: Ben Manes Date: Mon, 7 Dec 2020 20:38:00 -0800 Subject: [PATCH] Fix NPE when on the bootclasspath (fixes #481) To reduce runtime overhead due to fields needed only by certain configurations, code generation is used and reflection loads the optimal implementation classes. This trades off a small amount of disk space for reduced memory usage. Unfortunately the wrong classloader method was used, which is not available on the bootclasspath (null value). This fails when the cache is used by a compiler, e.g. ErrorProne's javac fork. Instead Class.forName is now used which should resolve to a non-null, acceptable class loader. It appears as if this should be the same loader as before, or else the system loader if on the bootclasspath. --- .../caffeine/cache/LocalCacheSelectorCode.java | 3 +-- .../caffeine/cache/NodeSelectorCode.java | 3 +-- .../jcache/spi/CaffeineCachingProvider.java | 16 +++++++++++----- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/caffeine/src/javaPoet/java/com/github/benmanes/caffeine/cache/LocalCacheSelectorCode.java b/caffeine/src/javaPoet/java/com/github/benmanes/caffeine/cache/LocalCacheSelectorCode.java index a368046d31..43fd50e64c 100644 --- a/caffeine/src/javaPoet/java/com/github/benmanes/caffeine/cache/LocalCacheSelectorCode.java +++ b/caffeine/src/javaPoet/java/com/github/benmanes/caffeine/cache/LocalCacheSelectorCode.java @@ -99,8 +99,7 @@ private LocalCacheSelectorCode expires() { private LocalCacheSelectorCode selector() { block .beginControlFlow("try") - .addStatement("$T clazz = $T.class.getClassLoader().loadClass(sb.toString())", - Class.class, LOCAL_CACHE_FACTORY) + .addStatement("Class clazz = Class.forName(sb.toString())") .addStatement("$T ctor = clazz.getDeclaredConstructor($T.class, $T.class, $T.class)", Constructor.class, BUILDER, CACHE_LOADER.rawType, TypeName.BOOLEAN) .add("@SuppressWarnings($S)\n", "unchecked") diff --git a/caffeine/src/javaPoet/java/com/github/benmanes/caffeine/cache/NodeSelectorCode.java b/caffeine/src/javaPoet/java/com/github/benmanes/caffeine/cache/NodeSelectorCode.java index e2bdb49d49..868121531e 100644 --- a/caffeine/src/javaPoet/java/com/github/benmanes/caffeine/cache/NodeSelectorCode.java +++ b/caffeine/src/javaPoet/java/com/github/benmanes/caffeine/cache/NodeSelectorCode.java @@ -94,8 +94,7 @@ private NodeSelectorCode maximum() { private NodeSelectorCode selector() { block .beginControlFlow("try") - .addStatement("$T clazz = $T.class.getClassLoader().loadClass(sb.toString())", - Class.class, NODE_FACTORY.rawType) + .addStatement("Class clazz = Class.forName(sb.toString())") .add("@SuppressWarnings($S)\n", "unchecked") .addStatement("$1T factory = ($1T) clazz.getDeclaredConstructor().newInstance()", NODE_FACTORY) diff --git a/jcache/src/main/java/com/github/benmanes/caffeine/jcache/spi/CaffeineCachingProvider.java b/jcache/src/main/java/com/github/benmanes/caffeine/jcache/spi/CaffeineCachingProvider.java index b8c1b34e77..6c8c507b75 100644 --- a/jcache/src/main/java/com/github/benmanes/caffeine/jcache/spi/CaffeineCachingProvider.java +++ b/jcache/src/main/java/com/github/benmanes/caffeine/jcache/spi/CaffeineCachingProvider.java @@ -180,7 +180,7 @@ public JCacheClassLoader() { public Class loadClass(String name) throws ClassNotFoundException { ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); ClassNotFoundException error = null; - if (contextClassLoader != null && contextClassLoader != DEFAULT_CLASS_LOADER) { + if ((contextClassLoader != null) && (contextClassLoader != DEFAULT_CLASS_LOADER)) { try { return contextClassLoader.loadClass(name); } catch (ClassNotFoundException e) { @@ -198,7 +198,9 @@ public Class loadClass(String name) throws ClassNotFoundException { } ClassLoader parentClassLoader = getParent(); - if (parentClassLoader != null && parentClassLoader != contextClassLoader && parentClassLoader != classClassLoader) { + if ((parentClassLoader != null) + && (parentClassLoader != classClassLoader) + && (parentClassLoader != contextClassLoader)) { return parentClassLoader.loadClass(name); } throw (error == null) ? new ClassNotFoundException(name) : error; @@ -207,7 +209,7 @@ public Class loadClass(String name) throws ClassNotFoundException { @Override public @Nullable URL getResource(String name) { ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); - if (contextClassLoader != null && contextClassLoader != DEFAULT_CLASS_LOADER) { + if ((contextClassLoader != null) && (contextClassLoader != DEFAULT_CLASS_LOADER)) { URL resource = contextClassLoader.getResource(name); if (resource != null) { return resource; @@ -223,7 +225,9 @@ public Class loadClass(String name) throws ClassNotFoundException { } ClassLoader parentClassLoader = getParent(); - if (parentClassLoader != null && parentClassLoader != contextClassLoader && parentClassLoader != classClassLoader) { + if ((parentClassLoader != null) + && (parentClassLoader != classClassLoader) + && (parentClassLoader != contextClassLoader)) { return parentClassLoader.getResource(name); } @@ -245,7 +249,9 @@ public Enumeration getResources(String name) throws IOException { } ClassLoader parentClassLoader = getParent(); - if (parentClassLoader != null && parentClassLoader != contextClassLoader && parentClassLoader != classClassLoader) { + if ((parentClassLoader != null) + && (parentClassLoader != classClassLoader) + && (parentClassLoader != contextClassLoader)) { resources.addAll(Collections.list(parentClassLoader.getResources(name))); }